diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..b9d54cd
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1 @@
+scripts/qrcode.js
diff --git a/blocks/live-voting/live-voting.css b/blocks/live-voting/live-voting.css
new file mode 100644
index 0000000..7cea507
--- /dev/null
+++ b/blocks/live-voting/live-voting.css
@@ -0,0 +1,34 @@
+div.container-flexbox {
+ display: grid;
+ grid-auto-rows: 1fr;
+ grid-template-columns: 1fr 1fr 1fr;
+}
+
+div.container-flexbox > * {
+ padding: 1rem;
+ background-color: #999;
+ align-items: center;
+}
+
+div.container-flexbox > *:nth-child(1) {
+ background-color: red;
+ color: white;
+}
+
+div.container-flexbox > *:nth-child(2) {
+ background-color: blue;
+ color: white;
+}
+
+div.container-flexbox > *:nth-child(3) {
+ background-color: orange;
+ color: white;
+}
+
+div.container-flexbox h2 {
+ text-align: center;
+}
+
+#chart-container {
+ height: 500px;
+}
diff --git a/blocks/live-voting/live-voting.js b/blocks/live-voting/live-voting.js
new file mode 100644
index 0000000..36135cb
--- /dev/null
+++ b/blocks/live-voting/live-voting.js
@@ -0,0 +1,141 @@
+import { loadScript, readBlockConfig } from '../../scripts/aem.js';
+import qrcode from '../../scripts/qrcode.js';
+
+const dp = [
+ ['Name', 'Votes'],
+ ['Jack Jin', 1],
+ ['Tanuj Jindal', 1],
+ ['Bruno Mateos', 1],
+];
+function drawChart() {
+ // eslint-disable-next-line no-undef
+ const data = google.visualization.arrayToDataTable(dp);
+
+ const options = {
+ is3D: true,
+ legend: { position: 'none' },
+ colors: ['red', 'blue', 'orange'],
+ };
+
+ // eslint-disable-next-line no-undef
+ const chart = new google.visualization.PieChart(document.getElementById('chart-container'));
+
+ chart.draw(data, options);
+}
+export default async function decorate(block) {
+ const config = readBlockConfig(block);
+ await loadScript('https://js.pusher.com/7.0/pusher-with-encryption.min.js', { defer: true });
+ await loadScript('https://www.gstatic.com/charts/loader.js', { defer: true });
+ if (config.config === 'all') {
+ // eslint-disable-next-line no-undef
+ const pusher = new Pusher('9d2674cf3e51f6d87102', {
+ cluster: 'us3',
+ useTLS: true,
+ });
+
+ const channel = pusher.subscribe('rs-poll');
+
+ // eslint-disable-next-line no-undef
+ google.charts.load('current', { packages: ['corechart'] });
+
+ channel.bind('rs-vote', (data) => {
+ // eslint-disable-next-line no-plusplus
+ for (let i = 0; i < dp.length; i++) {
+ if (dp[i][0] === data.name) {
+ dp[i][1] += 1;
+ drawChart();
+ }
+ }
+ console.log(
+ `The event rs-vote was triggered with data ${JSON.stringify(data)}`,
+ );
+ });
+
+ const names = JSON.parse(config.names).members;
+ const container = document.createElement('div');
+ container.classList.add('container-flexbox');
+ const col1 = document.createElement('div');
+
+ // eslint-disable-next-line new-cap
+ const qrcode1 = new qrcode(0, 'H');
+ qrcode1.addData('https://rockstar.adobeevents.com/en/live/a');
+ qrcode1.make();
+
+ // eslint-disable-next-line new-cap
+ const qrcode2 = new qrcode(0, 'H');
+ qrcode2.addData('https://rockstar.adobeevents.com/en/live/b');
+ qrcode2.make();
+
+ // eslint-disable-next-line new-cap
+ const qrcode3 = new qrcode(0, 'H');
+ qrcode3.addData('https://rockstar.adobeevents.com/en/live/c');
+ qrcode3.make();
+
+ const qr1 = document.createElement('div');
+ qr1.classList.add('qr1');
+ qr1.innerHTML = qrcode1.createSvgTag({});
+ col1.classList.add('col-1');
+ col1.appendChild(qr1);
+ const col1content = document.createElement('h2');
+ // eslint-disable-next-line prefer-destructuring
+ col1content.innerText = names[0];
+ col1.appendChild(col1content);
+ container.appendChild(col1);
+
+ // column two
+ const col2 = document.createElement('div');
+ col2.classList.add('col-2');
+ const qr2 = document.createElement('div');
+ qr2.innerHTML = qrcode2.createSvgTag({});
+ col2.appendChild(qr2);
+
+ const col2content = document.createElement('h2');
+ // eslint-disable-next-line prefer-destructuring
+ col2content.innerText = names[1];
+ col2.appendChild(col2content);
+ container.appendChild(col2);
+
+ // column three
+ const col3 = document.createElement('div');
+ col3.classList.add('col-3');
+ const qr3 = document.createElement('div');
+ qr3.innerHTML = qrcode3.createSvgTag({});
+ col3.appendChild(qr3);
+ const col3content = document.createElement('h2');
+ // eslint-disable-next-line prefer-destructuring
+ col3content.innerText = names[2];
+ col3.appendChild(col3content);
+ container.appendChild(col3);
+
+ block.replaceWith(container);
+ const chart = document.createElement('div');
+ chart.id = 'chart-container';
+ container.insertAdjacentElement('afterend', chart);
+ // eslint-disable-next-line no-undef
+ google.charts.setOnLoadCallback(drawChart);
+ } else {
+ const { name } = config;
+
+ const container = document.createElement('div');
+ container.classList.add('container-vote');
+
+ const res = await fetch('https://6hcuq5rf1h.execute-api.us-east-1.amazonaws.com/vote', {
+ method: 'POST',
+ body: JSON.stringify({ name }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ await res.json().then((data) => {
+ const vote = document.createElement('h2');
+ vote.innerText = data.message;
+ container.appendChild(vote);
+ });
+
+ block.replaceWith(container);
+
+ // put a limit on times a person can vote
+ }
+
+ console.log(`mode: ${config.config}`);
+}
diff --git a/scripts/qrcode.js b/scripts/qrcode.js
new file mode 100644
index 0000000..8597c5b
--- /dev/null
+++ b/scripts/qrcode.js
@@ -0,0 +1,2132 @@
+/**
+ *
+ *
+ *
+ *
+ * Github
+ * |
+ *
+ *
+ * |
+ *
+ *
+ * ### How to use:
+ *
+ * First run:
+ *
+ * ```
+ * npm install --save qrcode-generator-es6
+ * ```
+ *
+ * Then use it in your code like:
+ *
+ * ```
+ * import qrcode from './qrcode.js';
+ *
+ * const qr = new qrcode(0, 'H');
+ * qr.addData('This is my data');
+ * qr.make();
+ * my_element.innerHTML = qr.createSvgTag({});
+ * ```
+ *
+ * @module qrcode-generator-es6
+ */
+//---------------------------------------------------------------------
+//
+// QR Code Generator for JavaScript
+//
+// Copyright (c) 2009 Kazuhiko Arase
+//
+// URL: http://www.d-project.com/
+//
+// Licensed under the MIT license:
+// http://www.opensource.org/licenses/mit-license.php
+//
+// The word 'QR Code' is registered trademark of
+// DENSO WAVE INCORPORATED
+// http://www.denso-wave.com/qrcode/faqpatent-e.html
+//
+//---------------------------------------------------------------------
+
+const PAD0 = 0xec;
+const PAD1 = 0x11;
+
+/**
+ * Displays a QR code. Set the code data with `addData` and, call `make` and then call `createSvgTag` or `createImgTag`.
+ *
+ * See `gallery.html` for an example.
+ *
+ * @param {integer} typeNumber The minimum QR code type number from 1 to 40. Using 0 allows any QR code type number.
+ * @param {String} errorCorrectionLevel 'L','M','Q','H'
+ */
+export default class qrcode {
+ constructor(typeNumber, errorCorrectionLevel) {
+ this._typeNumber = typeNumber;
+ this._errorCorrectionLevel = QRErrorCorrectionLevel[errorCorrectionLevel];
+ this._modules = null;
+ this._moduleCount = 0;
+ this._dataCache = null;
+ this._dataList = [];
+
+ this.makeImpl = (test, maskPattern) => {
+ this._moduleCount = this._typeNumber * 4 + 17;
+ this._modules = (function(moduleCount) {
+ let modules = new Array(moduleCount);
+ for (let row = 0; row < moduleCount; row += 1) {
+ modules[row] = new Array(moduleCount);
+ for (let col = 0; col < moduleCount; col += 1) {
+ modules[row][col] = null;
+ }
+ }
+ return modules;
+ })(this._moduleCount);
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this._moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this._moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this._typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this._dataCache == null) {
+ this._dataCache = this.createData(
+ this._typeNumber,
+ this._errorCorrectionLevel,
+ this._dataList
+ );
+ }
+
+ this.mapData(this._dataCache, maskPattern);
+ };
+
+ this.setupPositionProbePattern = (row, col) => {
+ for (let r = -1; r <= 7; r += 1) {
+ if (row + r <= -1 || this._moduleCount <= row + r) continue;
+
+ for (let c = -1; c <= 7; c += 1) {
+ if (col + c <= -1 || this._moduleCount <= col + c) continue;
+
+ if (
+ (0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)
+ ) {
+ this._modules[row + r][col + c] = true;
+ } else {
+ this._modules[row + r][col + c] = false;
+ }
+ }
+ }
+ };
+
+ this.getBestMaskPattern = () => {
+ let minLostPoint = 0;
+ let pattern = 0;
+
+ for (let i = 0; i < 8; i += 1) {
+ this.makeImpl(true, i);
+
+ let lostPoint = QRUtil.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ };
+
+ this.setupTimingPattern = () => {
+ for (let r = 8; r < this._moduleCount - 8; r += 1) {
+ if (this._modules[r][6] != null) {
+ continue;
+ }
+ this._modules[r][6] = r % 2 == 0;
+ }
+
+ for (let c = 8; c < this._moduleCount - 8; c += 1) {
+ if (this._modules[6][c] != null) {
+ continue;
+ }
+ this._modules[6][c] = c % 2 == 0;
+ }
+ };
+
+ this.setupPositionAdjustPattern = () => {
+ let pos = QRUtil.getPatternPosition(this._typeNumber);
+
+ for (let i = 0; i < pos.length; i += 1) {
+ for (let j = 0; j < pos.length; j += 1) {
+ let row = pos[i];
+ let col = pos[j];
+
+ if (this._modules[row][col] != null) {
+ continue;
+ }
+
+ for (let r = -2; r <= 2; r += 1) {
+ for (let c = -2; c <= 2; c += 1) {
+ if (
+ r == -2 ||
+ r == 2 ||
+ c == -2 ||
+ c == 2 ||
+ (r == 0 && c == 0)
+ ) {
+ this._modules[row + r][col + c] = true;
+ } else {
+ this._modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ };
+
+ this.setupTypeNumber = test => {
+ let bits = QRUtil.getBCHTypeNumber(this._typeNumber);
+
+ for (let i = 0; i < 18; i += 1) {
+ const mod = !test && ((bits >> i) & 1) == 1;
+ this._modules[Math.floor(i / 3)][
+ (i % 3) + this._moduleCount - 8 - 3
+ ] = mod;
+ }
+
+ for (let i = 0; i < 18; i += 1) {
+ const mod = !test && ((bits >> i) & 1) == 1;
+ this._modules[(i % 3) + this._moduleCount - 8 - 3][
+ Math.floor(i / 3)
+ ] = mod;
+ }
+ };
+
+ this.setupTypeInfo = (test, maskPattern) => {
+ let data = (this._errorCorrectionLevel << 3) | maskPattern;
+ let bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (let i = 0; i < 15; i += 1) {
+ const mod = !test && ((bits >> i) & 1) == 1;
+
+ if (i < 6) {
+ this._modules[i][8] = mod;
+ } else if (i < 8) {
+ this._modules[i + 1][8] = mod;
+ } else {
+ this._modules[this._moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (let i = 0; i < 15; i += 1) {
+ const mod = !test && ((bits >> i) & 1) == 1;
+
+ if (i < 8) {
+ this._modules[8][this._moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this._modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this._modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this._modules[this._moduleCount - 8][8] = !test;
+ };
+
+ this.mapData = (data, maskPattern) => {
+ let inc = -1;
+ let row = this._moduleCount - 1;
+ let bitIndex = 7;
+ let byteIndex = 0;
+ let maskFunc = QRUtil.getMaskFunction(maskPattern);
+
+ for (let col = this._moduleCount - 1; col > 0; col -= 2) {
+ if (col == 6) col -= 1;
+
+ while (true) {
+ for (let c = 0; c < 2; c += 1) {
+ if (this._modules[row][col - c] == null) {
+ let dark = false;
+
+ if (byteIndex < data.length) {
+ dark = ((data[byteIndex] >>> bitIndex) & 1) == 1;
+ }
+
+ let mask = maskFunc(row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this._modules[row][col - c] = dark;
+ bitIndex -= 1;
+
+ if (bitIndex == -1) {
+ byteIndex += 1;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this._moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+ };
+
+ this.createBytes = (buffer, rsBlocks) => {
+ let offset = 0;
+
+ let maxDcCount = 0;
+ let maxEcCount = 0;
+
+ let dcdata = new Array(rsBlocks.length);
+ let ecdata = new Array(rsBlocks.length);
+
+ for (let r = 0; r < rsBlocks.length; r += 1) {
+ let dcCount = rsBlocks[r].dataCount;
+ let ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (let i = 0; i < dcdata[r].length; i += 1) {
+ dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
+ }
+ offset += dcCount;
+
+ let rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ let rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ let modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (let i = 0; i < ecdata[r].length; i += 1) {
+ let modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = modIndex >= 0 ? modPoly.getAt(modIndex) : 0;
+ }
+ }
+
+ let totalCodeCount = 0;
+ for (let i = 0; i < rsBlocks.length; i += 1) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ let data = new Array(totalCodeCount);
+ let index = 0;
+
+ for (let i = 0; i < maxDcCount; i += 1) {
+ for (let r = 0; r < rsBlocks.length; r += 1) {
+ if (i < dcdata[r].length) {
+ data[index] = dcdata[r][i];
+ index += 1;
+ }
+ }
+ }
+
+ for (let i = 0; i < maxEcCount; i += 1) {
+ for (let r = 0; r < rsBlocks.length; r += 1) {
+ if (i < ecdata[r].length) {
+ data[index] = ecdata[r][i];
+ index += 1;
+ }
+ }
+ }
+
+ return data;
+ };
+
+ this.createData = (typeNumber, errorCorrectionLevel, dataList) => {
+ let rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel);
+
+ let buffer = qrBitBuffer();
+
+ for (let i = 0; i < dataList.length; i += 1) {
+ let data = dataList[i];
+ buffer.put(data.getMode(), 4);
+ buffer.put(
+ data.getLength(),
+ QRUtil.getLengthInBits(data.getMode(), typeNumber)
+ );
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ let totalDataCount = 0;
+ for (let i = 0; i < rsBlocks.length; i += 1) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw "code length overflow. (" +
+ buffer.getLengthInBits() +
+ ">" +
+ totalDataCount * 8 +
+ ")";
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD1, 8);
+ }
+
+ return this.createBytes(buffer, rsBlocks);
+ };
+ }
+
+ addData(data, mode) {
+ mode = mode || "Byte";
+
+ let newData = null;
+
+ switch (mode) {
+ case "Numeric":
+ newData = qrNumber(data);
+ break;
+ case "Alphanumeric":
+ newData = qrAlphaNum(data);
+ break;
+ case "Byte":
+ newData = qr8BitByte(data);
+ break;
+ case "Kanji":
+ newData = qrKanji(data);
+ break;
+ default:
+ throw "mode:" + mode;
+ }
+
+ this._dataList.push(newData);
+ this._dataCache = null;
+ }
+
+ /**
+ * @returns {boolean} true if the module at `row, col` is dark.
+ */
+ isDark(row, col) {
+ if (
+ row < 0 ||
+ this._moduleCount <= row ||
+ col < 0 ||
+ this._moduleCount <= col
+ ) {
+ throw row + "," + col;
+ }
+ return this._modules[row][col];
+ }
+
+ /**
+ * @returns {integer} The module count in one dimension of the QR code. The total number of modules is the square of this value.
+ */
+ getModuleCount() {
+ return this._moduleCount;
+ }
+
+ /**
+ * Call this when done adding data before getting the generated QR code image.
+ */
+ make() {
+ if (this._typeNumber < 1) {
+ let typeNumber = 1;
+
+ for (; typeNumber < 40; typeNumber++) {
+ let rsBlocks = QRRSBlock.getRSBlocks(
+ typeNumber,
+ this._errorCorrectionLevel
+ );
+ let buffer = qrBitBuffer();
+
+ for (let i = 0; i < this._dataList.length; i++) {
+ let data = this._dataList[i];
+ buffer.put(data.getMode(), 4);
+ buffer.put(
+ data.getLength(),
+ QRUtil.getLengthInBits(data.getMode(), typeNumber)
+ );
+ data.write(buffer);
+ }
+
+ let totalDataCount = 0;
+ for (let i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() <= totalDataCount * 8) {
+ break;
+ }
+ }
+
+ this._typeNumber = typeNumber;
+ }
+
+ this.makeImpl(false, this.getBestMaskPattern());
+ }
+
+ /**
+ * @param {Object} args
+ * @param {function} [args.drawCell] A callback with arguments `column, row, x, y` to draw a cell. `x, y` are the coordinates to draw it at. `c, y` are the QR code module indexes. Returns the svg element child string for the cell.
+ * @param {function} [args.cellColor] A callback which returns the color for the cell. By default, a function that returns `black`. Unused if `drawCell` is provided.
+ * @param {integer} [args.margin] The margin to draw around the QR code, by number of cells.
+ * @param {Object} [args.bg] The background. White by default.
+ * @param {boolean} args.bg.enabled Draw a background
+ * @param {String} args.bg.fill Fill color of the background
+ * @param {Object} [args.obstruction] An image to place in the center of the QR code.
+ * @param {integer} args.obstruction.width Width of the obstruction as a percentage of QR code width.
+ * @param {integer} args.obstruction.height Height of the obstruction as a percentage of QR code height.
+ * @param {String} args.obstruction.path The path of the obstruction image. Exclusive with svgData.
+ * @param {String} args.obstruction.svgData The SVG data to embed as an obstruction. Must start with `