From 77508479b4dab3959adf7825273cd641000d9eab Mon Sep 17 00:00:00 2001 From: Rumperuu Date: Mon, 23 Jul 2018 14:08:17 +0100 Subject: [PATCH] Added QR codes to ballot selection, and a couple other minor chchanges --- Node/package.json | 2 +- Node/test/demos2-booth.js | 1 + README.md | 19 +++-- allauthdemo/polls/crypto_rpc.py | 1 - allauthdemo/polls/tasks.py | 2 +- .../templates/bases/bootstrap-jquery.html | 1 + static/js/create-event-poll.js | 12 +-- static/js/event_vote.js | 85 ++++++++++++++----- static/js/qrcode.min.js | 1 + 9 files changed, 81 insertions(+), 43 deletions(-) create mode 100644 static/js/qrcode.min.js diff --git a/Node/package.json b/Node/package.json index be592f5..3133702 100644 --- a/Node/package.json +++ b/Node/package.json @@ -1,5 +1,5 @@ { - "name": "Node DEMOS2 Cryptography Server", + "name": "node-demos2-cryptography-server", "version": "1.0.0", "description": "Exposes Cryptographic Functionality from Various Endpoints", "main": "index.js", diff --git a/Node/test/demos2-booth.js b/Node/test/demos2-booth.js index 6416c52..bd63803 100755 --- a/Node/test/demos2-booth.js +++ b/Node/test/demos2-booth.js @@ -35,6 +35,7 @@ gpGen = function(){ B.rcopy(ctx.ROM_CURVE.CURVE_Pyb); var Qy=new ctx.FP2(0); Qy.bset(A,B); var Q=new ctx.ECP2(); + var Q=new ctx.ECP2(); Q.setxy(Qy,Qy); return{ diff --git a/README.md b/README.md index 5104910..b543030 100755 --- a/README.md +++ b/README.md @@ -59,9 +59,17 @@ python manage.py runserver The application will then be available at `127.0.0.1:8000`. -You can then click on 'Join' to create a new user account. Currently, a server error is thrown when you create a new email account saying something like 'Too Many Attempts'. Rest assured that the account will have been created. Navigate back to the home page and you should be able to log in. This will hopefully be fixed in a future version. +You can then click on 'Join' to create a new user account. -### Step 2: Running Celery +### Step 2: Running the Node.js Server + +The Node.js server exposes a lot of cryptographic operations that the application depends on throughout. To run the server, issue the following command line request from the `Node/` folder: + +``` +node index.js +``` + +### Step 3: Running Celery Celery is used to run tasks asynchronously and the DEMOS2 application can't run without this application. A bash script called `start_celery_worker.sh` is provided to make starting a worker as easy as possible: @@ -69,10 +77,3 @@ Celery is used to run tasks asynchronously and the DEMOS2 application can't run ./start_celery_worker.sh ``` -### Step 3: Running the Node.js Server - -The Node.js server exposes a lot of cryptographic operations that the application depends on throughout. To run the server, issue the following command line request from the `Node/` folder: - -``` -node index.js -``` diff --git a/allauthdemo/polls/crypto_rpc.py b/allauthdemo/polls/crypto_rpc.py index b2d804f..35e124a 100755 --- a/allauthdemo/polls/crypto_rpc.py +++ b/allauthdemo/polls/crypto_rpc.py @@ -30,7 +30,6 @@ def param(): jsondict = json.load(urllib2.urlopen(url)) return json.dumps(jsondict) - def combpk(pks): url = 'http://localhost:8080/cmpkstring' diff --git a/allauthdemo/polls/tasks.py b/allauthdemo/polls/tasks.py index ebe53ad..277d0ad 100755 --- a/allauthdemo/polls/tasks.py +++ b/allauthdemo/polls/tasks.py @@ -16,7 +16,7 @@ from .crypto_rpc import param, combpk, add_ciphers, get_tally The following tasks were re-implemented by Thomas Smith: generate_event_param, tally_results, generate_combpk, generate_enc - This file was also updated by Vincent de Almeida + This file was also updated by Vincent de Almeida and Ben Goldsworthy ''' # Will store the result of the initial cal to param() from .cpp_calls diff --git a/allauthdemo/templates/bases/bootstrap-jquery.html b/allauthdemo/templates/bases/bootstrap-jquery.html index e19f8b0..f75137b 100755 --- a/allauthdemo/templates/bases/bootstrap-jquery.html +++ b/allauthdemo/templates/bases/bootstrap-jquery.html @@ -17,6 +17,7 @@ integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"> + diff --git a/static/js/create-event-poll.js b/static/js/create-event-poll.js index 84c8e6a..cd8f080 100755 --- a/static/js/create-event-poll.js +++ b/static/js/create-event-poll.js @@ -235,16 +235,12 @@ function isEventTimingsValid() { var valid = true; var helpBlockId = "event-timings-error-block"; - // Extract the string val from the vote start and end input controls - var start_date_time = $('#vote-start-input').val(); - var end_date_time = $('#vote-end-input').val(); - - // Convert the string vals to Date objects - var start_dateObj = new Date(start_date_time); - var end_dateObj = new Date(end_date_time); + // Extract the dates from the vote start and end input controls + var start_date_time = $('#vote-start-input').data('DateTimePicker').date(); + var end_date_time = $('#vote-end-input').data('DateTimePicker').date(); // Ensure that the start date is before the end date and that the end date is after the start date - if(!(start_dateObj < end_dateObj && end_dateObj > start_dateObj)) { + if(!(start_date_time < end_date_time && end_date_time > start_date_time)) { checkAndAddError({ error: "The start date must be before the end date and the end after the start date.", helpBlockId: "event-timings-error-block" diff --git a/static/js/event_vote.js b/static/js/event_vote.js index 6de7a42..d97a1e7 100644 --- a/static/js/event_vote.js +++ b/static/js/event_vote.js @@ -211,7 +211,7 @@ function csrfSafeMethod(method) { return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } -function sendBallotToServer(ballot) { +function sendBallotToServer(selection, altHash) { $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { @@ -223,9 +223,9 @@ function sendBallotToServer(ballot) { $.ajax({ type : "POST", url : window.location, - data : JSON.stringify({ ballot: ballot}), + data : JSON.stringify({ ballot: selection}), success : function(){ - voteSuccessfullyReceived(); + onAfterBallotSend(altHash); } }); } @@ -272,30 +272,69 @@ function SHA256Hash(bytes, toStr) { } } -// FAO Ben: Called once the ballot has been sent to the back-end and dialog has closed -function onAfterBallotSend() { - // TODO: FAO Ben: Implement QR func here. - // TODO: Currently, there is a dialog already implemented in the event_vote.html page which is - // TODO: used for voting error information but could be used to display the QR code using JS in - // TODO: a similar way that showBallotChoiceDialog does. +// Called once the ballot has been sent to the back-end and dialog has closed +function onAfterBallotSend(altHash) { + let titleText = 'Vote Successfully Received'; + let bodyText = "Thank you for voting! This is your copy of your ballot - make sure to save it onto your phone before closing this window."; + + if(POLL_NUM !== POLL_COUNT) { + bodyText += " You can vote on the next poll by closing down this dialog and clicking 'Next Poll'."; + } + + // With one ballot selected, we can display a QR code of the voter's copy + var modalDialog = $('#modalDialog'); + var title = modalDialog.find('.modal-title'); + var body = modalDialog.find('.modal-body'); + title.text(titleText); + body.empty(); + + var p = document.createElement("p"); + p.innerHTML = bodyText; + body.append(p); + + // Generate the body of the dialog which displays the unselected ballot QR code and hash + var choiceGroupDiv = document.createElement('div'); + choiceGroupDiv.setAttribute('class', 'choice-group'); + + var QRCodeImg = document.createElement('img'); + QRCodeImg.setAttribute('class', 'QR-code'); + new QRCode(QRCodeImg, altHash); + + choiceGroupDiv.append(QRCodeImg); + + // ---------------------------------------------- + + var hashGroupDiv = document.createElement('div'); + var br = document.createElement('br'); + hashGroupDiv.append( br ); + + var hash = document.createElement("span"); + hash.innerHTML = "Hash: " + altHash; + hashGroupDiv.append( hash ); + + // ----------------------------------------------- + + body.append(choiceGroupDiv); + body.append(hashGroupDiv); + + modalDialog.modal('show'); } -function processBallotSelection(selection, selectionHash, successFn) { +function processBallotSelection(selection, selectionHash, alt, altHash) { // Dispatch the ballot to the server - sendBallotToServer(selection); - - // Close the choice selection dialog - var modalDialog = $('#modalDialog'); - modal.modal('hide'); + sendBallotToServer(selection, altHash); // Call the successfn currently with the selection hash but this may not be needed - successFn(selectionHash); + //successFn(alt, altHash); } function showBallotChoiceDialog(ballotA, ballotB) { - // Output hashes of the 2 ballots - const BALLOT_A_HASH = SHA256Hash(stringtobytes(JSON.stringify(ballotA)), true); - const BALLOT_B_HASH = SHA256Hash(stringtobytes(JSON.stringify(ballotB)), true); + var ballots = new Array(ballotA, ballotB); + var ballotHashes = new Array(2); + + // Hash both ballots and store + for (let i = 0; i <= 1; i++) + ballotHashes[i] = SHA256Hash(stringtobytes(JSON.stringify(ballots[i])), true); // With the ballots and their hashes generated, we can display the ballot choice dialog var modalDialog = $('#modalDialog'); @@ -327,14 +366,14 @@ function showBallotChoiceDialog(ballotA, ballotB) { hashGroupDiv.append( br ); var hashA = document.createElement("span"); - hashA.innerHTML = "Hash A: " + BALLOT_A_HASH; + hashA.innerHTML = "Hash A: " + ballotHashes[0]; hashGroupDiv.append( hashA ); var br2 = document.createElement('br'); hashGroupDiv.append( br2 ); var hashB = document.createElement("span"); - hashB.innerHTML = "Hash B: " + BALLOT_B_HASH; + hashB.innerHTML = "Hash B: " + ballotHashes[1]; hashGroupDiv.append( hashB ); // ----------------------------------------------- @@ -346,11 +385,11 @@ function showBallotChoiceDialog(ballotA, ballotB) { // Register callback functions for the selection of either A or B $('#choice-A').click(function(e) { - processBallotSelection(ballotA, BALLOT_A_HASH, onAfterBallotSend); + processBallotSelection(ballots[0], ballotHashes[0], ballots[1], ballotHashes[1]); }); $('#choice-B').click(function(e) { - processBallotSelection(ballotB, BALLOT_B_HASH, onAfterBallotSend); + processBallotSelection(ballots[1], ballotHashes[1], ballots[0], ballotHashes[0]); }); } diff --git a/static/js/qrcode.min.js b/static/js/qrcode.min.js new file mode 100644 index 0000000..993e88f --- /dev/null +++ b/static/js/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file