UdjinM6

Open Source JavaScript Darkcoin Brain Wallet Generator

Jan 27th, 2015
2,094
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 429.06 KB | None | 0 0
  1. <!doctype html>
  2. <html><head>
  3.     <title>Darkcoin paper wallet generator</title>
  4.     <!--
  5.    
  6.    generate-wallet.html (from https://bitcoinpaperwallet.com)
  7.    
  8.    Contact: Canton Becker / canton@gmail.com / www.cantonbecker.com
  9.    
  10.    generate-wallet.html is always distributed with a PGP signature "generate-wallet.html.sig" which you
  11.    can use to validate the integrity and authorship of this file like so:
  12.    
  13.    gpg --recv-key 36E1D9B6
  14.    gpg --verify --with-fingerprint generate-wallet.html.sig generate-wallet.html    
  15.    
  16.     The bitcoinpaperwallet.com folding wallet design may not be used for commercial use
  17.    without permission. The design of the bitcoin hologram sticker used to seal these wallets
  18.    is copyrighted. As a courtesy, please do not modify this software in such a way that the
  19.    links to purchase hologram stickers and wallet making supplies are removed or pointed elsewhere.
  20.    
  21.    This software (HTML and JavaScript) is ©Copyright 2014 Canton Becker and bitaddress.org
  22.    and licensed under the MIT license.
  23.    
  24.    Special thanks to pointbiz/bitaddress.org and Artiom Chilaru/flexlabs.org for significant
  25.    contributions to this software.
  26.    
  27.    Portions of this code are copyrighted by their respective authors - see below.
  28.  
  29.    ****************************************************************************************
  30.    ****************************************************************************************
  31.    * Contributions to support the bitcoinpaperwallet.com developers are extremely welcome.
  32.    * Bitcoin Donation Address: 1Pjg628vjMLBvADrPHsthtzKiryM2y46DG
  33.     * GitHub Repository:    https://github.com/cantonbecker/bitcoinpaperwallet
  34.    ****************************************************************************************
  35.     * The starting point for this code was the excellent single-file bitaddress.org project.
  36.    * Bitcoin Donation Address: 1NiNja1bUmhSoTXozBRBEtR8LeF9TGbZBN
  37.     * GitHub Repository:    https://github.com/pointbiz/bitaddress.org
  38.    ****************************************************************************************
  39.    ****************************************************************************************
  40.  
  41.  
  42.     Notice of Copyrights and Licenses:
  43.     ***********************************
  44.     The bitaddress.org project, software and embedded resources are copyright bitaddress.org.
  45.  
  46.     Portions of the all-in-one HTML document contain JavaScript codes that are the copyrights of others.
  47.     The individual copyrights are included throughout the document along with their licenses.
  48.     Included JavaScript libraries are separated with HTML script tags.
  49.  
  50.     Summary of JavaScript functions with a redistributable license:
  51.     JavaScript function     License
  52.     *******************     ***************
  53.     Array.prototype.map     Public Domain
  54.     window.Crypto           BSD License
  55.     window.SecureRandom     BSD License
  56.     window.EllipticCurve        BSD License
  57.     window.BigInteger       BSD License
  58.     window.QRCode           MIT License
  59.     window.Bitcoin          MIT License
  60.     window.Crypto_scrypt        MIT License
  61.     ninja.(*)               MIT License             // from bitaddress.org
  62.     parser.setUA            GPLv2 & MIT             // Browser User Agent detection
  63.     jsqrcode                Apache License, 2.0     // QR Code scanning from webcam
  64.    
  65.     This HTML file and the graphics required to make it work are available under The MIT License (MIT)
  66.  
  67.     Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  68.     associated documentation files (the "Software"), to deal in the Software without restriction, including
  69.     without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  70.     sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject
  71.     to the following conditions:
  72.  
  73.     The above copyright notice and this permission notice shall be included in all copies or substantial
  74.     portions of the Software.
  75.  
  76.     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  77.     LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  78.     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  79.     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  80.     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  81.  
  82.     GitHub Repository: https://github.com/cantonbecker/bitcoinpaperwallet
  83.     -->
  84.  
  85.     <meta charset="utf-8">
  86.  
  87. <script type="text/javascript">
  88.  
  89. function setCryptoCurrency(toThis) {
  90.     window.currencyName = toThis;
  91.     switch (toThis)
  92.     {
  93.     case 'Bitcoin':
  94.       window.networkVersion = 0x00;
  95.       window.privateKeyPrefix = 0x80;
  96.       window.WIFPrefix = '5';
  97.       window.compressedWIFPrefix = '[LK]';
  98.       break;
  99.     case 'Litecoin':
  100.         window.networkVersion = 0x30;
  101.         window.privateKeyPrefix = 0xb0;
  102.         window.WIFPrefix = '6';
  103.         window.compressedWIFPrefix = 'T';
  104.         document.title = 'Litecoin paper wallet generator';
  105.         break;
  106.     case 'Dogecoin':
  107.         window.networkVersion = 0x1e;
  108.         window.privateKeyPrefix = 0x9e;
  109.         window.WIFPrefix = '6';
  110.         window.compressedWIFPrefix = 'Q';  
  111.         document.title = 'Dogecoin paper wallet generator. Wow! Many coin. Such shiny.';
  112.         break;
  113.     case 'Darkcoin':
  114.         window.networkVersion = 0x4c;
  115.         window.privateKeyPrefix = 0xcc;
  116.         window.WIFPrefix = '7';
  117.         window.compressedWIFPrefix = 'X';
  118.         document.title = 'Darkcoin paper wallet generator'
  119.         break;
  120.     case 'Testnet':
  121.         window.networkVersion = 0x6F;
  122.         window.privateKeyPrefix = 0xEF;
  123.         window.WIFPrefix = '9';
  124.         window.compressedWIFPrefix = 'c';
  125.         document.title = 'Bitcoin TESTNET paper wallet generator';
  126.         break;
  127.     default:
  128.       alert ('Invalid cryptocurrency "' + toThis + '" at initialization. Defaulting to Bitcoin.');
  129.       setCryptoCurrency('Bitcoin');    
  130.     } // eof switch
  131.     return (true);
  132. }
  133.  
  134. function getParameterByName(name) {
  135.     name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
  136.     var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
  137.        results = regex.exec(location.search);
  138.     return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  139. }
  140.  
  141. var myDesign = getParameterByName('design');
  142. window.suppliesURL = 'https://bitcoinpaperwallet.com/?p=' + myDesign + '#purchase';
  143.  
  144. switch (myDesign) {
  145.     case 'alt-litecoin':
  146.         setCryptoCurrency('Litecoin');
  147.         break;
  148.     case 'alt-dogecoin':
  149.         setCryptoCurrency('Dogecoin');
  150.         break;
  151.     case 'alt-darkcoin':
  152.         setCryptoCurrency('Darkcoin');
  153.         break;
  154.     case 'alt-testnet':
  155.         setCryptoCurrency('Testnet');
  156.         break;
  157.     default:
  158.     setCryptoCurrency('Bitcoin');
  159.     window.suppliesURL = 'https://bitcoinpaperwallet.com/#purchase'; // remove special currency flag
  160. }
  161.  
  162. </script>
  163.  
  164.     <script type="text/javascript">
  165. // Array.prototype.map function is in the public domain.
  166. // Production steps of ECMA-262, Edition 5, 15.4.4.19  
  167. // Reference: http://es5.github.com/#x15.4.4.19  
  168. if (!Array.prototype.map) {
  169.     Array.prototype.map = function (callback, thisArg) {
  170.         var T, A, k;
  171.         if (this == null) {
  172.             throw new TypeError(" this is null or not defined");
  173.         }
  174.         // 1. Let O be the result of calling ToObject passing the |this| value as the argument.  
  175.         var O = Object(this);
  176.         // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".  
  177.         // 3. Let len be ToUint32(lenValue).  
  178.         var len = O.length >>> 0;
  179.         // 4. If IsCallable(callback) is false, throw a TypeError exception.  
  180.         // See: http://es5.github.com/#x9.11  
  181.         if ({}.toString.call(callback) != "[object Function]") {
  182.             throw new TypeError(callback + " is not a function");
  183.         }
  184.         // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.  
  185.         if (thisArg) {
  186.             T = thisArg;
  187.         }
  188.         // 6. Let A be a new array created as if by the expression new Array(len) where Array is  
  189.         // the standard built-in constructor with that name and len is the value of len.  
  190.         A = new Array(len);
  191.         // 7. Let k be 0  
  192.         k = 0;
  193.         // 8. Repeat, while k < len  
  194.         while (k < len) {
  195.             var kValue, mappedValue;
  196.             // a. Let Pk be ToString(k).  
  197.             //   This is implicit for LHS operands of the in operator  
  198.             // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.  
  199.             //   This step can be combined with c  
  200.             // c. If kPresent is true, then  
  201.             if (k in O) {
  202.                 // i. Let kValue be the result of calling the Get internal method of O with argument Pk.  
  203.                 kValue = O[k];
  204.                 // ii. Let mappedValue be the result of calling the Call internal method of callback  
  205.                 // with T as the this value and argument list containing kValue, k, and O.  
  206.                 mappedValue = callback.call(T, kValue, k, O);
  207.                 // iii. Call the DefineOwnProperty internal method of A with arguments  
  208.                 // Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},  
  209.                 // and false.  
  210.                 // In browsers that support Object.defineProperty, use the following:  
  211.                 // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });  
  212.                 // For best browser support, use the following:  
  213.                 A[k] = mappedValue;
  214.             }
  215.             // d. Increase k by 1.  
  216.             k++;
  217.         }
  218.         // 9. return A  
  219.         return A;
  220.     };
  221. }
  222.     </script>
  223.     <script type="text/javascript">
  224. /*!
  225. * Crypto-JS v2.5.4  Crypto.js
  226. * http://code.google.com/p/crypto-js/
  227. * Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
  228. * http://code.google.com/p/crypto-js/wiki/License
  229. */
  230. if (typeof Crypto == "undefined" || !Crypto.util) {
  231.     (function () {
  232.  
  233.         var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  234.  
  235.         // Global Crypto object
  236.         var Crypto = window.Crypto = {};
  237.  
  238.         // Crypto utilities
  239.         var util = Crypto.util = {
  240.  
  241.             // Bit-wise rotate left
  242.             rotl: function (n, b) {
  243.                 return (n << b) | (n >>> (32 - b));
  244.             },
  245.  
  246.             // Bit-wise rotate right
  247.             rotr: function (n, b) {
  248.                 return (n << (32 - b)) | (n >>> b);
  249.             },
  250.  
  251.             // Swap big-endian to little-endian and vice versa
  252.             endian: function (n) {
  253.  
  254.                 // If number given, swap endian
  255.                 if (n.constructor == Number) {
  256.                     return util.rotl(n, 8) & 0x00FF00FF |
  257.                 util.rotl(n, 24) & 0xFF00FF00;
  258.                 }
  259.  
  260.                 // Else, assume array and swap all items
  261.                 for (var i = 0; i < n.length; i++)
  262.                     n[i] = util.endian(n[i]);
  263.                 return n;
  264.  
  265.             },
  266.  
  267.             // Generate an array of any length of random bytes
  268.             randomBytes: function (n) {
  269.                 for (var bytes = []; n > 0; n--)
  270.                     bytes.push(Math.floor(Math.random() * 256));
  271.                 return bytes;
  272.             },
  273.  
  274.             // Convert a byte array to big-endian 32-bit words
  275.             bytesToWords: function (bytes) {
  276.                 for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
  277.                     words[b >>> 5] |= (bytes[i] & 0xFF) << (24 - b % 32);
  278.                 return words;
  279.             },
  280.  
  281.             // Convert big-endian 32-bit words to a byte array
  282.             wordsToBytes: function (words) {
  283.                 for (var bytes = [], b = 0; b < words.length * 32; b += 8)
  284.                     bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
  285.                 return bytes;
  286.             },
  287.  
  288.             // Convert a byte array to a hex string
  289.             bytesToHex: function (bytes) {
  290.                 for (var hex = [], i = 0; i < bytes.length; i++) {
  291.                     hex.push((bytes[i] >>> 4).toString(16));
  292.                     hex.push((bytes[i] & 0xF).toString(16));
  293.                 }
  294.                 return hex.join("");
  295.             },
  296.  
  297.             // Convert a hex string to a byte array
  298.             hexToBytes: function (hex) {
  299.                 for (var bytes = [], c = 0; c < hex.length; c += 2)
  300.                     bytes.push(parseInt(hex.substr(c, 2), 16));
  301.                 return bytes;
  302.             },
  303.  
  304.             // Convert a byte array to a base-64 string
  305.             bytesToBase64: function (bytes) {
  306.                 for (var base64 = [], i = 0; i < bytes.length; i += 3) {
  307.                     var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
  308.                     for (var j = 0; j < 4; j++) {
  309.                         if (i * 8 + j * 6 <= bytes.length * 8)
  310.                             base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
  311.                         else base64.push("=");
  312.                     }
  313.                 }
  314.  
  315.                 return base64.join("");
  316.             },
  317.  
  318.             // Convert a base-64 string to a byte array
  319.             base64ToBytes: function (base64) {
  320.                 // Remove non-base-64 characters
  321.                 base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
  322.  
  323.                 for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
  324.                     if (imod4 == 0) continue;
  325.                     bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
  326.                     (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
  327.                 }
  328.  
  329.                 return bytes;
  330.             }
  331.  
  332.         };
  333.  
  334.         // Crypto character encodings
  335.         var charenc = Crypto.charenc = {};
  336.  
  337.         // UTF-8 encoding
  338.         var UTF8 = charenc.UTF8 = {
  339.  
  340.             // Convert a string to a byte array
  341.             stringToBytes: function (str) {
  342.                 return Binary.stringToBytes(unescape(encodeURIComponent(str)));
  343.             },
  344.  
  345.             // Convert a byte array to a string
  346.             bytesToString: function (bytes) {
  347.                 return decodeURIComponent(escape(Binary.bytesToString(bytes)));
  348.             }
  349.  
  350.         };
  351.  
  352.         // Binary encoding
  353.         var Binary = charenc.Binary = {
  354.  
  355.             // Convert a string to a byte array
  356.             stringToBytes: function (str) {
  357.                 for (var bytes = [], i = 0; i < str.length; i++)
  358.                     bytes.push(str.charCodeAt(i) & 0xFF);
  359.                 return bytes;
  360.             },
  361.  
  362.             // Convert a byte array to a string
  363.             bytesToString: function (bytes) {
  364.                 for (var str = [], i = 0; i < bytes.length; i++)
  365.                     str.push(String.fromCharCode(bytes[i]));
  366.                 return str.join("");
  367.             }
  368.  
  369.         };
  370.  
  371.     })();
  372. }  
  373.     </script>
  374.     <script type="text/javascript">
  375. /*!
  376. * Crypto-JS v2.5.4  SHA256.js
  377. * http://code.google.com/p/crypto-js/
  378. * Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
  379. * http://code.google.com/p/crypto-js/wiki/License
  380. */
  381. (function () {
  382.  
  383.     // Shortcuts
  384.     var C = Crypto,
  385.         util = C.util,
  386.         charenc = C.charenc,
  387.         UTF8 = charenc.UTF8,
  388.         Binary = charenc.Binary;
  389.  
  390.     // Constants
  391.     var K = [0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
  392.         0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
  393.         0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
  394.         0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
  395.         0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
  396.         0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
  397.         0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
  398.         0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
  399.         0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
  400.         0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
  401.         0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
  402.         0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
  403.         0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
  404.         0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
  405.         0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
  406.         0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2];
  407.  
  408.     // Public API
  409.     var SHA256 = C.SHA256 = function (message, options) {
  410.         var digestbytes = util.wordsToBytes(SHA256._sha256(message));
  411.         return options && options.asBytes ? digestbytes :
  412.         options && options.asString ? Binary.bytesToString(digestbytes) :
  413.         util.bytesToHex(digestbytes);
  414.     };
  415.  
  416.     // The core
  417.     SHA256._sha256 = function (message) {
  418.  
  419.         // Convert to byte array
  420.         if (message.constructor == String) message = UTF8.stringToBytes(message);
  421.         /* else, assume byte array already */
  422.  
  423.         var m = util.bytesToWords(message),
  424.         l = message.length * 8,
  425.         H = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
  426.                 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19],
  427.         w = [],
  428.         a, b, c, d, e, f, g, h, i, j,
  429.         t1, t2;
  430.  
  431.         // Padding
  432.         m[l >> 5] |= 0x80 << (24 - l % 32);
  433.         m[((l + 64 >> 9) << 4) + 15] = l;
  434.  
  435.         for (var i = 0; i < m.length; i += 16) {
  436.  
  437.             a = H[0];
  438.             b = H[1];
  439.             c = H[2];
  440.             d = H[3];
  441.             e = H[4];
  442.             f = H[5];
  443.             g = H[6];
  444.             h = H[7];
  445.  
  446.             for (var j = 0; j < 64; j++) {
  447.  
  448.                 if (j < 16) w[j] = m[j + i];
  449.                 else {
  450.  
  451.                     var gamma0x = w[j - 15],
  452.                 gamma1x = w[j - 2],
  453.                 gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
  454.                             ((gamma0x << 14) | (gamma0x >>> 18)) ^
  455.                             (gamma0x >>> 3),
  456.                 gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
  457.                             ((gamma1x << 13) | (gamma1x >>> 19)) ^
  458.                             (gamma1x >>> 10);
  459.  
  460.                     w[j] = gamma0 + (w[j - 7] >>> 0) +
  461.                     gamma1 + (w[j - 16] >>> 0);
  462.  
  463.                 }
  464.  
  465.                 var ch = e & f ^ ~e & g,
  466.             maj = a & b ^ a & c ^ b & c,
  467.             sigma0 = ((a << 30) | (a >>> 2)) ^
  468.                         ((a << 19) | (a >>> 13)) ^
  469.                         ((a << 10) | (a >>> 22)),
  470.             sigma1 = ((e << 26) | (e >>> 6)) ^
  471.                         ((e << 21) | (e >>> 11)) ^
  472.                         ((e << 7) | (e >>> 25));
  473.  
  474.  
  475.                 t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0);
  476.                 t2 = sigma0 + maj;
  477.  
  478.                 h = g;
  479.                 g = f;
  480.                 f = e;
  481.                 e = (d + t1) >>> 0;
  482.                 d = c;
  483.                 c = b;
  484.                 b = a;
  485.                 a = (t1 + t2) >>> 0;
  486.  
  487.             }
  488.  
  489.             H[0] += a;
  490.             H[1] += b;
  491.             H[2] += c;
  492.             H[3] += d;
  493.             H[4] += e;
  494.             H[5] += f;
  495.             H[6] += g;
  496.             H[7] += h;
  497.  
  498.         }
  499.  
  500.         return H;
  501.  
  502.     };
  503.  
  504.     // Package private blocksize
  505.     SHA256._blocksize = 16;
  506.  
  507.     SHA256._digestsize = 32;
  508.  
  509. })();  
  510.     </script>
  511.     <script type="text/javascript">
  512. /*!
  513. * Crypto-JS v2.5.4  PBKDF2.js
  514. * http://code.google.com/p/crypto-js/
  515. * Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
  516. * http://code.google.com/p/crypto-js/wiki/License
  517. */
  518. (function () {
  519.  
  520.     // Shortcuts
  521.     var C = Crypto,
  522.         util = C.util,
  523.         charenc = C.charenc,
  524.         UTF8 = charenc.UTF8,
  525.         Binary = charenc.Binary;
  526.  
  527.     C.PBKDF2 = function (password, salt, keylen, options) {
  528.  
  529.         // Convert to byte arrays
  530.         if (password.constructor == String) password = UTF8.stringToBytes(password);
  531.         if (salt.constructor == String) salt = UTF8.stringToBytes(salt);
  532.         /* else, assume byte arrays already */
  533.  
  534.         // Defaults
  535.         var hasher = options && options.hasher || C.SHA1,
  536.             iterations = options && options.iterations || 1;
  537.  
  538.         // Pseudo-random function
  539.         function PRF(password, salt) {
  540.             return C.HMAC(hasher, salt, password, { asBytes: true });
  541.         }
  542.  
  543.         // Generate key
  544.         var derivedKeyBytes = [],
  545.             blockindex = 1;
  546.         while (derivedKeyBytes.length < keylen) {
  547.             var block = PRF(password, salt.concat(util.wordsToBytes([blockindex])));
  548.             for (var u = block, i = 1; i < iterations; i++) {
  549.                 u = PRF(password, u);
  550.                 for (var j = 0; j < block.length; j++) block[j] ^= u[j];
  551.             }
  552.             derivedKeyBytes = derivedKeyBytes.concat(block);
  553.             blockindex++;
  554.         }
  555.  
  556.         // Truncate excess bytes
  557.         derivedKeyBytes.length = keylen;
  558.  
  559.         return options && options.asBytes ? derivedKeyBytes :
  560.         options && options.asString ? Binary.bytesToString(derivedKeyBytes) :
  561.         util.bytesToHex(derivedKeyBytes);
  562.  
  563.     };
  564.  
  565. })();
  566.     </script>
  567.     <script type="text/javascript">
  568. /*!
  569. * Crypto-JS v2.5.4  HMAC.js
  570. * http://code.google.com/p/crypto-js/
  571. * Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
  572. * http://code.google.com/p/crypto-js/wiki/License
  573. */
  574. (function () {
  575.  
  576.     // Shortcuts
  577.     var C = Crypto,
  578.         util = C.util,
  579.         charenc = C.charenc,
  580.         UTF8 = charenc.UTF8,
  581.         Binary = charenc.Binary;
  582.  
  583.     C.HMAC = function (hasher, message, key, options) {
  584.  
  585.         // Convert to byte arrays
  586.         if (message.constructor == String) message = UTF8.stringToBytes(message);
  587.         if (key.constructor == String) key = UTF8.stringToBytes(key);
  588.         /* else, assume byte arrays already */
  589.  
  590.         // Allow arbitrary length keys
  591.         if (key.length > hasher._blocksize * 4)
  592.             key = hasher(key, { asBytes: true });
  593.  
  594.         // XOR keys with pad constants
  595.         var okey = key.slice(0),
  596.             ikey = key.slice(0);
  597.         for (var i = 0; i < hasher._blocksize * 4; i++) {
  598.             okey[i] ^= 0x5C;
  599.             ikey[i] ^= 0x36;
  600.         }
  601.  
  602.         var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true });
  603.  
  604.         return options && options.asBytes ? hmacbytes :
  605.         options && options.asString ? Binary.bytesToString(hmacbytes) :
  606.         util.bytesToHex(hmacbytes);
  607.  
  608.     };
  609.  
  610. })();
  611.     </script>
  612.     <script type="text/javascript">
  613. /*!
  614. * Crypto-JS v2.5.4  AES.js
  615. * http://code.google.com/p/crypto-js/
  616. * Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
  617. * http://code.google.com/p/crypto-js/wiki/License
  618. */
  619. (function () {
  620.  
  621.     // Shortcuts
  622.     var C = Crypto,
  623.         util = C.util,
  624.         charenc = C.charenc,
  625.         UTF8 = charenc.UTF8;
  626.  
  627.     // Precomputed SBOX
  628.     var SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
  629.             0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
  630.             0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
  631.             0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
  632.             0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
  633.             0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
  634.             0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
  635.             0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
  636.             0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
  637.             0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
  638.             0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
  639.             0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
  640.             0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
  641.             0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
  642.             0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
  643.             0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
  644.             0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
  645.             0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
  646.             0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
  647.             0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
  648.             0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
  649.             0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
  650.             0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
  651.             0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
  652.             0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
  653.             0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
  654.             0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
  655.             0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
  656.             0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
  657.             0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
  658.             0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
  659.             0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
  660.  
  661.     // Compute inverse SBOX lookup table
  662.     for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i;
  663.  
  664.     // Compute multiplication in GF(2^8) lookup tables
  665.     var MULT2 = [],
  666.         MULT3 = [],
  667.         MULT9 = [],
  668.         MULTB = [],
  669.         MULTD = [],
  670.         MULTE = [];
  671.  
  672.     function xtime(a, b) {
  673.         for (var result = 0, i = 0; i < 8; i++) {
  674.             if (b & 1) result ^= a;
  675.             var hiBitSet = a & 0x80;
  676.             a = (a << 1) & 0xFF;
  677.             if (hiBitSet) a ^= 0x1b;
  678.             b >>>= 1;
  679.         }
  680.         return result;
  681.     }
  682.  
  683.     for (var i = 0; i < 256; i++) {
  684.         MULT2[i] = xtime(i, 2);
  685.         MULT3[i] = xtime(i, 3);
  686.         MULT9[i] = xtime(i, 9);
  687.         MULTB[i] = xtime(i, 0xB);
  688.         MULTD[i] = xtime(i, 0xD);
  689.         MULTE[i] = xtime(i, 0xE);
  690.     }
  691.  
  692.     // Precomputed RCon lookup
  693.     var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
  694.  
  695.     // Inner state
  696.     var state = [[], [], [], []],
  697.         keylength,
  698.         nrounds,
  699.         keyschedule;
  700.  
  701.     var AES = C.AES = {
  702.  
  703.         /**
  704.         * Public API
  705.         */
  706.  
  707.         encrypt: function (message, password, options) {
  708.  
  709.             options = options || {};
  710.  
  711.             // Determine mode
  712.             var mode = options.mode || new C.mode.OFB;
  713.  
  714.             // Allow mode to override options
  715.             if (mode.fixOptions) mode.fixOptions(options);
  716.  
  717.             var
  718.  
  719.             // Convert to bytes if message is a string
  720.         m = (
  721.             message.constructor == String ?
  722.             UTF8.stringToBytes(message) :
  723.             message
  724.         ),
  725.  
  726.             // Generate random IV
  727.         iv = options.iv || util.randomBytes(AES._blocksize * 4),
  728.  
  729.             // Generate key
  730.         k = (
  731.             password.constructor == String ?
  732.             // Derive key from pass-phrase
  733.             C.PBKDF2(password, iv, 32, { asBytes: true }) :
  734.             // else, assume byte array representing cryptographic key
  735.             password
  736.         );
  737.  
  738.             // Encrypt
  739.             AES._init(k);
  740.             mode.encrypt(AES, m, iv);
  741.  
  742.             // Return ciphertext
  743.             m = options.iv ? m : iv.concat(m);
  744.             return (options && options.asBytes) ? m : util.bytesToBase64(m);
  745.  
  746.         },
  747.  
  748.         decrypt: function (ciphertext, password, options) {
  749.  
  750.             options = options || {};
  751.  
  752.             // Determine mode
  753.             var mode = options.mode || new C.mode.OFB;
  754.  
  755.             // Allow mode to override options
  756.             if (mode.fixOptions) mode.fixOptions(options);
  757.  
  758.             var
  759.  
  760.             // Convert to bytes if ciphertext is a string
  761.         c = (
  762.             ciphertext.constructor == String ?
  763.             util.base64ToBytes(ciphertext) :
  764.             ciphertext
  765.         ),
  766.  
  767.             // Separate IV and message
  768.         iv = options.iv || c.splice(0, AES._blocksize * 4),
  769.  
  770.             // Generate key
  771.         k = (
  772.             password.constructor == String ?
  773.             // Derive key from pass-phrase
  774.             C.PBKDF2(password, iv, 32, { asBytes: true }) :
  775.             // else, assume byte array representing cryptographic key
  776.             password
  777.         );
  778.  
  779.             // Decrypt
  780.             AES._init(k);
  781.             mode.decrypt(AES, c, iv);
  782.  
  783.             // Return plaintext
  784.             return (options && options.asBytes) ? c : UTF8.bytesToString(c);
  785.  
  786.         },
  787.  
  788.  
  789.         /**
  790.         * Package private methods and properties
  791.         */
  792.  
  793.         _blocksize: 4,
  794.  
  795.         _encryptblock: function (m, offset) {
  796.  
  797.             // Set input
  798.             for (var row = 0; row < AES._blocksize; row++) {
  799.                 for (var col = 0; col < 4; col++)
  800.                     state[row][col] = m[offset + col * 4 + row];
  801.             }
  802.  
  803.             // Add round key
  804.             for (var row = 0; row < 4; row++) {
  805.                 for (var col = 0; col < 4; col++)
  806.                     state[row][col] ^= keyschedule[col][row];
  807.             }
  808.  
  809.             for (var round = 1; round < nrounds; round++) {
  810.  
  811.                 // Sub bytes
  812.                 for (var row = 0; row < 4; row++) {
  813.                     for (var col = 0; col < 4; col++)
  814.                         state[row][col] = SBOX[state[row][col]];
  815.                 }
  816.  
  817.                 // Shift rows
  818.                 state[1].push(state[1].shift());
  819.                 state[2].push(state[2].shift());
  820.                 state[2].push(state[2].shift());
  821.                 state[3].unshift(state[3].pop());
  822.  
  823.                 // Mix columns
  824.                 for (var col = 0; col < 4; col++) {
  825.  
  826.                     var s0 = state[0][col],
  827.                 s1 = state[1][col],
  828.                 s2 = state[2][col],
  829.                 s3 = state[3][col];
  830.  
  831.                     state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
  832.                     state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
  833.                     state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
  834.                     state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];
  835.  
  836.                 }
  837.  
  838.                 // Add round key
  839.                 for (var row = 0; row < 4; row++) {
  840.                     for (var col = 0; col < 4; col++)
  841.                         state[row][col] ^= keyschedule[round * 4 + col][row];
  842.                 }
  843.  
  844.             }
  845.  
  846.             // Sub bytes
  847.             for (var row = 0; row < 4; row++) {
  848.                 for (var col = 0; col < 4; col++)
  849.                     state[row][col] = SBOX[state[row][col]];
  850.             }
  851.  
  852.             // Shift rows
  853.             state[1].push(state[1].shift());
  854.             state[2].push(state[2].shift());
  855.             state[2].push(state[2].shift());
  856.             state[3].unshift(state[3].pop());
  857.  
  858.             // Add round key
  859.             for (var row = 0; row < 4; row++) {
  860.                 for (var col = 0; col < 4; col++)
  861.                     state[row][col] ^= keyschedule[nrounds * 4 + col][row];
  862.             }
  863.  
  864.             // Set output
  865.             for (var row = 0; row < AES._blocksize; row++) {
  866.                 for (var col = 0; col < 4; col++)
  867.                     m[offset + col * 4 + row] = state[row][col];
  868.             }
  869.  
  870.         },
  871.  
  872.         _decryptblock: function (c, offset) {
  873.  
  874.             // Set input
  875.             for (var row = 0; row < AES._blocksize; row++) {
  876.                 for (var col = 0; col < 4; col++)
  877.                     state[row][col] = c[offset + col * 4 + row];
  878.             }
  879.  
  880.             // Add round key
  881.             for (var row = 0; row < 4; row++) {
  882.                 for (var col = 0; col < 4; col++)
  883.                     state[row][col] ^= keyschedule[nrounds * 4 + col][row];
  884.             }
  885.  
  886.             for (var round = 1; round < nrounds; round++) {
  887.  
  888.                 // Inv shift rows
  889.                 state[1].unshift(state[1].pop());
  890.                 state[2].push(state[2].shift());
  891.                 state[2].push(state[2].shift());
  892.                 state[3].push(state[3].shift());
  893.  
  894.                 // Inv sub bytes
  895.                 for (var row = 0; row < 4; row++) {
  896.                     for (var col = 0; col < 4; col++)
  897.                         state[row][col] = INVSBOX[state[row][col]];
  898.                 }
  899.  
  900.                 // Add round key
  901.                 for (var row = 0; row < 4; row++) {
  902.                     for (var col = 0; col < 4; col++)
  903.                         state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
  904.                 }
  905.  
  906.                 // Inv mix columns
  907.                 for (var col = 0; col < 4; col++) {
  908.  
  909.                     var s0 = state[0][col],
  910.                 s1 = state[1][col],
  911.                 s2 = state[2][col],
  912.                 s3 = state[3][col];
  913.  
  914.                     state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
  915.                     state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
  916.                     state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
  917.                     state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];
  918.  
  919.                 }
  920.  
  921.             }
  922.  
  923.             // Inv shift rows
  924.             state[1].unshift(state[1].pop());
  925.             state[2].push(state[2].shift());
  926.             state[2].push(state[2].shift());
  927.             state[3].push(state[3].shift());
  928.  
  929.             // Inv sub bytes
  930.             for (var row = 0; row < 4; row++) {
  931.                 for (var col = 0; col < 4; col++)
  932.                     state[row][col] = INVSBOX[state[row][col]];
  933.             }
  934.  
  935.             // Add round key
  936.             for (var row = 0; row < 4; row++) {
  937.                 for (var col = 0; col < 4; col++)
  938.                     state[row][col] ^= keyschedule[col][row];
  939.             }
  940.  
  941.             // Set output
  942.             for (var row = 0; row < AES._blocksize; row++) {
  943.                 for (var col = 0; col < 4; col++)
  944.                     c[offset + col * 4 + row] = state[row][col];
  945.             }
  946.  
  947.         },
  948.  
  949.  
  950.         /**
  951.         * Private methods
  952.         */
  953.  
  954.         _init: function (k) {
  955.             keylength = k.length / 4;
  956.             nrounds = keylength + 6;
  957.             AES._keyexpansion(k);
  958.         },
  959.  
  960.         // Generate a key schedule
  961.         _keyexpansion: function (k) {
  962.  
  963.             keyschedule = [];
  964.  
  965.             for (var row = 0; row < keylength; row++) {
  966.                 keyschedule[row] = [
  967.             k[row * 4],
  968.             k[row * 4 + 1],
  969.             k[row * 4 + 2],
  970.             k[row * 4 + 3]
  971.         ];
  972.             }
  973.  
  974.             for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {
  975.  
  976.                 var temp = [
  977.             keyschedule[row - 1][0],
  978.             keyschedule[row - 1][1],
  979.             keyschedule[row - 1][2],
  980.             keyschedule[row - 1][3]
  981.         ];
  982.  
  983.                 if (row % keylength == 0) {
  984.  
  985.                     // Rot word
  986.                     temp.push(temp.shift());
  987.  
  988.                     // Sub word
  989.                     temp[0] = SBOX[temp[0]];
  990.                     temp[1] = SBOX[temp[1]];
  991.                     temp[2] = SBOX[temp[2]];
  992.                     temp[3] = SBOX[temp[3]];
  993.  
  994.                     temp[0] ^= RCON[row / keylength];
  995.  
  996.                 } else if (keylength > 6 && row % keylength == 4) {
  997.  
  998.                     // Sub word
  999.                     temp[0] = SBOX[temp[0]];
  1000.                     temp[1] = SBOX[temp[1]];
  1001.                     temp[2] = SBOX[temp[2]];
  1002.                     temp[3] = SBOX[temp[3]];
  1003.  
  1004.                 }
  1005.  
  1006.                 keyschedule[row] = [
  1007.             keyschedule[row - keylength][0] ^ temp[0],
  1008.             keyschedule[row - keylength][1] ^ temp[1],
  1009.             keyschedule[row - keylength][2] ^ temp[2],
  1010.             keyschedule[row - keylength][3] ^ temp[3]
  1011.         ];
  1012.  
  1013.             }
  1014.  
  1015.         }
  1016.  
  1017.     };
  1018.  
  1019. })();
  1020.     </script>
  1021.     <script type="text/javascript">
  1022. /*!
  1023. * Crypto-JS 2.5.4 BlockModes.js
  1024. * contribution from Simon Greatrix
  1025. */
  1026.  
  1027. (function (C) {
  1028.  
  1029.     // Create pad namespace
  1030.     var C_pad = C.pad = {};
  1031.  
  1032.     // Calculate the number of padding bytes required.
  1033.     function _requiredPadding(cipher, message) {
  1034.         var blockSizeInBytes = cipher._blocksize * 4;
  1035.         var reqd = blockSizeInBytes - message.length % blockSizeInBytes;
  1036.         return reqd;
  1037.     }
  1038.  
  1039.     // Remove padding when the final byte gives the number of padding bytes.
  1040.     var _unpadLength = function (cipher, message, alg, padding) {
  1041.         var pad = message.pop();
  1042.         if (pad == 0) {
  1043.             throw new Error("Invalid zero-length padding specified for " + alg
  1044.             + ". Wrong cipher specification or key used?");
  1045.         }
  1046.         var maxPad = cipher._blocksize * 4;
  1047.         if (pad > maxPad) {
  1048.             throw new Error("Invalid padding length of " + pad
  1049.             + " specified for " + alg
  1050.             + ". Wrong cipher specification or key used?");
  1051.         }
  1052.         for (var i = 1; i < pad; i++) {
  1053.             var b = message.pop();
  1054.             if (padding != undefined && padding != b) {
  1055.                 throw new Error("Invalid padding byte of 0x" + b.toString(16)
  1056.                 + " specified for " + alg
  1057.                 + ". Wrong cipher specification or key used?");
  1058.             }
  1059.         }
  1060.     };
  1061.  
  1062.     // No-operation padding, used for stream ciphers
  1063.     C_pad.NoPadding = {
  1064.         pad: function (cipher, message) { },
  1065.         unpad: function (cipher, message) { }
  1066.     };
  1067.  
  1068.     // Zero Padding.
  1069.     //
  1070.     // If the message is not an exact number of blocks, the final block is
  1071.     // completed with 0x00 bytes. There is no unpadding.
  1072.     C_pad.ZeroPadding = {
  1073.         pad: function (cipher, message) {
  1074.             var blockSizeInBytes = cipher._blocksize * 4;
  1075.             var reqd = message.length % blockSizeInBytes;
  1076.             if (reqd != 0) {
  1077.                 for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) {
  1078.                     message.push(0x00);
  1079.                 }
  1080.             }
  1081.         },
  1082.  
  1083.         unpad: function (cipher, message) {
  1084.             while (message[message.length - 1] == 0) {
  1085.                 message.pop();
  1086.             }
  1087.         }
  1088.     };
  1089.  
  1090.     // ISO/IEC 7816-4 padding.
  1091.     //
  1092.     // Pads the plain text with an 0x80 byte followed by as many 0x00
  1093.     // bytes are required to complete the block.
  1094.     C_pad.iso7816 = {
  1095.         pad: function (cipher, message) {
  1096.             var reqd = _requiredPadding(cipher, message);
  1097.             message.push(0x80);
  1098.             for (; reqd > 1; reqd--) {
  1099.                 message.push(0x00);
  1100.             }
  1101.         },
  1102.  
  1103.         unpad: function (cipher, message) {
  1104.             var padLength;
  1105.             for (padLength = cipher._blocksize * 4; padLength > 0; padLength--) {
  1106.                 var b = message.pop();
  1107.                 if (b == 0x80) return;
  1108.                 if (b != 0x00) {
  1109.                     throw new Error("ISO-7816 padding byte must be 0, not 0x" + b.toString(16) + ". Wrong cipher specification or key used?");
  1110.                 }
  1111.             }
  1112.             throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?");
  1113.         }
  1114.     };
  1115.  
  1116.     // ANSI X.923 padding
  1117.     //
  1118.     // The final block is padded with zeros except for the last byte of the
  1119.     // last block which contains the number of padding bytes.
  1120.     C_pad.ansix923 = {
  1121.         pad: function (cipher, message) {
  1122.             var reqd = _requiredPadding(cipher, message);
  1123.             for (var i = 1; i < reqd; i++) {
  1124.                 message.push(0x00);
  1125.             }
  1126.             message.push(reqd);
  1127.         },
  1128.  
  1129.         unpad: function (cipher, message) {
  1130.             _unpadLength(cipher, message, "ANSI X.923", 0);
  1131.         }
  1132.     };
  1133.  
  1134.     // ISO 10126
  1135.     //
  1136.     // The final block is padded with random bytes except for the last
  1137.     // byte of the last block which contains the number of padding bytes.
  1138.     C_pad.iso10126 = {
  1139.         pad: function (cipher, message) {
  1140.             var reqd = _requiredPadding(cipher, message);
  1141.             for (var i = 1; i < reqd; i++) {
  1142.                 message.push(Math.floor(Math.random() * 256));
  1143.             }
  1144.             message.push(reqd);
  1145.         },
  1146.  
  1147.         unpad: function (cipher, message) {
  1148.             _unpadLength(cipher, message, "ISO 10126", undefined);
  1149.         }
  1150.     };
  1151.  
  1152.     // PKCS7 padding
  1153.     //
  1154.     // PKCS7 is described in RFC 5652. Padding is in whole bytes. The
  1155.     // value of each added byte is the number of bytes that are added,
  1156.     // i.e. N bytes, each of value N are added.
  1157.     C_pad.pkcs7 = {
  1158.         pad: function (cipher, message) {
  1159.             var reqd = _requiredPadding(cipher, message);
  1160.             for (var i = 0; i < reqd; i++) {
  1161.                 message.push(reqd);
  1162.             }
  1163.         },
  1164.  
  1165.         unpad: function (cipher, message) {
  1166.             _unpadLength(cipher, message, "PKCS 7", message[message.length - 1]);
  1167.         }
  1168.     };
  1169.  
  1170.     // Create mode namespace
  1171.     var C_mode = C.mode = {};
  1172.  
  1173.     /**
  1174.     * Mode base "class".
  1175.     */
  1176.     var Mode = C_mode.Mode = function (padding) {
  1177.         if (padding) {
  1178.             this._padding = padding;
  1179.         }
  1180.     };
  1181.  
  1182.     Mode.prototype = {
  1183.         encrypt: function (cipher, m, iv) {
  1184.             this._padding.pad(cipher, m);
  1185.             this._doEncrypt(cipher, m, iv);
  1186.         },
  1187.  
  1188.         decrypt: function (cipher, m, iv) {
  1189.             this._doDecrypt(cipher, m, iv);
  1190.             this._padding.unpad(cipher, m);
  1191.         },
  1192.  
  1193.         // Default padding
  1194.         _padding: C_pad.iso7816
  1195.     };
  1196.  
  1197.  
  1198.     /**
  1199.     * Electronic Code Book mode.
  1200.     *
  1201.     * ECB applies the cipher directly against each block of the input.
  1202.     *
  1203.     * ECB does not require an initialization vector.
  1204.     */
  1205.     var ECB = C_mode.ECB = function () {
  1206.         // Call parent constructor
  1207.         Mode.apply(this, arguments);
  1208.     };
  1209.  
  1210.     // Inherit from Mode
  1211.     var ECB_prototype = ECB.prototype = new Mode;
  1212.  
  1213.     // Concrete steps for Mode template
  1214.     ECB_prototype._doEncrypt = function (cipher, m, iv) {
  1215.         var blockSizeInBytes = cipher._blocksize * 4;
  1216.         // Encrypt each block
  1217.         for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
  1218.             cipher._encryptblock(m, offset);
  1219.         }
  1220.     };
  1221.     ECB_prototype._doDecrypt = function (cipher, c, iv) {
  1222.         var blockSizeInBytes = cipher._blocksize * 4;
  1223.         // Decrypt each block
  1224.         for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
  1225.             cipher._decryptblock(c, offset);
  1226.         }
  1227.     };
  1228.  
  1229.     // ECB never uses an IV
  1230.     ECB_prototype.fixOptions = function (options) {
  1231.         options.iv = [];
  1232.     };
  1233.  
  1234.  
  1235.     /**
  1236.     * Cipher block chaining
  1237.     *
  1238.     * The first block is XORed with the IV. Subsequent blocks are XOR with the
  1239.     * previous cipher output.
  1240.     */
  1241.     var CBC = C_mode.CBC = function () {
  1242.         // Call parent constructor
  1243.         Mode.apply(this, arguments);
  1244.     };
  1245.  
  1246.     // Inherit from Mode
  1247.     var CBC_prototype = CBC.prototype = new Mode;
  1248.  
  1249.     // Concrete steps for Mode template
  1250.     CBC_prototype._doEncrypt = function (cipher, m, iv) {
  1251.         var blockSizeInBytes = cipher._blocksize * 4;
  1252.  
  1253.         // Encrypt each block
  1254.         for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
  1255.             if (offset == 0) {
  1256.                 // XOR first block using IV
  1257.                 for (var i = 0; i < blockSizeInBytes; i++)
  1258.                     m[i] ^= iv[i];
  1259.             } else {
  1260.                 // XOR this block using previous crypted block
  1261.                 for (var i = 0; i < blockSizeInBytes; i++)
  1262.                     m[offset + i] ^= m[offset + i - blockSizeInBytes];
  1263.             }
  1264.             // Encrypt block
  1265.             cipher._encryptblock(m, offset);
  1266.         }
  1267.     };
  1268.     CBC_prototype._doDecrypt = function (cipher, c, iv) {
  1269.         var blockSizeInBytes = cipher._blocksize * 4;
  1270.  
  1271.         // At the start, the previously crypted block is the IV
  1272.         var prevCryptedBlock = iv;
  1273.  
  1274.         // Decrypt each block
  1275.         for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
  1276.             // Save this crypted block
  1277.             var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
  1278.             // Decrypt block
  1279.             cipher._decryptblock(c, offset);
  1280.             // XOR decrypted block using previous crypted block
  1281.             for (var i = 0; i < blockSizeInBytes; i++) {
  1282.                 c[offset + i] ^= prevCryptedBlock[i];
  1283.             }
  1284.             prevCryptedBlock = thisCryptedBlock;
  1285.         }
  1286.     };
  1287.  
  1288.  
  1289.     /**
  1290.     * Cipher feed back
  1291.     *
  1292.     * The cipher output is XORed with the plain text to produce the cipher output,
  1293.     * which is then fed back into the cipher to produce a bit pattern to XOR the
  1294.     * next block with.
  1295.     *
  1296.     * This is a stream cipher mode and does not require padding.
  1297.     */
  1298.     var CFB = C_mode.CFB = function () {
  1299.         // Call parent constructor
  1300.         Mode.apply(this, arguments);
  1301.     };
  1302.  
  1303.     // Inherit from Mode
  1304.     var CFB_prototype = CFB.prototype = new Mode;
  1305.  
  1306.     // Override padding
  1307.     CFB_prototype._padding = C_pad.NoPadding;
  1308.  
  1309.     // Concrete steps for Mode template
  1310.     CFB_prototype._doEncrypt = function (cipher, m, iv) {
  1311.         var blockSizeInBytes = cipher._blocksize * 4,
  1312.    keystream = iv.slice(0);
  1313.  
  1314.         // Encrypt each byte
  1315.         for (var i = 0; i < m.length; i++) {
  1316.  
  1317.             var j = i % blockSizeInBytes;
  1318.             if (j == 0) cipher._encryptblock(keystream, 0);
  1319.  
  1320.             m[i] ^= keystream[j];
  1321.             keystream[j] = m[i];
  1322.         }
  1323.     };
  1324.     CFB_prototype._doDecrypt = function (cipher, c, iv) {
  1325.         var blockSizeInBytes = cipher._blocksize * 4,
  1326.             keystream = iv.slice(0);
  1327.  
  1328.         // Encrypt each byte
  1329.         for (var i = 0; i < c.length; i++) {
  1330.  
  1331.             var j = i % blockSizeInBytes;
  1332.             if (j == 0) cipher._encryptblock(keystream, 0);
  1333.  
  1334.             var b = c[i];
  1335.             c[i] ^= keystream[j];
  1336.             keystream[j] = b;
  1337.         }
  1338.     };
  1339.  
  1340.  
  1341.     /**
  1342.     * Output feed back
  1343.     *
  1344.     * The cipher repeatedly encrypts its own output. The output is XORed with the
  1345.     * plain text to produce the cipher text.
  1346.     *
  1347.     * This is a stream cipher mode and does not require padding.
  1348.     */
  1349.     var OFB = C_mode.OFB = function () {
  1350.         // Call parent constructor
  1351.         Mode.apply(this, arguments);
  1352.     };
  1353.  
  1354.     // Inherit from Mode
  1355.     var OFB_prototype = OFB.prototype = new Mode;
  1356.  
  1357.     // Override padding
  1358.     OFB_prototype._padding = C_pad.NoPadding;
  1359.  
  1360.     // Concrete steps for Mode template
  1361.     OFB_prototype._doEncrypt = function (cipher, m, iv) {
  1362.  
  1363.         var blockSizeInBytes = cipher._blocksize * 4,
  1364.             keystream = iv.slice(0);
  1365.  
  1366.         // Encrypt each byte
  1367.         for (var i = 0; i < m.length; i++) {
  1368.  
  1369.             // Generate keystream
  1370.             if (i % blockSizeInBytes == 0)
  1371.                 cipher._encryptblock(keystream, 0);
  1372.  
  1373.             // Encrypt byte
  1374.             m[i] ^= keystream[i % blockSizeInBytes];
  1375.  
  1376.         }
  1377.     };
  1378.     OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
  1379.  
  1380.     /**
  1381.     * Counter
  1382.     * @author Gergely Risko
  1383.     *
  1384.     * After every block the last 4 bytes of the IV is increased by one
  1385.     * with carry and that IV is used for the next block.
  1386.     *
  1387.     * This is a stream cipher mode and does not require padding.
  1388.     */
  1389.     var CTR = C_mode.CTR = function () {
  1390.         // Call parent constructor
  1391.         Mode.apply(this, arguments);
  1392.     };
  1393.  
  1394.     // Inherit from Mode
  1395.     var CTR_prototype = CTR.prototype = new Mode;
  1396.  
  1397.     // Override padding
  1398.     CTR_prototype._padding = C_pad.NoPadding;
  1399.  
  1400.     CTR_prototype._doEncrypt = function (cipher, m, iv) {
  1401.         var blockSizeInBytes = cipher._blocksize * 4;
  1402.         var counter = iv.slice(0);
  1403.  
  1404.         for (var i = 0; i < m.length; ) {
  1405.             // do not lose iv
  1406.             var keystream = counter.slice(0);
  1407.  
  1408.             // Generate keystream for next block
  1409.             cipher._encryptblock(keystream, 0);
  1410.  
  1411.             // XOR keystream with block
  1412.             for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
  1413.                 m[i] ^= keystream[j];
  1414.             }
  1415.  
  1416.             // Increase counter
  1417.             if (++(counter[blockSizeInBytes - 1]) == 256) {
  1418.                 counter[blockSizeInBytes - 1] = 0;
  1419.                 if (++(counter[blockSizeInBytes - 2]) == 256) {
  1420.                     counter[blockSizeInBytes - 2] = 0;
  1421.                     if (++(counter[blockSizeInBytes - 3]) == 256) {
  1422.                         counter[blockSizeInBytes - 3] = 0;
  1423.                         ++(counter[blockSizeInBytes - 4]);
  1424.                     }
  1425.                 }
  1426.             }
  1427.         }
  1428.     };
  1429.     CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
  1430.  
  1431. })(Crypto);
  1432.     </script>
  1433.     <script type="text/javascript">
  1434. /*!
  1435. * Crypto-JS v2.0.0  RIPEMD-160
  1436. * http://code.google.com/p/crypto-js/
  1437. * Copyright (c) 2009, Jeff Mott. All rights reserved.
  1438. * http://code.google.com/p/crypto-js/wiki/License
  1439. *
  1440. * A JavaScript implementation of the RIPEMD-160 Algorithm
  1441. * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
  1442. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
  1443. * Distributed under the BSD License
  1444. * See http://pajhome.org.uk/crypt/md5 for details.
  1445. * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
  1446. * Ported to Crypto-JS by Stefan Thomas.
  1447. */
  1448.  
  1449. (function () {
  1450.     // Shortcuts
  1451.     var C = Crypto,
  1452.     util = C.util,
  1453.     charenc = C.charenc,
  1454.     UTF8 = charenc.UTF8,
  1455.     Binary = charenc.Binary;
  1456.  
  1457.     // Convert a byte array to little-endian 32-bit words
  1458.     util.bytesToLWords = function (bytes) {
  1459.  
  1460.         var output = Array(bytes.length >> 2);
  1461.         for (var i = 0; i < output.length; i++)
  1462.             output[i] = 0;
  1463.         for (var i = 0; i < bytes.length * 8; i += 8)
  1464.             output[i >> 5] |= (bytes[i / 8] & 0xFF) << (i % 32);
  1465.         return output;
  1466.     };
  1467.  
  1468.     // Convert little-endian 32-bit words to a byte array
  1469.     util.lWordsToBytes = function (words) {
  1470.         var output = [];
  1471.         for (var i = 0; i < words.length * 32; i += 8)
  1472.             output.push((words[i >> 5] >>> (i % 32)) & 0xff);
  1473.         return output;
  1474.     };
  1475.  
  1476.     // Public API
  1477.     var RIPEMD160 = C.RIPEMD160 = function (message, options) {
  1478.         var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message));
  1479.         return options && options.asBytes ? digestbytes :
  1480.             options && options.asString ? Binary.bytesToString(digestbytes) :
  1481.             util.bytesToHex(digestbytes);
  1482.     };
  1483.  
  1484.     // The core
  1485.     RIPEMD160._rmd160 = function (message) {
  1486.         // Convert to byte array
  1487.         if (message.constructor == String) message = UTF8.stringToBytes(message);
  1488.  
  1489.         var x = util.bytesToLWords(message),
  1490.             len = message.length * 8;
  1491.  
  1492.         /* append padding */
  1493.         x[len >> 5] |= 0x80 << (len % 32);
  1494.         x[(((len + 64) >>> 9) << 4) + 14] = len;
  1495.  
  1496.         var h0 = 0x67452301;
  1497.         var h1 = 0xefcdab89;
  1498.         var h2 = 0x98badcfe;
  1499.         var h3 = 0x10325476;
  1500.         var h4 = 0xc3d2e1f0;
  1501.  
  1502.         for (var i = 0; i < x.length; i += 16) {
  1503.             var T;
  1504.             var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
  1505.             var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
  1506.             for (var j = 0; j <= 79; ++j) {
  1507.                 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
  1508.                 T = safe_add(T, x[i + rmd160_r1[j]]);
  1509.                 T = safe_add(T, rmd160_K1(j));
  1510.                 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
  1511.                 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
  1512.                 T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
  1513.                 T = safe_add(T, x[i + rmd160_r2[j]]);
  1514.                 T = safe_add(T, rmd160_K2(j));
  1515.                 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
  1516.                 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
  1517.             }
  1518.             T = safe_add(h1, safe_add(C1, D2));
  1519.             h1 = safe_add(h2, safe_add(D1, E2));
  1520.             h2 = safe_add(h3, safe_add(E1, A2));
  1521.             h3 = safe_add(h4, safe_add(A1, B2));
  1522.             h4 = safe_add(h0, safe_add(B1, C2));
  1523.             h0 = T;
  1524.         }
  1525.         return [h0, h1, h2, h3, h4];
  1526.     }
  1527.  
  1528.     function rmd160_f(j, x, y, z) {
  1529.         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
  1530.             (16 <= j && j <= 31) ? (x & y) | (~x & z) :
  1531.             (32 <= j && j <= 47) ? (x | ~y) ^ z :
  1532.             (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
  1533.             (64 <= j && j <= 79) ? x ^ (y | ~z) :
  1534.             "rmd160_f: j out of range";
  1535.     }
  1536.     function rmd160_K1(j) {
  1537.         return (0 <= j && j <= 15) ? 0x00000000 :
  1538.             (16 <= j && j <= 31) ? 0x5a827999 :
  1539.             (32 <= j && j <= 47) ? 0x6ed9eba1 :
  1540.             (48 <= j && j <= 63) ? 0x8f1bbcdc :
  1541.             (64 <= j && j <= 79) ? 0xa953fd4e :
  1542.             "rmd160_K1: j out of range";
  1543.     }
  1544.     function rmd160_K2(j) {
  1545.         return (0 <= j && j <= 15) ? 0x50a28be6 :
  1546.             (16 <= j && j <= 31) ? 0x5c4dd124 :
  1547.             (32 <= j && j <= 47) ? 0x6d703ef3 :
  1548.             (48 <= j && j <= 63) ? 0x7a6d76e9 :
  1549.             (64 <= j && j <= 79) ? 0x00000000 :
  1550.             "rmd160_K2: j out of range";
  1551.     }
  1552.     var rmd160_r1 = [
  1553.         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  1554.         7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
  1555.         3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
  1556.         1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
  1557.         4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
  1558.     ];
  1559.     var rmd160_r2 = [
  1560.         5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
  1561.         6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
  1562.         15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
  1563.         8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
  1564.         12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
  1565.     ];
  1566.     var rmd160_s1 = [
  1567.         11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
  1568.         7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
  1569.         11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
  1570.         11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
  1571.         9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
  1572.     ];
  1573.     var rmd160_s2 = [
  1574.         8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
  1575.         9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
  1576.         9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
  1577.         15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
  1578.         8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
  1579.     ];
  1580.  
  1581.     /*
  1582.     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
  1583.     * to work around bugs in some JS interpreters.
  1584.     */
  1585.     function safe_add(x, y) {
  1586.         var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  1587.         var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  1588.         return (msw << 16) | (lsw & 0xFFFF);
  1589.     }
  1590.  
  1591.     /*
  1592.     * Bitwise rotate a 32-bit number to the left.
  1593.     */
  1594.     function bit_rol(num, cnt) {
  1595.         return (num << cnt) | (num >>> (32 - cnt));
  1596.     }
  1597. })();
  1598.     </script>
  1599.     <script type="text/javascript">
  1600. /*!
  1601. * Random number generator with ArcFour PRNG
  1602. *
  1603. * NOTE: For best results, put code like
  1604. * <body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();'>
  1605. * in your main HTML document.
  1606. *
  1607. * Copyright Tom Wu, bitaddress.org  BSD License.
  1608. * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
  1609. */
  1610. (function () {
  1611.  
  1612.     // Constructor function of Global SecureRandom object
  1613.     var sr = window.SecureRandom = function () { };
  1614.  
  1615.     // Properties
  1616.     sr.state;
  1617.     sr.pool;
  1618.     sr.pptr;
  1619.     sr.poolCopyOnInit;
  1620.  
  1621.     // Pool size must be a multiple of 4 and greater than 32.
  1622.     // An array of bytes the size of the pool will be passed to init()
  1623.     sr.poolSize = 256;
  1624.  
  1625.     // --- object methods ---
  1626.  
  1627.     // public method
  1628.     // ba: byte array
  1629.     sr.prototype.nextBytes = function (ba) {
  1630.         var i;
  1631.         if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
  1632.             try {
  1633.                 var rvBytes = new Uint8Array(ba.length);
  1634.                 window.crypto.getRandomValues(rvBytes);
  1635.                 for (i = 0; i < ba.length; ++i)
  1636.                     ba[i] = sr.getByte() ^ rvBytes[i];
  1637.                 return;
  1638.             } catch (e) {
  1639.                 alert(e);
  1640.             }
  1641.         }
  1642.         for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte();
  1643.     };
  1644.  
  1645.  
  1646.     // --- static methods ---
  1647.  
  1648.     // Mix in the current time (w/milliseconds) into the pool
  1649.     // NOTE: this method should be called from body click/keypress event handlers to increase entropy
  1650.     sr.seedTime = function () {
  1651.         sr.seedInt(new Date().getTime());
  1652.     }
  1653.  
  1654.     sr.getByte = function () {
  1655.         if (sr.state == null) {
  1656.             sr.seedTime();
  1657.             sr.state = sr.ArcFour(); // Plug in your RNG constructor here
  1658.             sr.state.init(sr.pool);
  1659.             sr.poolCopyOnInit = [];
  1660.             for (sr.pptr = 0; sr.pptr < sr.pool.length; ++sr.pptr)
  1661.                 sr.poolCopyOnInit[sr.pptr] = sr.pool[sr.pptr];
  1662.             sr.pptr = 0;
  1663.         }
  1664.         // TODO: allow reseeding after first request
  1665.         return sr.state.next();
  1666.     }
  1667.  
  1668.     // Mix in a 32-bit integer into the pool
  1669.     sr.seedInt = function (x) {
  1670.         sr.seedInt8(x);
  1671.         sr.seedInt8((x >> 8));
  1672.         sr.seedInt8((x >> 16));
  1673.         sr.seedInt8((x >> 24));
  1674.     }
  1675.  
  1676.     // Mix in a 16-bit integer into the pool
  1677.     sr.seedInt16 = function (x) {
  1678.         sr.seedInt8(x);
  1679.         sr.seedInt8((x >> 8));
  1680.     }
  1681.  
  1682.     // Mix in a 8-bit integer into the pool
  1683.     sr.seedInt8 = function (x) {
  1684.         sr.pool[sr.pptr++] ^= x & 255;
  1685.         if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize;
  1686.     }
  1687.  
  1688.     // Arcfour is a PRNG
  1689.     sr.ArcFour = function () {
  1690.         function Arcfour() {
  1691.             this.i = 0;
  1692.             this.j = 0;
  1693.             this.S = new Array();
  1694.         }
  1695.  
  1696.         // Initialize arcfour context from key, an array of ints, each from [0..255]
  1697.         function ARC4init(key) {
  1698.             var i, j, t;
  1699.             for (i = 0; i < 256; ++i)
  1700.                 this.S[i] = i;
  1701.             j = 0;
  1702.             for (i = 0; i < 256; ++i) {
  1703.                 j = (j + this.S[i] + key[i % key.length]) & 255;
  1704.                 t = this.S[i];
  1705.                 this.S[i] = this.S[j];
  1706.                 this.S[j] = t;
  1707.             }
  1708.             this.i = 0;
  1709.             this.j = 0;
  1710.         }
  1711.  
  1712.         function ARC4next() {
  1713.             var t;
  1714.             this.i = (this.i + 1) & 255;
  1715.             this.j = (this.j + this.S[this.i]) & 255;
  1716.             t = this.S[this.i];
  1717.             this.S[this.i] = this.S[this.j];
  1718.             this.S[this.j] = t;
  1719.             return this.S[(t + this.S[this.i]) & 255];
  1720.         }
  1721.  
  1722.         Arcfour.prototype.init = ARC4init;
  1723.         Arcfour.prototype.next = ARC4next;
  1724.  
  1725.         return new Arcfour();
  1726.     };
  1727.  
  1728.  
  1729.     // Initialize the pool with junk if needed.
  1730.     if (sr.pool == null) {
  1731.         sr.pool = new Array();
  1732.         sr.pptr = 0;
  1733.         var t;
  1734.         if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
  1735.             try {
  1736.                 // Use webcrypto if available
  1737.                 var ua = new Uint8Array(sr.poolSize);
  1738.                 window.crypto.getRandomValues(ua);
  1739.                 for (t = 0; t < sr.poolSize; ++t)
  1740.                     sr.pool[sr.pptr++] = ua[t];
  1741.             } catch (e) { alert(e); }
  1742.         }
  1743.         while (sr.pptr < sr.poolSize) {  // extract some randomness from Math.random()
  1744.             t = Math.floor(65536 * Math.random());
  1745.             sr.pool[sr.pptr++] = t >>> 8;
  1746.             sr.pool[sr.pptr++] = t & 255;
  1747.         }
  1748.         sr.pptr = Math.floor(sr.poolSize * Math.random());
  1749.         sr.seedTime();
  1750.         // entropy
  1751.         var entropyStr = "";
  1752.         // screen size and color depth: ~4.8 to ~5.4 bits
  1753.         entropyStr += (window.screen.height * window.screen.width * window.screen.colorDepth);
  1754.         entropyStr += (window.screen.availHeight * window.screen.availWidth * window.screen.pixelDepth);
  1755.         // time zone offset: ~4 bits
  1756.         var dateObj = new Date();
  1757.         var timeZoneOffset = dateObj.getTimezoneOffset();
  1758.         entropyStr += timeZoneOffset;
  1759.         // user agent: ~8.3 to ~11.6 bits
  1760.         entropyStr += navigator.userAgent;
  1761.         // browser plugin details: ~16.2 to ~21.8 bits
  1762.         var pluginsStr = "";
  1763.         for (var i = 0; i < navigator.plugins.length; i++) {
  1764.             pluginsStr += navigator.plugins[i].name + " " + navigator.plugins[i].filename + " " + navigator.plugins[i].description + " " + navigator.plugins[i].version + ", ";
  1765.         }
  1766.         var mimeTypesStr = "";
  1767.         for (var i = 0; i < navigator.mimeTypes.length; i++) {
  1768.             mimeTypesStr += navigator.mimeTypes[i].description + " " + navigator.mimeTypes[i].type + " " + navigator.mimeTypes[i].suffixes + ", ";
  1769.         }
  1770.         entropyStr += pluginsStr + mimeTypesStr;
  1771.         // cookies and storage: 1 bit
  1772.         entropyStr += navigator.cookieEnabled + typeof (sessionStorage) + typeof (localStorage);
  1773.         // language: ~7 bit
  1774.         entropyStr += navigator.language;
  1775.         // history: ~2 bit
  1776.         entropyStr += window.history.length;
  1777.         // location
  1778.         entropyStr += window.location;
  1779.  
  1780.         var entropyBytes = Crypto.SHA256(entropyStr, { asBytes: true });
  1781.         for (var i = 0 ; i < entropyBytes.length ; i++) {
  1782.             sr.seedInt8(entropyBytes[i]);
  1783.         }
  1784.     }
  1785. })();
  1786.     </script>
  1787.     <script type="text/javascript">
  1788. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/faa10f0f6a1fff0b9a99fffb9bc30cee33b17212/src/ecdsa.js
  1789. /*!
  1790. * Basic Javascript Elliptic Curve implementation
  1791. * Ported loosely from BouncyCastle's Java EC code
  1792. * Only Fp curves implemented for now
  1793. *
  1794. * Copyright Tom Wu, bitaddress.org  BSD License.
  1795. * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
  1796. */
  1797. (function () {
  1798.  
  1799.     // Constructor function of Global EllipticCurve object
  1800.     var ec = window.EllipticCurve = function () { };
  1801.  
  1802.  
  1803.     // ----------------
  1804.     // ECFieldElementFp constructor
  1805.     // q instanceof BigInteger
  1806.     // x instanceof BigInteger
  1807.     ec.FieldElementFp = function (q, x) {
  1808.         this.x = x;
  1809.         // TODO if(x.compareTo(q) >= 0) error
  1810.         this.q = q;
  1811.     };
  1812.  
  1813.     ec.FieldElementFp.prototype.equals = function (other) {
  1814.         if (other == this) return true;
  1815.         return (this.q.equals(other.q) && this.x.equals(other.x));
  1816.     };
  1817.  
  1818.     ec.FieldElementFp.prototype.toBigInteger = function () {
  1819.         return this.x;
  1820.     };
  1821.  
  1822.     ec.FieldElementFp.prototype.negate = function () {
  1823.         return new ec.FieldElementFp(this.q, this.x.negate().mod(this.q));
  1824.     };
  1825.  
  1826.     ec.FieldElementFp.prototype.add = function (b) {
  1827.         return new ec.FieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
  1828.     };
  1829.  
  1830.     ec.FieldElementFp.prototype.subtract = function (b) {
  1831.         return new ec.FieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
  1832.     };
  1833.  
  1834.     ec.FieldElementFp.prototype.multiply = function (b) {
  1835.         return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
  1836.     };
  1837.  
  1838.     ec.FieldElementFp.prototype.square = function () {
  1839.         return new ec.FieldElementFp(this.q, this.x.square().mod(this.q));
  1840.     };
  1841.  
  1842.     ec.FieldElementFp.prototype.divide = function (b) {
  1843.         return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
  1844.     };
  1845.  
  1846.     ec.FieldElementFp.prototype.getByteLength = function () {
  1847.         return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
  1848.     };
  1849.  
  1850.     // D.1.4 91
  1851.     /**
  1852.     * return a sqrt root - the routine verifies that the calculation
  1853.     * returns the right value - if none exists it returns null.
  1854.     *
  1855.     * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
  1856.     * Ported to JavaScript by bitaddress.org
  1857.     */
  1858.     ec.FieldElementFp.prototype.sqrt = function () {
  1859.         if (!this.q.testBit(0)) throw new Error("even value of q");
  1860.  
  1861.         // p mod 4 == 3
  1862.         if (this.q.testBit(1)) {
  1863.             // z = g^(u+1) + p, p = 4u + 3
  1864.             var z = new ec.FieldElementFp(this.q, this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE), this.q));
  1865.             return z.square().equals(this) ? z : null;
  1866.         }
  1867.  
  1868.         // p mod 4 == 1
  1869.         var qMinusOne = this.q.subtract(BigInteger.ONE);
  1870.         var legendreExponent = qMinusOne.shiftRight(1);
  1871.         if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE))) return null;
  1872.         var u = qMinusOne.shiftRight(2);
  1873.         var k = u.shiftLeft(1).add(BigInteger.ONE);
  1874.         var Q = this.x;
  1875.         var fourQ = Q.shiftLeft(2).mod(this.q);
  1876.         var U, V;
  1877.  
  1878.         do {
  1879.             var rand = new SecureRandom();
  1880.             var P;
  1881.             do {
  1882.                 P = new BigInteger(this.q.bitLength(), rand);
  1883.             }
  1884.             while (P.compareTo(this.q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
  1885.  
  1886.             var result = ec.FieldElementFp.fastLucasSequence(this.q, P, Q, k);
  1887.  
  1888.             U = result[0];
  1889.             V = result[1];
  1890.             if (V.multiply(V).mod(this.q).equals(fourQ)) {
  1891.                 // Integer division by 2, mod q
  1892.                 if (V.testBit(0)) {
  1893.                     V = V.add(this.q);
  1894.                 }
  1895.                 V = V.shiftRight(1);
  1896.                 return new ec.FieldElementFp(this.q, V);
  1897.             }
  1898.         }
  1899.         while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
  1900.  
  1901.         return null;
  1902.     };
  1903.  
  1904.     /*
  1905.     * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
  1906.     * Ported to JavaScript by bitaddress.org
  1907.     */
  1908.     ec.FieldElementFp.fastLucasSequence = function (p, P, Q, k) {
  1909.         // TODO Research and apply "common-multiplicand multiplication here"
  1910.  
  1911.         var n = k.bitLength();
  1912.         var s = k.getLowestSetBit();
  1913.         var Uh = BigInteger.ONE;
  1914.         var Vl = BigInteger.TWO;
  1915.         var Vh = P;
  1916.         var Ql = BigInteger.ONE;
  1917.         var Qh = BigInteger.ONE;
  1918.  
  1919.         for (var j = n - 1; j >= s + 1; --j) {
  1920.             Ql = Ql.multiply(Qh).mod(p);
  1921.             if (k.testBit(j)) {
  1922.                 Qh = Ql.multiply(Q).mod(p);
  1923.                 Uh = Uh.multiply(Vh).mod(p);
  1924.                 Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
  1925.                 Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
  1926.             }
  1927.             else {
  1928.                 Qh = Ql;
  1929.                 Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
  1930.                 Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
  1931.                 Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
  1932.             }
  1933.         }
  1934.  
  1935.         Ql = Ql.multiply(Qh).mod(p);
  1936.         Qh = Ql.multiply(Q).mod(p);
  1937.         Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
  1938.         Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
  1939.         Ql = Ql.multiply(Qh).mod(p);
  1940.  
  1941.         for (var j = 1; j <= s; ++j) {
  1942.             Uh = Uh.multiply(Vl).mod(p);
  1943.             Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
  1944.             Ql = Ql.multiply(Ql).mod(p);
  1945.         }
  1946.  
  1947.         return [Uh, Vl];
  1948.     };
  1949.  
  1950.     // ----------------
  1951.     // ECPointFp constructor
  1952.     ec.PointFp = function (curve, x, y, z, compressed) {
  1953.         this.curve = curve;
  1954.         this.x = x;
  1955.         this.y = y;
  1956.         // Projective coordinates: either zinv == null or z * zinv == 1
  1957.         // z and zinv are just BigIntegers, not fieldElements
  1958.         if (z == null) {
  1959.             this.z = BigInteger.ONE;
  1960.         }
  1961.         else {
  1962.             this.z = z;
  1963.         }
  1964.         this.zinv = null;
  1965.         // compression flag
  1966.         this.compressed = !!compressed;
  1967.     };
  1968.  
  1969.     ec.PointFp.prototype.getX = function () {
  1970.         if (this.zinv == null) {
  1971.             this.zinv = this.z.modInverse(this.curve.q);
  1972.         }
  1973.         var r = this.x.toBigInteger().multiply(this.zinv);
  1974.         this.curve.reduce(r);
  1975.         return this.curve.fromBigInteger(r);
  1976.     };
  1977.  
  1978.     ec.PointFp.prototype.getY = function () {
  1979.         if (this.zinv == null) {
  1980.             this.zinv = this.z.modInverse(this.curve.q);
  1981.         }
  1982.         var r = this.y.toBigInteger().multiply(this.zinv);
  1983.         this.curve.reduce(r);
  1984.         return this.curve.fromBigInteger(r);
  1985.     };
  1986.  
  1987.     ec.PointFp.prototype.equals = function (other) {
  1988.         if (other == this) return true;
  1989.         if (this.isInfinity()) return other.isInfinity();
  1990.         if (other.isInfinity()) return this.isInfinity();
  1991.         var u, v;
  1992.         // u = Y2 * Z1 - Y1 * Z2
  1993.         u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
  1994.         if (!u.equals(BigInteger.ZERO)) return false;
  1995.         // v = X2 * Z1 - X1 * Z2
  1996.         v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
  1997.         return v.equals(BigInteger.ZERO);
  1998.     };
  1999.  
  2000.     ec.PointFp.prototype.isInfinity = function () {
  2001.         if ((this.x == null) && (this.y == null)) return true;
  2002.         return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
  2003.     };
  2004.  
  2005.     ec.PointFp.prototype.negate = function () {
  2006.         return new ec.PointFp(this.curve, this.x, this.y.negate(), this.z);
  2007.     };
  2008.  
  2009.     ec.PointFp.prototype.add = function (b) {
  2010.         if (this.isInfinity()) return b;
  2011.         if (b.isInfinity()) return this;
  2012.  
  2013.         // u = Y2 * Z1 - Y1 * Z2
  2014.         var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
  2015.         // v = X2 * Z1 - X1 * Z2
  2016.         var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
  2017.  
  2018.  
  2019.         if (BigInteger.ZERO.equals(v)) {
  2020.             if (BigInteger.ZERO.equals(u)) {
  2021.                 return this.twice(); // this == b, so double
  2022.             }
  2023.             return this.curve.getInfinity(); // this = -b, so infinity
  2024.         }
  2025.  
  2026.         var THREE = new BigInteger("3");
  2027.         var x1 = this.x.toBigInteger();
  2028.         var y1 = this.y.toBigInteger();
  2029.         var x2 = b.x.toBigInteger();
  2030.         var y2 = b.y.toBigInteger();
  2031.  
  2032.         var v2 = v.square();
  2033.         var v3 = v2.multiply(v);
  2034.         var x1v2 = x1.multiply(v2);
  2035.         var zu2 = u.square().multiply(this.z);
  2036.  
  2037.         // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
  2038.         var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
  2039.         // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
  2040.         var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
  2041.         // z3 = v^3 * z1 * z2
  2042.         var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
  2043.  
  2044.         return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
  2045.     };
  2046.  
  2047.     ec.PointFp.prototype.twice = function () {
  2048.         if (this.isInfinity()) return this;
  2049.         if (this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
  2050.  
  2051.         // TODO: optimized handling of constants
  2052.         var THREE = new BigInteger("3");
  2053.         var x1 = this.x.toBigInteger();
  2054.         var y1 = this.y.toBigInteger();
  2055.  
  2056.         var y1z1 = y1.multiply(this.z);
  2057.         var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
  2058.         var a = this.curve.a.toBigInteger();
  2059.  
  2060.         // w = 3 * x1^2 + a * z1^2
  2061.         var w = x1.square().multiply(THREE);
  2062.         if (!BigInteger.ZERO.equals(a)) {
  2063.             w = w.add(this.z.square().multiply(a));
  2064.         }
  2065.         w = w.mod(this.curve.q);
  2066.         //this.curve.reduce(w);
  2067.         // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
  2068.         var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
  2069.         // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
  2070.         var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
  2071.         // z3 = 8 * (y1 * z1)^3
  2072.         var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
  2073.  
  2074.         return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
  2075.     };
  2076.  
  2077.     // Simple NAF (Non-Adjacent Form) multiplication algorithm
  2078.     // TODO: modularize the multiplication algorithm
  2079.     ec.PointFp.prototype.multiply = function (k) {
  2080.         if (this.isInfinity()) return this;
  2081.         if (k.signum() == 0) return this.curve.getInfinity();
  2082.  
  2083.         var e = k;
  2084.         var h = e.multiply(new BigInteger("3"));
  2085.  
  2086.         var neg = this.negate();
  2087.         var R = this;
  2088.  
  2089.         var i;
  2090.         for (i = h.bitLength() - 2; i > 0; --i) {
  2091.             R = R.twice();
  2092.  
  2093.             var hBit = h.testBit(i);
  2094.             var eBit = e.testBit(i);
  2095.  
  2096.             if (hBit != eBit) {
  2097.                 R = R.add(hBit ? this : neg);
  2098.             }
  2099.         }
  2100.  
  2101.         return R;
  2102.     };
  2103.  
  2104.     // Compute this*j + x*k (simultaneous multiplication)
  2105.     ec.PointFp.prototype.multiplyTwo = function (j, x, k) {
  2106.         var i;
  2107.         if (j.bitLength() > k.bitLength())
  2108.             i = j.bitLength() - 1;
  2109.         else
  2110.             i = k.bitLength() - 1;
  2111.  
  2112.         var R = this.curve.getInfinity();
  2113.         var both = this.add(x);
  2114.         while (i >= 0) {
  2115.             R = R.twice();
  2116.             if (j.testBit(i)) {
  2117.                 if (k.testBit(i)) {
  2118.                     R = R.add(both);
  2119.                 }
  2120.                 else {
  2121.                     R = R.add(this);
  2122.                 }
  2123.             }
  2124.             else {
  2125.                 if (k.testBit(i)) {
  2126.                     R = R.add(x);
  2127.                 }
  2128.             }
  2129.             --i;
  2130.         }
  2131.  
  2132.         return R;
  2133.     };
  2134.  
  2135.     // patched by bitaddress.org and Casascius for use with Bitcoin.ECKey
  2136.     // patched by coretechs to support compressed public keys
  2137.     ec.PointFp.prototype.getEncoded = function (compressed) {
  2138.         var x = this.getX().toBigInteger();
  2139.         var y = this.getY().toBigInteger();
  2140.         var len = 32; // integerToBytes will zero pad if integer is less than 32 bytes. 32 bytes length is required by the Bitcoin protocol.
  2141.         var enc = ec.integerToBytes(x, len);
  2142.  
  2143.         // when compressed prepend byte depending if y point is even or odd
  2144.         if (compressed) {
  2145.             if (y.isEven()) {
  2146.                 enc.unshift(0x02);
  2147.             }
  2148.             else {
  2149.                 enc.unshift(0x03);
  2150.             }
  2151.         }
  2152.         else {
  2153.             enc.unshift(0x04);
  2154.             enc = enc.concat(ec.integerToBytes(y, len)); // uncompressed public key appends the bytes of the y point
  2155.         }
  2156.         return enc;
  2157.     };
  2158.  
  2159.     ec.PointFp.decodeFrom = function (curve, enc) {
  2160.         var type = enc[0];
  2161.         var dataLen = enc.length - 1;
  2162.  
  2163.         // Extract x and y as byte arrays
  2164.         var xBa = enc.slice(1, 1 + dataLen / 2);
  2165.         var yBa = enc.slice(1 + dataLen / 2, 1 + dataLen);
  2166.  
  2167.         // Prepend zero byte to prevent interpretation as negative integer
  2168.         xBa.unshift(0);
  2169.         yBa.unshift(0);
  2170.  
  2171.         // Convert to BigIntegers
  2172.         var x = new BigInteger(xBa);
  2173.         var y = new BigInteger(yBa);
  2174.  
  2175.         // Return point
  2176.         return new ec.PointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
  2177.     };
  2178.  
  2179.     ec.PointFp.prototype.add2D = function (b) {
  2180.         if (this.isInfinity()) return b;
  2181.         if (b.isInfinity()) return this;
  2182.  
  2183.         if (this.x.equals(b.x)) {
  2184.             if (this.y.equals(b.y)) {
  2185.                 // this = b, i.e. this must be doubled
  2186.                 return this.twice();
  2187.             }
  2188.             // this = -b, i.e. the result is the point at infinity
  2189.             return this.curve.getInfinity();
  2190.         }
  2191.  
  2192.         var x_x = b.x.subtract(this.x);
  2193.         var y_y = b.y.subtract(this.y);
  2194.         var gamma = y_y.divide(x_x);
  2195.  
  2196.         var x3 = gamma.square().subtract(this.x).subtract(b.x);
  2197.         var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
  2198.  
  2199.         return new ec.PointFp(this.curve, x3, y3);
  2200.     };
  2201.  
  2202.     ec.PointFp.prototype.twice2D = function () {
  2203.         if (this.isInfinity()) return this;
  2204.         if (this.y.toBigInteger().signum() == 0) {
  2205.             // if y1 == 0, then (x1, y1) == (x1, -y1)
  2206.             // and hence this = -this and thus 2(x1, y1) == infinity
  2207.             return this.curve.getInfinity();
  2208.         }
  2209.  
  2210.         var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
  2211.         var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
  2212.         var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
  2213.  
  2214.         var x3 = gamma.square().subtract(this.x.multiply(TWO));
  2215.         var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
  2216.  
  2217.         return new ec.PointFp(this.curve, x3, y3);
  2218.     };
  2219.  
  2220.     ec.PointFp.prototype.multiply2D = function (k) {
  2221.         if (this.isInfinity()) return this;
  2222.         if (k.signum() == 0) return this.curve.getInfinity();
  2223.  
  2224.         var e = k;
  2225.         var h = e.multiply(new BigInteger("3"));
  2226.  
  2227.         var neg = this.negate();
  2228.         var R = this;
  2229.  
  2230.         var i;
  2231.         for (i = h.bitLength() - 2; i > 0; --i) {
  2232.             R = R.twice();
  2233.  
  2234.             var hBit = h.testBit(i);
  2235.             var eBit = e.testBit(i);
  2236.  
  2237.             if (hBit != eBit) {
  2238.                 R = R.add2D(hBit ? this : neg);
  2239.             }
  2240.         }
  2241.  
  2242.         return R;
  2243.     };
  2244.  
  2245.     ec.PointFp.prototype.isOnCurve = function () {
  2246.         var x = this.getX().toBigInteger();
  2247.         var y = this.getY().toBigInteger();
  2248.         var a = this.curve.getA().toBigInteger();
  2249.         var b = this.curve.getB().toBigInteger();
  2250.         var n = this.curve.getQ();
  2251.         var lhs = y.multiply(y).mod(n);
  2252.         var rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(n);
  2253.         return lhs.equals(rhs);
  2254.     };
  2255.  
  2256.     ec.PointFp.prototype.toString = function () {
  2257.         return '(' + this.getX().toBigInteger().toString() + ',' + this.getY().toBigInteger().toString() + ')';
  2258.     };
  2259.  
  2260.     /**
  2261.     * Validate an elliptic curve point.
  2262.     *
  2263.     * See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
  2264.     */
  2265.     ec.PointFp.prototype.validate = function () {
  2266.         var n = this.curve.getQ();
  2267.  
  2268.         // Check Q != O
  2269.         if (this.isInfinity()) {
  2270.             throw new Error("Point is at infinity.");
  2271.         }
  2272.  
  2273.         // Check coordinate bounds
  2274.         var x = this.getX().toBigInteger();
  2275.         var y = this.getY().toBigInteger();
  2276.         if (x.compareTo(BigInteger.ONE) < 0 || x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
  2277.             throw new Error('x coordinate out of bounds');
  2278.         }
  2279.         if (y.compareTo(BigInteger.ONE) < 0 || y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
  2280.             throw new Error('y coordinate out of bounds');
  2281.         }
  2282.  
  2283.         // Check y^2 = x^3 + ax + b (mod n)
  2284.         if (!this.isOnCurve()) {
  2285.             throw new Error("Point is not on the curve.");
  2286.         }
  2287.  
  2288.         // Check nQ = 0 (Q is a scalar multiple of G)
  2289.         if (this.multiply(n).isInfinity()) {
  2290.             // TODO: This check doesn't work - fix.
  2291.             throw new Error("Point is not a scalar multiple of G.");
  2292.         }
  2293.  
  2294.         return true;
  2295.     };
  2296.  
  2297.  
  2298.  
  2299.  
  2300.     // ----------------
  2301.     // ECCurveFp constructor
  2302.     ec.CurveFp = function (q, a, b) {
  2303.         this.q = q;
  2304.         this.a = this.fromBigInteger(a);
  2305.         this.b = this.fromBigInteger(b);
  2306.         this.infinity = new ec.PointFp(this, null, null);
  2307.         this.reducer = new Barrett(this.q);
  2308.     }
  2309.  
  2310.     ec.CurveFp.prototype.getQ = function () {
  2311.         return this.q;
  2312.     };
  2313.  
  2314.     ec.CurveFp.prototype.getA = function () {
  2315.         return this.a;
  2316.     };
  2317.  
  2318.     ec.CurveFp.prototype.getB = function () {
  2319.         return this.b;
  2320.     };
  2321.  
  2322.     ec.CurveFp.prototype.equals = function (other) {
  2323.         if (other == this) return true;
  2324.         return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
  2325.     };
  2326.  
  2327.     ec.CurveFp.prototype.getInfinity = function () {
  2328.         return this.infinity;
  2329.     };
  2330.  
  2331.     ec.CurveFp.prototype.fromBigInteger = function (x) {
  2332.         return new ec.FieldElementFp(this.q, x);
  2333.     };
  2334.  
  2335.     ec.CurveFp.prototype.reduce = function (x) {
  2336.         this.reducer.reduce(x);
  2337.     };
  2338.  
  2339.     // for now, work with hex strings because they're easier in JS
  2340.     // compressed support added by bitaddress.org
  2341.     ec.CurveFp.prototype.decodePointHex = function (s) {
  2342.         var firstByte = parseInt(s.substr(0, 2), 16);
  2343.         switch (firstByte) { // first byte
  2344.             case 0:
  2345.                 return this.infinity;
  2346.             case 2: // compressed
  2347.             case 3: // compressed
  2348.                 var yTilde = firstByte & 1;
  2349.                 var xHex = s.substr(2, s.length - 2);
  2350.                 var X1 = new BigInteger(xHex, 16);
  2351.                 return this.decompressPoint(yTilde, X1);
  2352.             case 4: // uncompressed
  2353.             case 6: // hybrid
  2354.             case 7: // hybrid
  2355.                 var len = (s.length - 2) / 2;
  2356.                 var xHex = s.substr(2, len);
  2357.                 var yHex = s.substr(len + 2, len);
  2358.  
  2359.                 return new ec.PointFp(this,
  2360.                     this.fromBigInteger(new BigInteger(xHex, 16)),
  2361.                     this.fromBigInteger(new BigInteger(yHex, 16)));
  2362.  
  2363.             default: // unsupported
  2364.                 return null;
  2365.         }
  2366.     };
  2367.  
  2368.     ec.CurveFp.prototype.encodePointHex = function (p) {
  2369.         if (p.isInfinity()) return "00";
  2370.         var xHex = p.getX().toBigInteger().toString(16);
  2371.         var yHex = p.getY().toBigInteger().toString(16);
  2372.         var oLen = this.getQ().toString(16).length;
  2373.         if ((oLen % 2) != 0) oLen++;
  2374.         while (xHex.length < oLen) {
  2375.             xHex = "0" + xHex;
  2376.         }
  2377.         while (yHex.length < oLen) {
  2378.             yHex = "0" + yHex;
  2379.         }
  2380.         return "04" + xHex + yHex;
  2381.     };
  2382.  
  2383.     /*
  2384.     * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
  2385.     * Ported to JavaScript by bitaddress.org
  2386.     *
  2387.     * Number yTilde
  2388.     * BigInteger X1
  2389.     */
  2390.     ec.CurveFp.prototype.decompressPoint = function (yTilde, X1) {
  2391.         var x = this.fromBigInteger(X1);
  2392.         var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
  2393.         var beta = alpha.sqrt();
  2394.         // if we can't find a sqrt we haven't got a point on the curve - run!
  2395.         if (beta == null) throw new Error("Invalid point compression");
  2396.         var betaValue = beta.toBigInteger();
  2397.         var bit0 = betaValue.testBit(0) ? 1 : 0;
  2398.         if (bit0 != yTilde) {
  2399.             // Use the other root
  2400.             beta = this.fromBigInteger(this.getQ().subtract(betaValue));
  2401.         }
  2402.         return new ec.PointFp(this, x, beta, null, true);
  2403.     };
  2404.  
  2405.  
  2406.     ec.fromHex = function (s) { return new BigInteger(s, 16); };
  2407.  
  2408.     ec.integerToBytes = function (i, len) {
  2409.         var bytes = i.toByteArrayUnsigned();
  2410.         if (len < bytes.length) {
  2411.             bytes = bytes.slice(bytes.length - len);
  2412.         } else while (len > bytes.length) {
  2413.             bytes.unshift(0);
  2414.         }
  2415.         return bytes;
  2416.     };
  2417.  
  2418.  
  2419.     // Named EC curves
  2420.     // ----------------
  2421.     // X9ECParameters constructor
  2422.     ec.X9Parameters = function (curve, g, n, h) {
  2423.         this.curve = curve;
  2424.         this.g = g;
  2425.         this.n = n;
  2426.         this.h = h;
  2427.     }
  2428.     ec.X9Parameters.prototype.getCurve = function () { return this.curve; };
  2429.     ec.X9Parameters.prototype.getG = function () { return this.g; };
  2430.     ec.X9Parameters.prototype.getN = function () { return this.n; };
  2431.     ec.X9Parameters.prototype.getH = function () { return this.h; };
  2432.  
  2433.     // secp256k1 is the Curve used by Bitcoin
  2434.     ec.secNamedCurves = {
  2435.         // used by Bitcoin
  2436.         "secp256k1": function () {
  2437.             // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
  2438.             var p = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
  2439.             var a = BigInteger.ZERO;
  2440.             var b = ec.fromHex("7");
  2441.             var n = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
  2442.             var h = BigInteger.ONE;
  2443.             var curve = new ec.CurveFp(p, a, b);
  2444.             var G = curve.decodePointHex("04"
  2445.                     + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
  2446.                     + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
  2447.             return new ec.X9Parameters(curve, G, n, h);
  2448.         }
  2449.     };
  2450.  
  2451.     // secp256k1 called by Bitcoin's ECKEY
  2452.     ec.getSECCurveByName = function (name) {
  2453.         if (ec.secNamedCurves[name] == undefined) return null;
  2454.         return ec.secNamedCurves[name]();
  2455.     }
  2456. })();
  2457.     </script>
  2458.     <script type="text/javascript">
  2459. /*!
  2460. * Basic JavaScript BN library - subset useful for RSA encryption. v1.3
  2461. *
  2462. * Copyright (c) 2005  Tom Wu
  2463. * All Rights Reserved.
  2464. * BSD License
  2465. * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
  2466. *
  2467. * Copyright Stephan Thomas
  2468. * Copyright bitaddress.org
  2469. */
  2470.  
  2471. (function () {
  2472.  
  2473.     // (public) Constructor function of Global BigInteger object
  2474.     var BigInteger = window.BigInteger = function BigInteger(a, b, c) {
  2475.         if (a != null)
  2476.             if ("number" == typeof a) this.fromNumber(a, b, c);
  2477.             else if (b == null && "string" != typeof a) this.fromString(a, 256);
  2478.             else this.fromString(a, b);
  2479.     };
  2480.  
  2481.     // Bits per digit
  2482.     var dbits;
  2483.  
  2484.     // JavaScript engine analysis
  2485.     var canary = 0xdeadbeefcafe;
  2486.     var j_lm = ((canary & 0xffffff) == 0xefcafe);
  2487.  
  2488.     // return new, unset BigInteger
  2489.     function nbi() { return new BigInteger(null); }
  2490.  
  2491.     // am: Compute w_j += (x*this_i), propagate carries,
  2492.     // c is initial carry, returns final carry.
  2493.     // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
  2494.     // We need to select the fastest one that works in this environment.
  2495.  
  2496.     // am1: use a single mult and divide to get the high bits,
  2497.     // max digit bits should be 26 because
  2498.     // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
  2499.     function am1(i, x, w, j, c, n) {
  2500.         while (--n >= 0) {
  2501.             var v = x * this[i++] + w[j] + c;
  2502.             c = Math.floor(v / 0x4000000);
  2503.             w[j++] = v & 0x3ffffff;
  2504.         }
  2505.         return c;
  2506.     }
  2507.     // am2 avoids a big mult-and-extract completely.
  2508.     // Max digit bits should be <= 30 because we do bitwise ops
  2509.     // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
  2510.     function am2(i, x, w, j, c, n) {
  2511.         var xl = x & 0x7fff, xh = x >> 15;
  2512.         while (--n >= 0) {
  2513.             var l = this[i] & 0x7fff;
  2514.             var h = this[i++] >> 15;
  2515.             var m = xh * l + h * xl;
  2516.             l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
  2517.             c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
  2518.             w[j++] = l & 0x3fffffff;
  2519.         }
  2520.         return c;
  2521.     }
  2522.     // Alternately, set max digit bits to 28 since some
  2523.     // browsers slow down when dealing with 32-bit numbers.
  2524.     function am3(i, x, w, j, c, n) {
  2525.         var xl = x & 0x3fff, xh = x >> 14;
  2526.         while (--n >= 0) {
  2527.             var l = this[i] & 0x3fff;
  2528.             var h = this[i++] >> 14;
  2529.             var m = xh * l + h * xl;
  2530.             l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
  2531.             c = (l >> 28) + (m >> 14) + xh * h;
  2532.             w[j++] = l & 0xfffffff;
  2533.         }
  2534.         return c;
  2535.     }
  2536.     if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
  2537.         BigInteger.prototype.am = am2;
  2538.         dbits = 30;
  2539.     }
  2540.     else if (j_lm && (navigator.appName != "Netscape")) {
  2541.         BigInteger.prototype.am = am1;
  2542.         dbits = 26;
  2543.     }
  2544.     else { // Mozilla/Netscape seems to prefer am3
  2545.         BigInteger.prototype.am = am3;
  2546.         dbits = 28;
  2547.     }
  2548.  
  2549.     BigInteger.prototype.DB = dbits;
  2550.     BigInteger.prototype.DM = ((1 << dbits) - 1);
  2551.     BigInteger.prototype.DV = (1 << dbits);
  2552.  
  2553.     var BI_FP = 52;
  2554.     BigInteger.prototype.FV = Math.pow(2, BI_FP);
  2555.     BigInteger.prototype.F1 = BI_FP - dbits;
  2556.     BigInteger.prototype.F2 = 2 * dbits - BI_FP;
  2557.  
  2558.     // Digit conversions
  2559.     var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
  2560.     var BI_RC = new Array();
  2561.     var rr, vv;
  2562.     rr = "0".charCodeAt(0);
  2563.     for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
  2564.     rr = "a".charCodeAt(0);
  2565.     for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
  2566.     rr = "A".charCodeAt(0);
  2567.     for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
  2568.  
  2569.     function int2char(n) { return BI_RM.charAt(n); }
  2570.     function intAt(s, i) {
  2571.         var c = BI_RC[s.charCodeAt(i)];
  2572.         return (c == null) ? -1 : c;
  2573.     }
  2574.  
  2575.  
  2576.  
  2577.     // return bigint initialized to value
  2578.     function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
  2579.  
  2580.  
  2581.     // returns bit length of the integer x
  2582.     function nbits(x) {
  2583.         var r = 1, t;
  2584.         if ((t = x >>> 16) != 0) { x = t; r += 16; }
  2585.         if ((t = x >> 8) != 0) { x = t; r += 8; }
  2586.         if ((t = x >> 4) != 0) { x = t; r += 4; }
  2587.         if ((t = x >> 2) != 0) { x = t; r += 2; }
  2588.         if ((t = x >> 1) != 0) { x = t; r += 1; }
  2589.         return r;
  2590.     }
  2591.  
  2592.  
  2593.  
  2594.  
  2595.  
  2596.  
  2597.  
  2598.     // (protected) copy this to r
  2599.     BigInteger.prototype.copyTo = function (r) {
  2600.         for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
  2601.         r.t = this.t;
  2602.         r.s = this.s;
  2603.     };
  2604.  
  2605.  
  2606.     // (protected) set from integer value x, -DV <= x < DV
  2607.     BigInteger.prototype.fromInt = function (x) {
  2608.         this.t = 1;
  2609.         this.s = (x < 0) ? -1 : 0;
  2610.         if (x > 0) this[0] = x;
  2611.         else if (x < -1) this[0] = x + this.DV;
  2612.         else this.t = 0;
  2613.     };
  2614.  
  2615.     // (protected) set from string and radix
  2616.     BigInteger.prototype.fromString = function (s, b) {
  2617.         var k;
  2618.         if (b == 16) k = 4;
  2619.         else if (b == 8) k = 3;
  2620.         else if (b == 256) k = 8; // byte array
  2621.         else if (b == 2) k = 1;
  2622.         else if (b == 32) k = 5;
  2623.         else if (b == 4) k = 2;
  2624.         else { this.fromRadix(s, b); return; }
  2625.         this.t = 0;
  2626.         this.s = 0;
  2627.         var i = s.length, mi = false, sh = 0;
  2628.         while (--i >= 0) {
  2629.             var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
  2630.             if (x < 0) {
  2631.                 if (s.charAt(i) == "-") mi = true;
  2632.                 continue;
  2633.             }
  2634.             mi = false;
  2635.             if (sh == 0)
  2636.                 this[this.t++] = x;
  2637.             else if (sh + k > this.DB) {
  2638.                 this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
  2639.                 this[this.t++] = (x >> (this.DB - sh));
  2640.             }
  2641.             else
  2642.                 this[this.t - 1] |= x << sh;
  2643.             sh += k;
  2644.             if (sh >= this.DB) sh -= this.DB;
  2645.         }
  2646.         if (k == 8 && (s[0] & 0x80) != 0) {
  2647.             this.s = -1;
  2648.             if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
  2649.         }
  2650.         this.clamp();
  2651.         if (mi) BigInteger.ZERO.subTo(this, this);
  2652.     };
  2653.  
  2654.  
  2655.     // (protected) clamp off excess high words
  2656.     BigInteger.prototype.clamp = function () {
  2657.         var c = this.s & this.DM;
  2658.         while (this.t > 0 && this[this.t - 1] == c) --this.t;
  2659.     };
  2660.  
  2661.     // (protected) r = this << n*DB
  2662.     BigInteger.prototype.dlShiftTo = function (n, r) {
  2663.         var i;
  2664.         for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
  2665.         for (i = n - 1; i >= 0; --i) r[i] = 0;
  2666.         r.t = this.t + n;
  2667.         r.s = this.s;
  2668.     };
  2669.  
  2670.     // (protected) r = this >> n*DB
  2671.     BigInteger.prototype.drShiftTo = function (n, r) {
  2672.         for (var i = n; i < this.t; ++i) r[i - n] = this[i];
  2673.         r.t = Math.max(this.t - n, 0);
  2674.         r.s = this.s;
  2675.     };
  2676.  
  2677.  
  2678.     // (protected) r = this << n
  2679.     BigInteger.prototype.lShiftTo = function (n, r) {
  2680.         var bs = n % this.DB;
  2681.         var cbs = this.DB - bs;
  2682.         var bm = (1 << cbs) - 1;
  2683.         var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i;
  2684.         for (i = this.t - 1; i >= 0; --i) {
  2685.             r[i + ds + 1] = (this[i] >> cbs) | c;
  2686.             c = (this[i] & bm) << bs;
  2687.         }
  2688.         for (i = ds - 1; i >= 0; --i) r[i] = 0;
  2689.         r[ds] = c;
  2690.         r.t = this.t + ds + 1;
  2691.         r.s = this.s;
  2692.         r.clamp();
  2693.     };
  2694.  
  2695.  
  2696.     // (protected) r = this >> n
  2697.     BigInteger.prototype.rShiftTo = function (n, r) {
  2698.         r.s = this.s;
  2699.         var ds = Math.floor(n / this.DB);
  2700.         if (ds >= this.t) { r.t = 0; return; }
  2701.         var bs = n % this.DB;
  2702.         var cbs = this.DB - bs;
  2703.         var bm = (1 << bs) - 1;
  2704.         r[0] = this[ds] >> bs;
  2705.         for (var i = ds + 1; i < this.t; ++i) {
  2706.             r[i - ds - 1] |= (this[i] & bm) << cbs;
  2707.             r[i - ds] = this[i] >> bs;
  2708.         }
  2709.         if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
  2710.         r.t = this.t - ds;
  2711.         r.clamp();
  2712.     };
  2713.  
  2714.  
  2715.     // (protected) r = this - a
  2716.     BigInteger.prototype.subTo = function (a, r) {
  2717.         var i = 0, c = 0, m = Math.min(a.t, this.t);
  2718.         while (i < m) {
  2719.             c += this[i] - a[i];
  2720.             r[i++] = c & this.DM;
  2721.             c >>= this.DB;
  2722.         }
  2723.         if (a.t < this.t) {
  2724.             c -= a.s;
  2725.             while (i < this.t) {
  2726.                 c += this[i];
  2727.                 r[i++] = c & this.DM;
  2728.                 c >>= this.DB;
  2729.             }
  2730.             c += this.s;
  2731.         }
  2732.         else {
  2733.             c += this.s;
  2734.             while (i < a.t) {
  2735.                 c -= a[i];
  2736.                 r[i++] = c & this.DM;
  2737.                 c >>= this.DB;
  2738.             }
  2739.             c -= a.s;
  2740.         }
  2741.         r.s = (c < 0) ? -1 : 0;
  2742.         if (c < -1) r[i++] = this.DV + c;
  2743.         else if (c > 0) r[i++] = c;
  2744.         r.t = i;
  2745.         r.clamp();
  2746.     };
  2747.  
  2748.  
  2749.     // (protected) r = this * a, r != this,a (HAC 14.12)
  2750.     // "this" should be the larger one if appropriate.
  2751.     BigInteger.prototype.multiplyTo = function (a, r) {
  2752.         var x = this.abs(), y = a.abs();
  2753.         var i = x.t;
  2754.         r.t = i + y.t;
  2755.         while (--i >= 0) r[i] = 0;
  2756.         for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
  2757.         r.s = 0;
  2758.         r.clamp();
  2759.         if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
  2760.     };
  2761.  
  2762.  
  2763.     // (protected) r = this^2, r != this (HAC 14.16)
  2764.     BigInteger.prototype.squareTo = function (r) {
  2765.         var x = this.abs();
  2766.         var i = r.t = 2 * x.t;
  2767.         while (--i >= 0) r[i] = 0;
  2768.         for (i = 0; i < x.t - 1; ++i) {
  2769.             var c = x.am(i, x[i], r, 2 * i, 0, 1);
  2770.             if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
  2771.                 r[i + x.t] -= x.DV;
  2772.                 r[i + x.t + 1] = 1;
  2773.             }
  2774.         }
  2775.         if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
  2776.         r.s = 0;
  2777.         r.clamp();
  2778.     };
  2779.  
  2780.  
  2781.  
  2782.     // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
  2783.     // r != q, this != m.  q or r may be null.
  2784.     BigInteger.prototype.divRemTo = function (m, q, r) {
  2785.         var pm = m.abs();
  2786.         if (pm.t <= 0) return;
  2787.         var pt = this.abs();
  2788.         if (pt.t < pm.t) {
  2789.             if (q != null) q.fromInt(0);
  2790.             if (r != null) this.copyTo(r);
  2791.             return;
  2792.         }
  2793.         if (r == null) r = nbi();
  2794.         var y = nbi(), ts = this.s, ms = m.s;
  2795.         var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
  2796.         if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); }
  2797.         else { pm.copyTo(y); pt.copyTo(r); }
  2798.         var ys = y.t;
  2799.         var y0 = y[ys - 1];
  2800.         if (y0 == 0) return;
  2801.         var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
  2802.         var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2;
  2803.         var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
  2804.         y.dlShiftTo(j, t);
  2805.         if (r.compareTo(t) >= 0) {
  2806.             r[r.t++] = 1;
  2807.             r.subTo(t, r);
  2808.         }
  2809.         BigInteger.ONE.dlShiftTo(ys, t);
  2810.         t.subTo(y, y); // "negative" y so we can replace sub with am later
  2811.         while (y.t < ys) y[y.t++] = 0;
  2812.         while (--j >= 0) {
  2813.             // Estimate quotient digit
  2814.             var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
  2815.             if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) {  // Try it out
  2816.                 y.dlShiftTo(j, t);
  2817.                 r.subTo(t, r);
  2818.                 while (r[i] < --qd) r.subTo(t, r);
  2819.             }
  2820.         }
  2821.         if (q != null) {
  2822.             r.drShiftTo(ys, q);
  2823.             if (ts != ms) BigInteger.ZERO.subTo(q, q);
  2824.         }
  2825.         r.t = ys;
  2826.         r.clamp();
  2827.         if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
  2828.         if (ts < 0) BigInteger.ZERO.subTo(r, r);
  2829.     };
  2830.  
  2831.  
  2832.     // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
  2833.     // justification:
  2834.     //         xy == 1 (mod m)
  2835.     //         xy =  1+km
  2836.     //   xy(2-xy) = (1+km)(1-km)
  2837.     // x[y(2-xy)] = 1-k^2m^2
  2838.     // x[y(2-xy)] == 1 (mod m^2)
  2839.     // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
  2840.     // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
  2841.     // JS multiply "overflows" differently from C/C++, so care is needed here.
  2842.     BigInteger.prototype.invDigit = function () {
  2843.         if (this.t < 1) return 0;
  2844.         var x = this[0];
  2845.         if ((x & 1) == 0) return 0;
  2846.         var y = x & 3;  // y == 1/x mod 2^2
  2847.         y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
  2848.         y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
  2849.         y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
  2850.         // last step - calculate inverse mod DV directly;
  2851.         // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
  2852.         y = (y * (2 - x * y % this.DV)) % this.DV;  // y == 1/x mod 2^dbits
  2853.         // we really want the negative inverse, and -DV < y < DV
  2854.         return (y > 0) ? this.DV - y : -y;
  2855.     };
  2856.  
  2857.  
  2858.     // (protected) true iff this is even
  2859.     BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; };
  2860.  
  2861.  
  2862.     // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
  2863.     BigInteger.prototype.exp = function (e, z) {
  2864.         if (e > 0xffffffff || e < 1) return BigInteger.ONE;
  2865.         var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
  2866.         g.copyTo(r);
  2867.         while (--i >= 0) {
  2868.             z.sqrTo(r, r2);
  2869.             if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
  2870.             else { var t = r; r = r2; r2 = t; }
  2871.         }
  2872.         return z.revert(r);
  2873.     };
  2874.  
  2875.  
  2876.     // (public) return string representation in given radix
  2877.     BigInteger.prototype.toString = function (b) {
  2878.         if (this.s < 0) return "-" + this.negate().toString(b);
  2879.         var k;
  2880.         if (b == 16) k = 4;
  2881.         else if (b == 8) k = 3;
  2882.         else if (b == 2) k = 1;
  2883.         else if (b == 32) k = 5;
  2884.         else if (b == 4) k = 2;
  2885.         else return this.toRadix(b);
  2886.         var km = (1 << k) - 1, d, m = false, r = "", i = this.t;
  2887.         var p = this.DB - (i * this.DB) % k;
  2888.         if (i-- > 0) {
  2889.             if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); }
  2890.             while (i >= 0) {
  2891.                 if (p < k) {
  2892.                     d = (this[i] & ((1 << p) - 1)) << (k - p);
  2893.                     d |= this[--i] >> (p += this.DB - k);
  2894.                 }
  2895.                 else {
  2896.                     d = (this[i] >> (p -= k)) & km;
  2897.                     if (p <= 0) { p += this.DB; --i; }
  2898.                 }
  2899.                 if (d > 0) m = true;
  2900.                 if (m) r += int2char(d);
  2901.             }
  2902.         }
  2903.         return m ? r : "0";
  2904.     };
  2905.  
  2906.  
  2907.     // (public) -this
  2908.     BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; };
  2909.  
  2910.     // (public) |this|
  2911.     BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; };
  2912.  
  2913.     // (public) return + if this > a, - if this < a, 0 if equal
  2914.     BigInteger.prototype.compareTo = function (a) {
  2915.         var r = this.s - a.s;
  2916.         if (r != 0) return r;
  2917.         var i = this.t;
  2918.         r = i - a.t;
  2919.         if (r != 0) return (this.s < 0) ? -r : r;
  2920.         while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
  2921.         return 0;
  2922.     }
  2923.  
  2924.     // (public) return the number of bits in "this"
  2925.     BigInteger.prototype.bitLength = function () {
  2926.         if (this.t <= 0) return 0;
  2927.         return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
  2928.     };
  2929.  
  2930.     // (public) this mod a
  2931.     BigInteger.prototype.mod = function (a) {
  2932.         var r = nbi();
  2933.         this.abs().divRemTo(a, null, r);
  2934.         if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
  2935.         return r;
  2936.     }
  2937.  
  2938.     // (public) this^e % m, 0 <= e < 2^32
  2939.     BigInteger.prototype.modPowInt = function (e, m) {
  2940.         var z;
  2941.         if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
  2942.         return this.exp(e, z);
  2943.     };
  2944.  
  2945.     // "constants"
  2946.     BigInteger.ZERO = nbv(0);
  2947.     BigInteger.ONE = nbv(1);
  2948.  
  2949.  
  2950.  
  2951.  
  2952.  
  2953.  
  2954.  
  2955.     // Copyright (c) 2005-2009  Tom Wu
  2956.     // All Rights Reserved.
  2957.     // See "LICENSE" for details.
  2958.     // Extended JavaScript BN functions, required for RSA private ops.
  2959.     // Version 1.1: new BigInteger("0", 10) returns "proper" zero
  2960.     // Version 1.2: square() API, isProbablePrime fix
  2961.  
  2962.  
  2963.     // return index of lowest 1-bit in x, x < 2^31
  2964.     function lbit(x) {
  2965.         if (x == 0) return -1;
  2966.         var r = 0;
  2967.         if ((x & 0xffff) == 0) { x >>= 16; r += 16; }
  2968.         if ((x & 0xff) == 0) { x >>= 8; r += 8; }
  2969.         if ((x & 0xf) == 0) { x >>= 4; r += 4; }
  2970.         if ((x & 3) == 0) { x >>= 2; r += 2; }
  2971.         if ((x & 1) == 0) ++r;
  2972.         return r;
  2973.     }
  2974.  
  2975.     // return number of 1 bits in x
  2976.     function cbit(x) {
  2977.         var r = 0;
  2978.         while (x != 0) { x &= x - 1; ++r; }
  2979.         return r;
  2980.     }
  2981.  
  2982.     var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
  2983.     var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
  2984.  
  2985.  
  2986.  
  2987.     // (protected) return x s.t. r^x < DV
  2988.     BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); };
  2989.  
  2990.     // (protected) convert to radix string
  2991.     BigInteger.prototype.toRadix = function (b) {
  2992.         if (b == null) b = 10;
  2993.         if (this.signum() == 0 || b < 2 || b > 36) return "0";
  2994.         var cs = this.chunkSize(b);
  2995.         var a = Math.pow(b, cs);
  2996.         var d = nbv(a), y = nbi(), z = nbi(), r = "";
  2997.         this.divRemTo(d, y, z);
  2998.         while (y.signum() > 0) {
  2999.             r = (a + z.intValue()).toString(b).substr(1) + r;
  3000.             y.divRemTo(d, y, z);
  3001.         }
  3002.         return z.intValue().toString(b) + r;
  3003.     };
  3004.  
  3005.     // (protected) convert from radix string
  3006.     BigInteger.prototype.fromRadix = function (s, b) {
  3007.         this.fromInt(0);
  3008.         if (b == null) b = 10;
  3009.         var cs = this.chunkSize(b);
  3010.         var d = Math.pow(b, cs), mi = false, j = 0, w = 0;
  3011.         for (var i = 0; i < s.length; ++i) {
  3012.             var x = intAt(s, i);
  3013.             if (x < 0) {
  3014.                 if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
  3015.                 continue;
  3016.             }
  3017.             w = b * w + x;
  3018.             if (++j >= cs) {
  3019.                 this.dMultiply(d);
  3020.                 this.dAddOffset(w, 0);
  3021.                 j = 0;
  3022.                 w = 0;
  3023.             }
  3024.         }
  3025.         if (j > 0) {
  3026.             this.dMultiply(Math.pow(b, j));
  3027.             this.dAddOffset(w, 0);
  3028.         }
  3029.         if (mi) BigInteger.ZERO.subTo(this, this);
  3030.     };
  3031.  
  3032.     // (protected) alternate constructor
  3033.     BigInteger.prototype.fromNumber = function (a, b, c) {
  3034.         if ("number" == typeof b) {
  3035.             // new BigInteger(int,int,RNG)
  3036.             if (a < 2) this.fromInt(1);
  3037.             else {
  3038.                 this.fromNumber(a, c);
  3039.                 if (!this.testBit(a - 1))   // force MSB set
  3040.                     this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
  3041.                 if (this.isEven()) this.dAddOffset(1, 0); // force odd
  3042.                 while (!this.isProbablePrime(b)) {
  3043.                     this.dAddOffset(2, 0);
  3044.                     if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
  3045.                 }
  3046.             }
  3047.         }
  3048.         else {
  3049.             // new BigInteger(int,RNG)
  3050.             var x = new Array(), t = a & 7;
  3051.             x.length = (a >> 3) + 1;
  3052.             b.nextBytes(x);
  3053.             if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0;
  3054.             this.fromString(x, 256);
  3055.         }
  3056.     };
  3057.  
  3058.     // (protected) r = this op a (bitwise)
  3059.     BigInteger.prototype.bitwiseTo = function (a, op, r) {
  3060.         var i, f, m = Math.min(a.t, this.t);
  3061.         for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
  3062.         if (a.t < this.t) {
  3063.             f = a.s & this.DM;
  3064.             for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
  3065.             r.t = this.t;
  3066.         }
  3067.         else {
  3068.             f = this.s & this.DM;
  3069.             for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
  3070.             r.t = a.t;
  3071.         }
  3072.         r.s = op(this.s, a.s);
  3073.         r.clamp();
  3074.     };
  3075.  
  3076.     // (protected) this op (1<<n)
  3077.     BigInteger.prototype.changeBit = function (n, op) {
  3078.         var r = BigInteger.ONE.shiftLeft(n);
  3079.         this.bitwiseTo(r, op, r);
  3080.         return r;
  3081.     };
  3082.  
  3083.     // (protected) r = this + a
  3084.     BigInteger.prototype.addTo = function (a, r) {
  3085.         var i = 0, c = 0, m = Math.min(a.t, this.t);
  3086.         while (i < m) {
  3087.             c += this[i] + a[i];
  3088.             r[i++] = c & this.DM;
  3089.             c >>= this.DB;
  3090.         }
  3091.         if (a.t < this.t) {
  3092.             c += a.s;
  3093.             while (i < this.t) {
  3094.                 c += this[i];
  3095.                 r[i++] = c & this.DM;
  3096.                 c >>= this.DB;
  3097.             }
  3098.             c += this.s;
  3099.         }
  3100.         else {
  3101.             c += this.s;
  3102.             while (i < a.t) {
  3103.                 c += a[i];
  3104.                 r[i++] = c & this.DM;
  3105.                 c >>= this.DB;
  3106.             }
  3107.             c += a.s;
  3108.         }
  3109.         r.s = (c < 0) ? -1 : 0;
  3110.         if (c > 0) r[i++] = c;
  3111.         else if (c < -1) r[i++] = this.DV + c;
  3112.         r.t = i;
  3113.         r.clamp();
  3114.     };
  3115.  
  3116.     // (protected) this *= n, this >= 0, 1 < n < DV
  3117.     BigInteger.prototype.dMultiply = function (n) {
  3118.         this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
  3119.         ++this.t;
  3120.         this.clamp();
  3121.     };
  3122.  
  3123.     // (protected) this += n << w words, this >= 0
  3124.     BigInteger.prototype.dAddOffset = function (n, w) {
  3125.         if (n == 0) return;
  3126.         while (this.t <= w) this[this.t++] = 0;
  3127.         this[w] += n;
  3128.         while (this[w] >= this.DV) {
  3129.             this[w] -= this.DV;
  3130.             if (++w >= this.t) this[this.t++] = 0;
  3131.             ++this[w];
  3132.         }
  3133.     };
  3134.  
  3135.     // (protected) r = lower n words of "this * a", a.t <= n
  3136.     // "this" should be the larger one if appropriate.
  3137.     BigInteger.prototype.multiplyLowerTo = function (a, n, r) {
  3138.         var i = Math.min(this.t + a.t, n);
  3139.         r.s = 0; // assumes a,this >= 0
  3140.         r.t = i;
  3141.         while (i > 0) r[--i] = 0;
  3142.         var j;
  3143.         for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
  3144.         for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
  3145.         r.clamp();
  3146.     };
  3147.  
  3148.  
  3149.     // (protected) r = "this * a" without lower n words, n > 0
  3150.     // "this" should be the larger one if appropriate.
  3151.     BigInteger.prototype.multiplyUpperTo = function (a, n, r) {
  3152.         --n;
  3153.         var i = r.t = this.t + a.t - n;
  3154.         r.s = 0; // assumes a,this >= 0
  3155.         while (--i >= 0) r[i] = 0;
  3156.         for (i = Math.max(n - this.t, 0); i < a.t; ++i)
  3157.             r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
  3158.         r.clamp();
  3159.         r.drShiftTo(1, r);
  3160.     };
  3161.  
  3162.     // (protected) this % n, n < 2^26
  3163.     BigInteger.prototype.modInt = function (n) {
  3164.         if (n <= 0) return 0;
  3165.         var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0;
  3166.         if (this.t > 0)
  3167.             if (d == 0) r = this[0] % n;
  3168.             else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
  3169.         return r;
  3170.     };
  3171.  
  3172.  
  3173.     // (protected) true if probably prime (HAC 4.24, Miller-Rabin)
  3174.     BigInteger.prototype.millerRabin = function (t) {
  3175.         var n1 = this.subtract(BigInteger.ONE);
  3176.         var k = n1.getLowestSetBit();
  3177.         if (k <= 0) return false;
  3178.         var r = n1.shiftRight(k);
  3179.         t = (t + 1) >> 1;
  3180.         if (t > lowprimes.length) t = lowprimes.length;
  3181.         var a = nbi();
  3182.         for (var i = 0; i < t; ++i) {
  3183.             //Pick bases at random, instead of starting at 2
  3184.             a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
  3185.             var y = a.modPow(r, this);
  3186.             if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
  3187.                 var j = 1;
  3188.                 while (j++ < k && y.compareTo(n1) != 0) {
  3189.                     y = y.modPowInt(2, this);
  3190.                     if (y.compareTo(BigInteger.ONE) == 0) return false;
  3191.                 }
  3192.                 if (y.compareTo(n1) != 0) return false;
  3193.             }
  3194.         }
  3195.         return true;
  3196.     };
  3197.  
  3198.  
  3199.  
  3200.     // (public)
  3201.     BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; };
  3202.  
  3203.     // (public) return value as integer
  3204.     BigInteger.prototype.intValue = function () {
  3205.         if (this.s < 0) {
  3206.             if (this.t == 1) return this[0] - this.DV;
  3207.             else if (this.t == 0) return -1;
  3208.         }
  3209.         else if (this.t == 1) return this[0];
  3210.         else if (this.t == 0) return 0;
  3211.         // assumes 16 < DB < 32
  3212.         return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
  3213.     };
  3214.  
  3215.  
  3216.     // (public) return value as byte
  3217.     BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; };
  3218.  
  3219.     // (public) return value as short (assumes DB>=16)
  3220.     BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; };
  3221.  
  3222.     // (public) 0 if this == 0, 1 if this > 0
  3223.     BigInteger.prototype.signum = function () {
  3224.         if (this.s < 0) return -1;
  3225.         else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
  3226.         else return 1;
  3227.     };
  3228.  
  3229.  
  3230.     // (public) convert to bigendian byte array
  3231.     BigInteger.prototype.toByteArray = function () {
  3232.         var i = this.t, r = new Array();
  3233.         r[0] = this.s;
  3234.         var p = this.DB - (i * this.DB) % 8, d, k = 0;
  3235.         if (i-- > 0) {
  3236.             if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
  3237.                 r[k++] = d | (this.s << (this.DB - p));
  3238.             while (i >= 0) {
  3239.                 if (p < 8) {
  3240.                     d = (this[i] & ((1 << p) - 1)) << (8 - p);
  3241.                     d |= this[--i] >> (p += this.DB - 8);
  3242.                 }
  3243.                 else {
  3244.                     d = (this[i] >> (p -= 8)) & 0xff;
  3245.                     if (p <= 0) { p += this.DB; --i; }
  3246.                 }
  3247.                 if ((d & 0x80) != 0) d |= -256;
  3248.                 if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k;
  3249.                 if (k > 0 || d != this.s) r[k++] = d;
  3250.             }
  3251.         }
  3252.         return r;
  3253.     };
  3254.  
  3255.     BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); };
  3256.     BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; };
  3257.     BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; };
  3258.  
  3259.     // (public) this & a
  3260.     function op_and(x, y) { return x & y; }
  3261.     BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; };
  3262.  
  3263.     // (public) this | a
  3264.     function op_or(x, y) { return x | y; }
  3265.     BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; };
  3266.  
  3267.     // (public) this ^ a
  3268.     function op_xor(x, y) { return x ^ y; }
  3269.     BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; };
  3270.  
  3271.     // (public) this & ~a
  3272.     function op_andnot(x, y) { return x & ~y; }
  3273.     BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; };
  3274.  
  3275.     // (public) ~this
  3276.     BigInteger.prototype.not = function () {
  3277.         var r = nbi();
  3278.         for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
  3279.         r.t = this.t;
  3280.         r.s = ~this.s;
  3281.         return r;
  3282.     };
  3283.  
  3284.     // (public) this << n
  3285.     BigInteger.prototype.shiftLeft = function (n) {
  3286.         var r = nbi();
  3287.         if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
  3288.         return r;
  3289.     };
  3290.  
  3291.     // (public) this >> n
  3292.     BigInteger.prototype.shiftRight = function (n) {
  3293.         var r = nbi();
  3294.         if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
  3295.         return r;
  3296.     };
  3297.  
  3298.     // (public) returns index of lowest 1-bit (or -1 if none)
  3299.     BigInteger.prototype.getLowestSetBit = function () {
  3300.         for (var i = 0; i < this.t; ++i)
  3301.             if (this[i] != 0) return i * this.DB + lbit(this[i]);
  3302.         if (this.s < 0) return this.t * this.DB;
  3303.         return -1;
  3304.     };
  3305.  
  3306.     // (public) return number of set bits
  3307.     BigInteger.prototype.bitCount = function () {
  3308.         var r = 0, x = this.s & this.DM;
  3309.         for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
  3310.         return r;
  3311.     };
  3312.  
  3313.     // (public) true iff nth bit is set
  3314.     BigInteger.prototype.testBit = function (n) {
  3315.         var j = Math.floor(n / this.DB);
  3316.         if (j >= this.t) return (this.s != 0);
  3317.         return ((this[j] & (1 << (n % this.DB))) != 0);
  3318.     };
  3319.  
  3320.     // (public) this | (1<<n)
  3321.     BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or); };
  3322.     // (public) this & ~(1<<n)
  3323.     BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot); };
  3324.     // (public) this ^ (1<<n)
  3325.     BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor); };
  3326.     // (public) this + a
  3327.     BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r; };
  3328.     // (public) this - a
  3329.     BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r; };
  3330.     // (public) this * a
  3331.     BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r; };
  3332.     // (public) this / a
  3333.     BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r; };
  3334.     // (public) this % a
  3335.     BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r; };
  3336.     // (public) [this/a,this%a]
  3337.     BigInteger.prototype.divideAndRemainder = function (a) {
  3338.         var q = nbi(), r = nbi();
  3339.         this.divRemTo(a, q, r);
  3340.         return new Array(q, r);
  3341.     };
  3342.  
  3343.     // (public) this^e % m (HAC 14.85)
  3344.     BigInteger.prototype.modPow = function (e, m) {
  3345.         var i = e.bitLength(), k, r = nbv(1), z;
  3346.         if (i <= 0) return r;
  3347.         else if (i < 18) k = 1;
  3348.         else if (i < 48) k = 3;
  3349.         else if (i < 144) k = 4;
  3350.         else if (i < 768) k = 5;
  3351.         else k = 6;
  3352.         if (i < 8)
  3353.             z = new Classic(m);
  3354.         else if (m.isEven())
  3355.             z = new Barrett(m);
  3356.         else
  3357.             z = new Montgomery(m);
  3358.  
  3359.         // precomputation
  3360.         var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1;
  3361.         g[1] = z.convert(this);
  3362.         if (k > 1) {
  3363.             var g2 = nbi();
  3364.             z.sqrTo(g[1], g2);
  3365.             while (n <= km) {
  3366.                 g[n] = nbi();
  3367.                 z.mulTo(g2, g[n - 2], g[n]);
  3368.                 n += 2;
  3369.             }
  3370.         }
  3371.  
  3372.         var j = e.t - 1, w, is1 = true, r2 = nbi(), t;
  3373.         i = nbits(e[j]) - 1;
  3374.         while (j >= 0) {
  3375.             if (i >= k1) w = (e[j] >> (i - k1)) & km;
  3376.             else {
  3377.                 w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
  3378.                 if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
  3379.             }
  3380.  
  3381.             n = k;
  3382.             while ((w & 1) == 0) { w >>= 1; --n; }
  3383.             if ((i -= n) < 0) { i += this.DB; --j; }
  3384.             if (is1) {  // ret == 1, don't bother squaring or multiplying it
  3385.                 g[w].copyTo(r);
  3386.                 is1 = false;
  3387.             }
  3388.             else {
  3389.                 while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; }
  3390.                 if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; }
  3391.                 z.mulTo(r2, g[w], r);
  3392.             }
  3393.  
  3394.             while (j >= 0 && (e[j] & (1 << i)) == 0) {
  3395.                 z.sqrTo(r, r2); t = r; r = r2; r2 = t;
  3396.                 if (--i < 0) { i = this.DB - 1; --j; }
  3397.             }
  3398.         }
  3399.         return z.revert(r);
  3400.     };
  3401.  
  3402.     // (public) 1/this % m (HAC 14.61)
  3403.     BigInteger.prototype.modInverse = function (m) {
  3404.         var ac = m.isEven();
  3405.         if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
  3406.         var u = m.clone(), v = this.clone();
  3407.         var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
  3408.         while (u.signum() != 0) {
  3409.             while (u.isEven()) {
  3410.                 u.rShiftTo(1, u);
  3411.                 if (ac) {
  3412.                     if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); }
  3413.                     a.rShiftTo(1, a);
  3414.                 }
  3415.                 else if (!b.isEven()) b.subTo(m, b);
  3416.                 b.rShiftTo(1, b);
  3417.             }
  3418.             while (v.isEven()) {
  3419.                 v.rShiftTo(1, v);
  3420.                 if (ac) {
  3421.                     if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); }
  3422.                     c.rShiftTo(1, c);
  3423.                 }
  3424.                 else if (!d.isEven()) d.subTo(m, d);
  3425.                 d.rShiftTo(1, d);
  3426.             }
  3427.             if (u.compareTo(v) >= 0) {
  3428.                 u.subTo(v, u);
  3429.                 if (ac) a.subTo(c, a);
  3430.                 b.subTo(d, b);
  3431.             }
  3432.             else {
  3433.                 v.subTo(u, v);
  3434.                 if (ac) c.subTo(a, c);
  3435.                 d.subTo(b, d);
  3436.             }
  3437.         }
  3438.         if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
  3439.         if (d.compareTo(m) >= 0) return d.subtract(m);
  3440.         if (d.signum() < 0) d.addTo(m, d); else return d;
  3441.         if (d.signum() < 0) return d.add(m); else return d;
  3442.     };
  3443.  
  3444.  
  3445.     // (public) this^e
  3446.     BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); };
  3447.  
  3448.     // (public) gcd(this,a) (HAC 14.54)
  3449.     BigInteger.prototype.gcd = function (a) {
  3450.         var x = (this.s < 0) ? this.negate() : this.clone();
  3451.         var y = (a.s < 0) ? a.negate() : a.clone();
  3452.         if (x.compareTo(y) < 0) { var t = x; x = y; y = t; }
  3453.         var i = x.getLowestSetBit(), g = y.getLowestSetBit();
  3454.         if (g < 0) return x;
  3455.         if (i < g) g = i;
  3456.         if (g > 0) {
  3457.             x.rShiftTo(g, x);
  3458.             y.rShiftTo(g, y);
  3459.         }
  3460.         while (x.signum() > 0) {
  3461.             if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
  3462.             if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
  3463.             if (x.compareTo(y) >= 0) {
  3464.                 x.subTo(y, x);
  3465.                 x.rShiftTo(1, x);
  3466.             }
  3467.             else {
  3468.                 y.subTo(x, y);
  3469.                 y.rShiftTo(1, y);
  3470.             }
  3471.         }
  3472.         if (g > 0) y.lShiftTo(g, y);
  3473.         return y;
  3474.     };
  3475.  
  3476.     // (public) test primality with certainty >= 1-.5^t
  3477.     BigInteger.prototype.isProbablePrime = function (t) {
  3478.         var i, x = this.abs();
  3479.         if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
  3480.             for (i = 0; i < lowprimes.length; ++i)
  3481.                 if (x[0] == lowprimes[i]) return true;
  3482.             return false;
  3483.         }
  3484.         if (x.isEven()) return false;
  3485.         i = 1;
  3486.         while (i < lowprimes.length) {
  3487.             var m = lowprimes[i], j = i + 1;
  3488.             while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
  3489.             m = x.modInt(m);
  3490.             while (i < j) if (m % lowprimes[i++] == 0) return false;
  3491.         }
  3492.         return x.millerRabin(t);
  3493.     };
  3494.  
  3495.  
  3496.     // JSBN-specific extension
  3497.  
  3498.     // (public) this^2
  3499.     BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; };
  3500.  
  3501.  
  3502.     // NOTE: BigInteger interfaces not implemented in jsbn:
  3503.     // BigInteger(int signum, byte[] magnitude)
  3504.     // double doubleValue()
  3505.     // float floatValue()
  3506.     // int hashCode()
  3507.     // long longValue()
  3508.     // static BigInteger valueOf(long val)
  3509.  
  3510.  
  3511.  
  3512.     // Copyright Stephan Thomas (start) --- //
  3513.     // https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js
  3514.     // BigInteger monkey patching
  3515.     BigInteger.valueOf = nbv;
  3516.  
  3517.     /**
  3518.     * Returns a byte array representation of the big integer.
  3519.     *
  3520.     * This returns the absolute of the contained value in big endian
  3521.     * form. A value of zero results in an empty array.
  3522.     */
  3523.     BigInteger.prototype.toByteArrayUnsigned = function () {
  3524.         var ba = this.abs().toByteArray();
  3525.         if (ba.length) {
  3526.             if (ba[0] == 0) {
  3527.                 ba = ba.slice(1);
  3528.             }
  3529.             return ba.map(function (v) {
  3530.                 return (v < 0) ? v + 256 : v;
  3531.             });
  3532.         } else {
  3533.             // Empty array, nothing to do
  3534.             return ba;
  3535.         }
  3536.     };
  3537.  
  3538.     /**
  3539.     * Turns a byte array into a big integer.
  3540.     *
  3541.     * This function will interpret a byte array as a big integer in big
  3542.     * endian notation and ignore leading zeros.
  3543.     */
  3544.     BigInteger.fromByteArrayUnsigned = function (ba) {
  3545.         if (!ba.length) {
  3546.             return ba.valueOf(0);
  3547.         } else if (ba[0] & 0x80) {
  3548.             // Prepend a zero so the BigInteger class doesn't mistake this
  3549.             // for a negative integer.
  3550.             return new BigInteger([0].concat(ba));
  3551.         } else {
  3552.             return new BigInteger(ba);
  3553.         }
  3554.     };
  3555.     /**
  3556.     * Converts big integer to signed byte representation.
  3557.     *
  3558.     * The format for this value uses a the most significant bit as a sign
  3559.     * bit. If the most significant bit is already occupied by the
  3560.     * absolute value, an extra byte is prepended and the sign bit is set
  3561.     * there.
  3562.     *
  3563.     * Examples:
  3564.     *
  3565.     *      0 =>     0x00
  3566.     *      1 =>     0x01
  3567.     *     -1 =>     0x81
  3568.     *    127 =>     0x7f
  3569.     *   -127 =>     0xff
  3570.     *    128 =>   0x0080
  3571.     *   -128 =>   0x8080
  3572.     *    255 =>   0x00ff
  3573.     *   -255 =>   0x80ff
  3574.     *  16300 =>   0x3fac
  3575.     * -16300 =>   0xbfac
  3576.     *  62300 => 0x00f35c
  3577.     * -62300 => 0x80f35c
  3578.     */
  3579.     BigInteger.prototype.toByteArraySigned = function () {
  3580.         var val = this.abs().toByteArrayUnsigned();
  3581.         var neg = this.compareTo(BigInteger.ZERO) < 0;
  3582.  
  3583.         if (neg) {
  3584.             if (val[0] & 0x80) {
  3585.                 val.unshift(0x80);
  3586.             } else {
  3587.                 val[0] |= 0x80;
  3588.             }
  3589.         } else {
  3590.             if (val[0] & 0x80) {
  3591.                 val.unshift(0x00);
  3592.             }
  3593.         }
  3594.  
  3595.         return val;
  3596.     };
  3597.  
  3598.     /**
  3599.     * Parse a signed big integer byte representation.
  3600.     *
  3601.     * For details on the format please see BigInteger.toByteArraySigned.
  3602.     */
  3603.     BigInteger.fromByteArraySigned = function (ba) {
  3604.         // Check for negative value
  3605.         if (ba[0] & 0x80) {
  3606.             // Remove sign bit
  3607.             ba[0] &= 0x7f;
  3608.  
  3609.             return BigInteger.fromByteArrayUnsigned(ba).negate();
  3610.         } else {
  3611.             return BigInteger.fromByteArrayUnsigned(ba);
  3612.         }
  3613.     };
  3614.     // Copyright Stephan Thomas (end) --- //
  3615.  
  3616.  
  3617.  
  3618.  
  3619.     // ****** REDUCTION ******* //
  3620.  
  3621.     // Modular reduction using "classic" algorithm
  3622.     var Classic = window.Classic = function Classic(m) { this.m = m; }
  3623.     Classic.prototype.convert = function (x) {
  3624.         if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
  3625.         else return x;
  3626.     };
  3627.     Classic.prototype.revert = function (x) { return x; };
  3628.     Classic.prototype.reduce = function (x) { x.divRemTo(this.m, null, x); };
  3629.     Classic.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
  3630.     Classic.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
  3631.  
  3632.  
  3633.  
  3634.  
  3635.  
  3636.     // Montgomery reduction
  3637.     var Montgomery = window.Montgomery = function Montgomery(m) {
  3638.         this.m = m;
  3639.         this.mp = m.invDigit();
  3640.         this.mpl = this.mp & 0x7fff;
  3641.         this.mph = this.mp >> 15;
  3642.         this.um = (1 << (m.DB - 15)) - 1;
  3643.         this.mt2 = 2 * m.t;
  3644.     }
  3645.     // xR mod m
  3646.     Montgomery.prototype.convert = function (x) {
  3647.         var r = nbi();
  3648.         x.abs().dlShiftTo(this.m.t, r);
  3649.         r.divRemTo(this.m, null, r);
  3650.         if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
  3651.         return r;
  3652.     }
  3653.     // x/R mod m
  3654.     Montgomery.prototype.revert = function (x) {
  3655.         var r = nbi();
  3656.         x.copyTo(r);
  3657.         this.reduce(r);
  3658.         return r;
  3659.     };
  3660.     // x = x/R mod m (HAC 14.32)
  3661.     Montgomery.prototype.reduce = function (x) {
  3662.         while (x.t <= this.mt2) // pad x so am has enough room later
  3663.             x[x.t++] = 0;
  3664.         for (var i = 0; i < this.m.t; ++i) {
  3665.             // faster way of calculating u0 = x[i]*mp mod DV
  3666.             var j = x[i] & 0x7fff;
  3667.             var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
  3668.             // use am to combine the multiply-shift-add into one call
  3669.             j = i + this.m.t;
  3670.             x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
  3671.             // propagate carry
  3672.             while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
  3673.         }
  3674.         x.clamp();
  3675.         x.drShiftTo(this.m.t, x);
  3676.         if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
  3677.     };
  3678.     // r = "xy/R mod m"; x,y != r
  3679.     Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
  3680.     // r = "x^2/R mod m"; x != r
  3681.     Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
  3682.  
  3683.  
  3684.  
  3685.  
  3686.  
  3687.     // A "null" reducer
  3688.     var NullExp = window.NullExp = function NullExp() { }
  3689.     NullExp.prototype.convert = function (x) { return x; };
  3690.     NullExp.prototype.revert = function (x) { return x; };
  3691.     NullExp.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); };
  3692.     NullExp.prototype.sqrTo = function (x, r) { x.squareTo(r); };
  3693.  
  3694.  
  3695.  
  3696.  
  3697.  
  3698.     // Barrett modular reduction
  3699.     var Barrett = window.Barrett = function Barrett(m) {
  3700.         // setup Barrett
  3701.         this.r2 = nbi();
  3702.         this.q3 = nbi();
  3703.         BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
  3704.         this.mu = this.r2.divide(m);
  3705.         this.m = m;
  3706.     }
  3707.     Barrett.prototype.convert = function (x) {
  3708.         if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
  3709.         else if (x.compareTo(this.m) < 0) return x;
  3710.         else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
  3711.     };
  3712.     Barrett.prototype.revert = function (x) { return x; };
  3713.     // x = x mod m (HAC 14.42)
  3714.     Barrett.prototype.reduce = function (x) {
  3715.         x.drShiftTo(this.m.t - 1, this.r2);
  3716.         if (x.t > this.m.t + 1) { x.t = this.m.t + 1; x.clamp(); }
  3717.         this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
  3718.         this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
  3719.         while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
  3720.         x.subTo(this.r2, x);
  3721.         while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
  3722.     };
  3723.     // r = x*y mod m; x,y != r
  3724.     Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); };
  3725.     // r = x^2 mod m; x != r
  3726.     Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); };
  3727.  
  3728. })();
  3729.     </script>
  3730.     <script type="text/javascript">
  3731. //---------------------------------------------------------------------
  3732. // QRCode for JavaScript
  3733. //
  3734. // Copyright (c) 2009 Kazuhiko Arase
  3735. //
  3736. // URL: http://www.d-project.com/
  3737. //
  3738. // Licensed under the MIT license:
  3739. //   http://www.opensource.org/licenses/mit-license.php
  3740. //
  3741. // The word "QR Code" is registered trademark of
  3742. // DENSO WAVE INCORPORATED
  3743. //   http://www.denso-wave.com/qrcode/faqpatent-e.html
  3744. //
  3745. //---------------------------------------------------------------------
  3746.  
  3747. (function () {
  3748.     //---------------------------------------------------------------------
  3749.     // QRCode
  3750.     //---------------------------------------------------------------------
  3751.  
  3752.     var QRCode = window.QRCode = function (typeNumber, errorCorrectLevel) {
  3753.         this.typeNumber = typeNumber;
  3754.         this.errorCorrectLevel = errorCorrectLevel;
  3755.         this.modules = null;
  3756.         this.moduleCount = 0;
  3757.         this.dataCache = null;
  3758.         this.dataList = new Array();
  3759.     }
  3760.  
  3761.     QRCode.prototype = {
  3762.  
  3763.         addData: function (data) {
  3764.             var newData = new QRCode.QR8bitByte(data);
  3765.             this.dataList.push(newData);
  3766.             this.dataCache = null;
  3767.         },
  3768.  
  3769.         isDark: function (row, col) {
  3770.             if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
  3771.                 throw new Error(row + "," + col);
  3772.             }
  3773.             return this.modules[row][col];
  3774.         },
  3775.  
  3776.         getModuleCount: function () {
  3777.             return this.moduleCount;
  3778.         },
  3779.  
  3780.         make: function () {
  3781.             this.makeImpl(false, this.getBestMaskPattern());
  3782.         },
  3783.  
  3784.         makeImpl: function (test, maskPattern) {
  3785.  
  3786.             this.moduleCount = this.typeNumber * 4 + 17;
  3787.             this.modules = new Array(this.moduleCount);
  3788.  
  3789.             for (var row = 0; row < this.moduleCount; row++) {
  3790.  
  3791.                 this.modules[row] = new Array(this.moduleCount);
  3792.  
  3793.                 for (var col = 0; col < this.moduleCount; col++) {
  3794.                     this.modules[row][col] = null; //(col + row) % 3;
  3795.                 }
  3796.             }
  3797.  
  3798.             this.setupPositionProbePattern(0, 0);
  3799.             this.setupPositionProbePattern(this.moduleCount - 7, 0);
  3800.             this.setupPositionProbePattern(0, this.moduleCount - 7);
  3801.             this.setupPositionAdjustPattern();
  3802.             this.setupTimingPattern();
  3803.             this.setupTypeInfo(test, maskPattern);
  3804.  
  3805.             if (this.typeNumber >= 7) {
  3806.                 this.setupTypeNumber(test);
  3807.             }
  3808.  
  3809.             if (this.dataCache == null) {
  3810.                 this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
  3811.             }
  3812.  
  3813.             this.mapData(this.dataCache, maskPattern);
  3814.         },
  3815.  
  3816.         setupPositionProbePattern: function (row, col) {
  3817.  
  3818.             for (var r = -1; r <= 7; r++) {
  3819.  
  3820.                 if (row + r <= -1 || this.moduleCount <= row + r) continue;
  3821.  
  3822.                 for (var c = -1; c <= 7; c++) {
  3823.  
  3824.                     if (col + c <= -1 || this.moduleCount <= col + c) continue;
  3825.  
  3826.                     if ((0 <= r && r <= 6 && (c == 0 || c == 6))
  3827.                         || (0 <= c && c <= 6 && (r == 0 || r == 6))
  3828.                         || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
  3829.                         this.modules[row + r][col + c] = true;
  3830.                     } else {
  3831.                         this.modules[row + r][col + c] = false;
  3832.                     }
  3833.                 }
  3834.             }
  3835.         },
  3836.  
  3837.         getBestMaskPattern: function () {
  3838.  
  3839.             var minLostPoint = 0;
  3840.             var pattern = 0;
  3841.  
  3842.             for (var i = 0; i < 8; i++) {
  3843.  
  3844.                 this.makeImpl(true, i);
  3845.  
  3846.                 var lostPoint = QRCode.Util.getLostPoint(this);
  3847.  
  3848.                 if (i == 0 || minLostPoint > lostPoint) {
  3849.                     minLostPoint = lostPoint;
  3850.                     pattern = i;
  3851.                 }
  3852.             }
  3853.  
  3854.             return pattern;
  3855.         },
  3856.  
  3857.         createMovieClip: function (target_mc, instance_name, depth) {
  3858.  
  3859.             var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
  3860.             var cs = 1;
  3861.  
  3862.             this.make();
  3863.  
  3864.             for (var row = 0; row < this.modules.length; row++) {
  3865.  
  3866.                 var y = row * cs;
  3867.  
  3868.                 for (var col = 0; col < this.modules[row].length; col++) {
  3869.  
  3870.                     var x = col * cs;
  3871.                     var dark = this.modules[row][col];
  3872.  
  3873.                     if (dark) {
  3874.                         qr_mc.beginFill(0, 100);
  3875.                         qr_mc.moveTo(x, y);
  3876.                         qr_mc.lineTo(x + cs, y);
  3877.                         qr_mc.lineTo(x + cs, y + cs);
  3878.                         qr_mc.lineTo(x, y + cs);
  3879.                         qr_mc.endFill();
  3880.                     }
  3881.                 }
  3882.             }
  3883.  
  3884.             return qr_mc;
  3885.         },
  3886.  
  3887.         setupTimingPattern: function () {
  3888.  
  3889.             for (var r = 8; r < this.moduleCount - 8; r++) {
  3890.                 if (this.modules[r][6] != null) {
  3891.                     continue;
  3892.                 }
  3893.                 this.modules[r][6] = (r % 2 == 0);
  3894.             }
  3895.  
  3896.             for (var c = 8; c < this.moduleCount - 8; c++) {
  3897.                 if (this.modules[6][c] != null) {
  3898.                     continue;
  3899.                 }
  3900.                 this.modules[6][c] = (c % 2 == 0);
  3901.             }
  3902.         },
  3903.  
  3904.         setupPositionAdjustPattern: function () {
  3905.  
  3906.             var pos = QRCode.Util.getPatternPosition(this.typeNumber);
  3907.  
  3908.             for (var i = 0; i < pos.length; i++) {
  3909.  
  3910.                 for (var j = 0; j < pos.length; j++) {
  3911.  
  3912.                     var row = pos[i];
  3913.                     var col = pos[j];
  3914.  
  3915.                     if (this.modules[row][col] != null) {
  3916.                         continue;
  3917.                     }
  3918.  
  3919.                     for (var r = -2; r <= 2; r++) {
  3920.  
  3921.                         for (var c = -2; c <= 2; c++) {
  3922.  
  3923.                             if (r == -2 || r == 2 || c == -2 || c == 2
  3924.                                 || (r == 0 && c == 0)) {
  3925.                                 this.modules[row + r][col + c] = true;
  3926.                             } else {
  3927.                                 this.modules[row + r][col + c] = false;
  3928.                             }
  3929.                         }
  3930.                     }
  3931.                 }
  3932.             }
  3933.         },
  3934.  
  3935.         setupTypeNumber: function (test) {
  3936.  
  3937.             var bits = QRCode.Util.getBCHTypeNumber(this.typeNumber);
  3938.  
  3939.             for (var i = 0; i < 18; i++) {
  3940.                 var mod = (!test && ((bits >> i) & 1) == 1);
  3941.                 this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
  3942.             }
  3943.  
  3944.             for (var i = 0; i < 18; i++) {
  3945.                 var mod = (!test && ((bits >> i) & 1) == 1);
  3946.                 this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
  3947.             }
  3948.         },
  3949.  
  3950.         setupTypeInfo: function (test, maskPattern) {
  3951.  
  3952.             var data = (this.errorCorrectLevel << 3) | maskPattern;
  3953.             var bits = QRCode.Util.getBCHTypeInfo(data);
  3954.  
  3955.             // vertical    
  3956.             for (var i = 0; i < 15; i++) {
  3957.  
  3958.                 var mod = (!test && ((bits >> i) & 1) == 1);
  3959.  
  3960.                 if (i < 6) {
  3961.                     this.modules[i][8] = mod;
  3962.                 } else if (i < 8) {
  3963.                     this.modules[i + 1][8] = mod;
  3964.                 } else {
  3965.                     this.modules[this.moduleCount - 15 + i][8] = mod;
  3966.                 }
  3967.             }
  3968.  
  3969.             // horizontal
  3970.             for (var i = 0; i < 15; i++) {
  3971.  
  3972.                 var mod = (!test && ((bits >> i) & 1) == 1);
  3973.  
  3974.                 if (i < 8) {
  3975.                     this.modules[8][this.moduleCount - i - 1] = mod;
  3976.                 } else if (i < 9) {
  3977.                     this.modules[8][15 - i - 1 + 1] = mod;
  3978.                 } else {
  3979.                     this.modules[8][15 - i - 1] = mod;
  3980.                 }
  3981.             }
  3982.  
  3983.             // fixed module
  3984.             this.modules[this.moduleCount - 8][8] = (!test);
  3985.  
  3986.         },
  3987.  
  3988.         mapData: function (data, maskPattern) {
  3989.  
  3990.             var inc = -1;
  3991.             var row = this.moduleCount - 1;
  3992.             var bitIndex = 7;
  3993.             var byteIndex = 0;
  3994.  
  3995.             for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  3996.  
  3997.                 if (col == 6) col--;
  3998.  
  3999.                 while (true) {
  4000.  
  4001.                     for (var c = 0; c < 2; c++) {
  4002.  
  4003.                         if (this.modules[row][col - c] == null) {
  4004.  
  4005.                             var dark = false;
  4006.  
  4007.                             if (byteIndex < data.length) {
  4008.                                 dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
  4009.                             }
  4010.  
  4011.                             var mask = QRCode.Util.getMask(maskPattern, row, col - c);
  4012.  
  4013.                             if (mask) {
  4014.                                 dark = !dark;
  4015.                             }
  4016.  
  4017.                             this.modules[row][col - c] = dark;
  4018.                             bitIndex--;
  4019.  
  4020.                             if (bitIndex == -1) {
  4021.                                 byteIndex++;
  4022.                                 bitIndex = 7;
  4023.                             }
  4024.                         }
  4025.                     }
  4026.  
  4027.                     row += inc;
  4028.  
  4029.                     if (row < 0 || this.moduleCount <= row) {
  4030.                         row -= inc;
  4031.                         inc = -inc;
  4032.                         break;
  4033.                     }
  4034.                 }
  4035.             }
  4036.  
  4037.         }
  4038.  
  4039.     };
  4040.  
  4041.     QRCode.PAD0 = 0xEC;
  4042.     QRCode.PAD1 = 0x11;
  4043.  
  4044.     QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) {
  4045.  
  4046.         var rsBlocks = QRCode.RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  4047.  
  4048.         var buffer = new QRCode.BitBuffer();
  4049.  
  4050.         for (var i = 0; i < dataList.length; i++) {
  4051.             var data = dataList[i];
  4052.             buffer.put(data.mode, 4);
  4053.             buffer.put(data.getLength(), QRCode.Util.getLengthInBits(data.mode, typeNumber));
  4054.             data.write(buffer);
  4055.         }
  4056.  
  4057.         // calc num max data.
  4058.         var totalDataCount = 0;
  4059.         for (var i = 0; i < rsBlocks.length; i++) {
  4060.             totalDataCount += rsBlocks[i].dataCount;
  4061.         }
  4062.  
  4063.         if (buffer.getLengthInBits() > totalDataCount * 8) {
  4064.             throw new Error("code length overflow. ("
  4065.             + buffer.getLengthInBits()
  4066.             + ">"
  4067.             + totalDataCount * 8
  4068.             + ")");
  4069.         }
  4070.  
  4071.         // end code
  4072.         if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  4073.             buffer.put(0, 4);
  4074.         }
  4075.  
  4076.         // padding
  4077.         while (buffer.getLengthInBits() % 8 != 0) {
  4078.             buffer.putBit(false);
  4079.         }
  4080.  
  4081.         // padding
  4082.         while (true) {
  4083.  
  4084.             if (buffer.getLengthInBits() >= totalDataCount * 8) {
  4085.                 break;
  4086.             }
  4087.             buffer.put(QRCode.PAD0, 8);
  4088.  
  4089.             if (buffer.getLengthInBits() >= totalDataCount * 8) {
  4090.                 break;
  4091.             }
  4092.             buffer.put(QRCode.PAD1, 8);
  4093.         }
  4094.  
  4095.         return QRCode.createBytes(buffer, rsBlocks);
  4096.     };
  4097.  
  4098.     QRCode.createBytes = function (buffer, rsBlocks) {
  4099.  
  4100.         var offset = 0;
  4101.  
  4102.         var maxDcCount = 0;
  4103.         var maxEcCount = 0;
  4104.  
  4105.         var dcdata = new Array(rsBlocks.length);
  4106.         var ecdata = new Array(rsBlocks.length);
  4107.  
  4108.         for (var r = 0; r < rsBlocks.length; r++) {
  4109.  
  4110.             var dcCount = rsBlocks[r].dataCount;
  4111.             var ecCount = rsBlocks[r].totalCount - dcCount;
  4112.  
  4113.             maxDcCount = Math.max(maxDcCount, dcCount);
  4114.             maxEcCount = Math.max(maxEcCount, ecCount);
  4115.  
  4116.             dcdata[r] = new Array(dcCount);
  4117.  
  4118.             for (var i = 0; i < dcdata[r].length; i++) {
  4119.                 dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  4120.             }
  4121.             offset += dcCount;
  4122.  
  4123.             var rsPoly = QRCode.Util.getErrorCorrectPolynomial(ecCount);
  4124.             var rawPoly = new QRCode.Polynomial(dcdata[r], rsPoly.getLength() - 1);
  4125.  
  4126.             var modPoly = rawPoly.mod(rsPoly);
  4127.             ecdata[r] = new Array(rsPoly.getLength() - 1);
  4128.             for (var i = 0; i < ecdata[r].length; i++) {
  4129.                 var modIndex = i + modPoly.getLength() - ecdata[r].length;
  4130.                 ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
  4131.             }
  4132.  
  4133.         }
  4134.  
  4135.         var totalCodeCount = 0;
  4136.         for (var i = 0; i < rsBlocks.length; i++) {
  4137.             totalCodeCount += rsBlocks[i].totalCount;
  4138.         }
  4139.  
  4140.         var data = new Array(totalCodeCount);
  4141.         var index = 0;
  4142.  
  4143.         for (var i = 0; i < maxDcCount; i++) {
  4144.             for (var r = 0; r < rsBlocks.length; r++) {
  4145.                 if (i < dcdata[r].length) {
  4146.                     data[index++] = dcdata[r][i];
  4147.                 }
  4148.             }
  4149.         }
  4150.  
  4151.         for (var i = 0; i < maxEcCount; i++) {
  4152.             for (var r = 0; r < rsBlocks.length; r++) {
  4153.                 if (i < ecdata[r].length) {
  4154.                     data[index++] = ecdata[r][i];
  4155.                 }
  4156.             }
  4157.         }
  4158.  
  4159.         return data;
  4160.  
  4161.     };
  4162.  
  4163.     //---------------------------------------------------------------------
  4164.     // QR8bitByte
  4165.     //---------------------------------------------------------------------
  4166.     QRCode.QR8bitByte = function (data) {
  4167.         this.mode = QRCode.Mode.MODE_8BIT_BYTE;
  4168.         this.data = data;
  4169.     }
  4170.  
  4171.     QRCode.QR8bitByte.prototype = {
  4172.         getLength: function (buffer) {
  4173.             return this.data.length;
  4174.         },
  4175.  
  4176.         write: function (buffer) {
  4177.             for (var i = 0; i < this.data.length; i++) {
  4178.                 // not JIS ...
  4179.                 buffer.put(this.data.charCodeAt(i), 8);
  4180.             }
  4181.         }
  4182.     };
  4183.  
  4184.  
  4185.     //---------------------------------------------------------------------
  4186.     // QRMode
  4187.     //---------------------------------------------------------------------
  4188.     QRCode.Mode = {
  4189.         MODE_NUMBER: 1 << 0,
  4190.         MODE_ALPHA_NUM: 1 << 1,
  4191.         MODE_8BIT_BYTE: 1 << 2,
  4192.         MODE_KANJI: 1 << 3
  4193.     };
  4194.  
  4195.     //---------------------------------------------------------------------
  4196.     // QRErrorCorrectLevel
  4197.     //---------------------------------------------------------------------
  4198.     QRCode.ErrorCorrectLevel = {
  4199.         L: 1,
  4200.         M: 0,
  4201.         Q: 3,
  4202.         H: 2
  4203.     };
  4204.  
  4205.  
  4206.     //---------------------------------------------------------------------
  4207.     // QRMaskPattern
  4208.     //---------------------------------------------------------------------
  4209.     QRCode.MaskPattern = {
  4210.         PATTERN000: 0,
  4211.         PATTERN001: 1,
  4212.         PATTERN010: 2,
  4213.         PATTERN011: 3,
  4214.         PATTERN100: 4,
  4215.         PATTERN101: 5,
  4216.         PATTERN110: 6,
  4217.         PATTERN111: 7
  4218.     };
  4219.  
  4220.     //---------------------------------------------------------------------
  4221.     // QRUtil
  4222.     //---------------------------------------------------------------------
  4223.  
  4224.     QRCode.Util = {
  4225.  
  4226.         PATTERN_POSITION_TABLE: [
  4227.         [],
  4228.         [6, 18],
  4229.         [6, 22],
  4230.         [6, 26],
  4231.         [6, 30],
  4232.         [6, 34],
  4233.         [6, 22, 38],
  4234.         [6, 24, 42],
  4235.         [6, 26, 46],
  4236.         [6, 28, 50],
  4237.         [6, 30, 54],
  4238.         [6, 32, 58],
  4239.         [6, 34, 62],
  4240.         [6, 26, 46, 66],
  4241.         [6, 26, 48, 70],
  4242.         [6, 26, 50, 74],
  4243.         [6, 30, 54, 78],
  4244.         [6, 30, 56, 82],
  4245.         [6, 30, 58, 86],
  4246.         [6, 34, 62, 90],
  4247.         [6, 28, 50, 72, 94],
  4248.         [6, 26, 50, 74, 98],
  4249.         [6, 30, 54, 78, 102],
  4250.         [6, 28, 54, 80, 106],
  4251.         [6, 32, 58, 84, 110],
  4252.         [6, 30, 58, 86, 114],
  4253.         [6, 34, 62, 90, 118],
  4254.         [6, 26, 50, 74, 98, 122],
  4255.         [6, 30, 54, 78, 102, 126],
  4256.         [6, 26, 52, 78, 104, 130],
  4257.         [6, 30, 56, 82, 108, 134],
  4258.         [6, 34, 60, 86, 112, 138],
  4259.         [6, 30, 58, 86, 114, 142],
  4260.         [6, 34, 62, 90, 118, 146],
  4261.         [6, 30, 54, 78, 102, 126, 150],
  4262.         [6, 24, 50, 76, 102, 128, 154],
  4263.         [6, 28, 54, 80, 106, 132, 158],
  4264.         [6, 32, 58, 84, 110, 136, 162],
  4265.         [6, 26, 54, 82, 110, 138, 166],
  4266.         [6, 30, 58, 86, 114, 142, 170]
  4267.     ],
  4268.  
  4269.         G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
  4270.         G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
  4271.         G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
  4272.  
  4273.         getBCHTypeInfo: function (data) {
  4274.             var d = data << 10;
  4275.             while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15) >= 0) {
  4276.                 d ^= (QRCode.Util.G15 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G15)));
  4277.             }
  4278.             return ((data << 10) | d) ^ QRCode.Util.G15_MASK;
  4279.         },
  4280.  
  4281.         getBCHTypeNumber: function (data) {
  4282.             var d = data << 12;
  4283.             while (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18) >= 0) {
  4284.                 d ^= (QRCode.Util.G18 << (QRCode.Util.getBCHDigit(d) - QRCode.Util.getBCHDigit(QRCode.Util.G18)));
  4285.             }
  4286.             return (data << 12) | d;
  4287.         },
  4288.  
  4289.         getBCHDigit: function (data) {
  4290.  
  4291.             var digit = 0;
  4292.  
  4293.             while (data != 0) {
  4294.                 digit++;
  4295.                 data >>>= 1;
  4296.             }
  4297.  
  4298.             return digit;
  4299.         },
  4300.  
  4301.         getPatternPosition: function (typeNumber) {
  4302.             return QRCode.Util.PATTERN_POSITION_TABLE[typeNumber - 1];
  4303.         },
  4304.  
  4305.         getMask: function (maskPattern, i, j) {
  4306.  
  4307.             switch (maskPattern) {
  4308.  
  4309.                 case QRCode.MaskPattern.PATTERN000: return (i + j) % 2 == 0;
  4310.                 case QRCode.MaskPattern.PATTERN001: return i % 2 == 0;
  4311.                 case QRCode.MaskPattern.PATTERN010: return j % 3 == 0;
  4312.                 case QRCode.MaskPattern.PATTERN011: return (i + j) % 3 == 0;
  4313.                 case QRCode.MaskPattern.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  4314.                 case QRCode.MaskPattern.PATTERN101: return (i * j) % 2 + (i * j) % 3 == 0;
  4315.                 case QRCode.MaskPattern.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
  4316.                 case QRCode.MaskPattern.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
  4317.  
  4318.                 default:
  4319.                     throw new Error("bad maskPattern:" + maskPattern);
  4320.             }
  4321.         },
  4322.  
  4323.         getErrorCorrectPolynomial: function (errorCorrectLength) {
  4324.  
  4325.             var a = new QRCode.Polynomial([1], 0);
  4326.  
  4327.             for (var i = 0; i < errorCorrectLength; i++) {
  4328.                 a = a.multiply(new QRCode.Polynomial([1, QRCode.Math.gexp(i)], 0));
  4329.             }
  4330.  
  4331.             return a;
  4332.         },
  4333.  
  4334.         getLengthInBits: function (mode, type) {
  4335.  
  4336.             if (1 <= type && type < 10) {
  4337.  
  4338.                 // 1 - 9
  4339.  
  4340.                 switch (mode) {
  4341.                     case QRCode.Mode.MODE_NUMBER: return 10;
  4342.                     case QRCode.Mode.MODE_ALPHA_NUM: return 9;
  4343.                     case QRCode.Mode.MODE_8BIT_BYTE: return 8;
  4344.                     case QRCode.Mode.MODE_KANJI: return 8;
  4345.                     default:
  4346.                         throw new Error("mode:" + mode);
  4347.                 }
  4348.  
  4349.             } else if (type < 27) {
  4350.  
  4351.                 // 10 - 26
  4352.  
  4353.                 switch (mode) {
  4354.                     case QRCode.Mode.MODE_NUMBER: return 12;
  4355.                     case QRCode.Mode.MODE_ALPHA_NUM: return 11;
  4356.                     case QRCode.Mode.MODE_8BIT_BYTE: return 16;
  4357.                     case QRCode.Mode.MODE_KANJI: return 10;
  4358.                     default:
  4359.                         throw new Error("mode:" + mode);
  4360.                 }
  4361.  
  4362.             } else if (type < 41) {
  4363.  
  4364.                 // 27 - 40
  4365.  
  4366.                 switch (mode) {
  4367.                     case QRCode.Mode.MODE_NUMBER: return 14;
  4368.                     case QRCode.Mode.MODE_ALPHA_NUM: return 13;
  4369.                     case QRCode.Mode.MODE_8BIT_BYTE: return 16;
  4370.                     case QRCode.Mode.MODE_KANJI: return 12;
  4371.                     default:
  4372.                         throw new Error("mode:" + mode);
  4373.                 }
  4374.  
  4375.             } else {
  4376.                 throw new Error("type:" + type);
  4377.             }
  4378.         },
  4379.  
  4380.         getLostPoint: function (qrCode) {
  4381.  
  4382.             var moduleCount = qrCode.getModuleCount();
  4383.  
  4384.             var lostPoint = 0;
  4385.  
  4386.             // LEVEL1
  4387.  
  4388.             for (var row = 0; row < moduleCount; row++) {
  4389.  
  4390.                 for (var col = 0; col < moduleCount; col++) {
  4391.  
  4392.                     var sameCount = 0;
  4393.                     var dark = qrCode.isDark(row, col);
  4394.  
  4395.                     for (var r = -1; r <= 1; r++) {
  4396.  
  4397.                         if (row + r < 0 || moduleCount <= row + r) {
  4398.                             continue;
  4399.                         }
  4400.  
  4401.                         for (var c = -1; c <= 1; c++) {
  4402.  
  4403.                             if (col + c < 0 || moduleCount <= col + c) {
  4404.                                 continue;
  4405.                             }
  4406.  
  4407.                             if (r == 0 && c == 0) {
  4408.                                 continue;
  4409.                             }
  4410.  
  4411.                             if (dark == qrCode.isDark(row + r, col + c)) {
  4412.                                 sameCount++;
  4413.                             }
  4414.                         }
  4415.                     }
  4416.  
  4417.                     if (sameCount > 5) {
  4418.                         lostPoint += (3 + sameCount - 5);
  4419.                     }
  4420.                 }
  4421.             }
  4422.  
  4423.             // LEVEL2
  4424.  
  4425.             for (var row = 0; row < moduleCount - 1; row++) {
  4426.                 for (var col = 0; col < moduleCount - 1; col++) {
  4427.                     var count = 0;
  4428.                     if (qrCode.isDark(row, col)) count++;
  4429.                     if (qrCode.isDark(row + 1, col)) count++;
  4430.                     if (qrCode.isDark(row, col + 1)) count++;
  4431.                     if (qrCode.isDark(row + 1, col + 1)) count++;
  4432.                     if (count == 0 || count == 4) {
  4433.                         lostPoint += 3;
  4434.                     }
  4435.                 }
  4436.             }
  4437.  
  4438.             // LEVEL3
  4439.  
  4440.             for (var row = 0; row < moduleCount; row++) {
  4441.                 for (var col = 0; col < moduleCount - 6; col++) {
  4442.                     if (qrCode.isDark(row, col)
  4443.                         && !qrCode.isDark(row, col + 1)
  4444.                         && qrCode.isDark(row, col + 2)
  4445.                         && qrCode.isDark(row, col + 3)
  4446.                         && qrCode.isDark(row, col + 4)
  4447.                         && !qrCode.isDark(row, col + 5)
  4448.                         && qrCode.isDark(row, col + 6)) {
  4449.                         lostPoint += 40;
  4450.                     }
  4451.                 }
  4452.             }
  4453.  
  4454.             for (var col = 0; col < moduleCount; col++) {
  4455.                 for (var row = 0; row < moduleCount - 6; row++) {
  4456.                     if (qrCode.isDark(row, col)
  4457.                         && !qrCode.isDark(row + 1, col)
  4458.                         && qrCode.isDark(row + 2, col)
  4459.                         && qrCode.isDark(row + 3, col)
  4460.                         && qrCode.isDark(row + 4, col)
  4461.                         && !qrCode.isDark(row + 5, col)
  4462.                         && qrCode.isDark(row + 6, col)) {
  4463.                         lostPoint += 40;
  4464.                     }
  4465.                 }
  4466.             }
  4467.  
  4468.             // LEVEL4
  4469.  
  4470.             var darkCount = 0;
  4471.  
  4472.             for (var col = 0; col < moduleCount; col++) {
  4473.                 for (var row = 0; row < moduleCount; row++) {
  4474.                     if (qrCode.isDark(row, col)) {
  4475.                         darkCount++;
  4476.                     }
  4477.                 }
  4478.             }
  4479.  
  4480.             var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
  4481.             lostPoint += ratio * 10;
  4482.  
  4483.             return lostPoint;
  4484.         }
  4485.  
  4486.     };
  4487.  
  4488.  
  4489.     //---------------------------------------------------------------------
  4490.     // QRMath
  4491.     //---------------------------------------------------------------------
  4492.  
  4493.     QRCode.Math = {
  4494.  
  4495.         glog: function (n) {
  4496.  
  4497.             if (n < 1) {
  4498.                 throw new Error("glog(" + n + ")");
  4499.             }
  4500.  
  4501.             return QRCode.Math.LOG_TABLE[n];
  4502.         },
  4503.  
  4504.         gexp: function (n) {
  4505.  
  4506.             while (n < 0) {
  4507.                 n += 255;
  4508.             }
  4509.  
  4510.             while (n >= 256) {
  4511.                 n -= 255;
  4512.             }
  4513.  
  4514.             return QRCode.Math.EXP_TABLE[n];
  4515.         },
  4516.  
  4517.         EXP_TABLE: new Array(256),
  4518.  
  4519.         LOG_TABLE: new Array(256)
  4520.  
  4521.     };
  4522.  
  4523.     for (var i = 0; i < 8; i++) {
  4524.         QRCode.Math.EXP_TABLE[i] = 1 << i;
  4525.     }
  4526.     for (var i = 8; i < 256; i++) {
  4527.         QRCode.Math.EXP_TABLE[i] = QRCode.Math.EXP_TABLE[i - 4]
  4528.         ^ QRCode.Math.EXP_TABLE[i - 5]
  4529.         ^ QRCode.Math.EXP_TABLE[i - 6]
  4530.         ^ QRCode.Math.EXP_TABLE[i - 8];
  4531.     }
  4532.     for (var i = 0; i < 255; i++) {
  4533.         QRCode.Math.LOG_TABLE[QRCode.Math.EXP_TABLE[i]] = i;
  4534.     }
  4535.  
  4536.     //---------------------------------------------------------------------
  4537.     // QRPolynomial
  4538.     //---------------------------------------------------------------------
  4539.  
  4540.     QRCode.Polynomial = function (num, shift) {
  4541.  
  4542.         if (num.length == undefined) {
  4543.             throw new Error(num.length + "/" + shift);
  4544.         }
  4545.  
  4546.         var offset = 0;
  4547.  
  4548.         while (offset < num.length && num[offset] == 0) {
  4549.             offset++;
  4550.         }
  4551.  
  4552.         this.num = new Array(num.length - offset + shift);
  4553.         for (var i = 0; i < num.length - offset; i++) {
  4554.             this.num[i] = num[i + offset];
  4555.         }
  4556.     }
  4557.  
  4558.     QRCode.Polynomial.prototype = {
  4559.  
  4560.         get: function (index) {
  4561.             return this.num[index];
  4562.         },
  4563.  
  4564.         getLength: function () {
  4565.             return this.num.length;
  4566.         },
  4567.  
  4568.         multiply: function (e) {
  4569.  
  4570.             var num = new Array(this.getLength() + e.getLength() - 1);
  4571.  
  4572.             for (var i = 0; i < this.getLength(); i++) {
  4573.                 for (var j = 0; j < e.getLength(); j++) {
  4574.                     num[i + j] ^= QRCode.Math.gexp(QRCode.Math.glog(this.get(i)) + QRCode.Math.glog(e.get(j)));
  4575.                 }
  4576.             }
  4577.  
  4578.             return new QRCode.Polynomial(num, 0);
  4579.         },
  4580.  
  4581.         mod: function (e) {
  4582.  
  4583.             if (this.getLength() - e.getLength() < 0) {
  4584.                 return this;
  4585.             }
  4586.  
  4587.             var ratio = QRCode.Math.glog(this.get(0)) - QRCode.Math.glog(e.get(0));
  4588.  
  4589.             var num = new Array(this.getLength());
  4590.  
  4591.             for (var i = 0; i < this.getLength(); i++) {
  4592.                 num[i] = this.get(i);
  4593.             }
  4594.  
  4595.             for (var i = 0; i < e.getLength(); i++) {
  4596.                 num[i] ^= QRCode.Math.gexp(QRCode.Math.glog(e.get(i)) + ratio);
  4597.             }
  4598.  
  4599.             // recursive call
  4600.             return new QRCode.Polynomial(num, 0).mod(e);
  4601.         }
  4602.     };
  4603.  
  4604.     //---------------------------------------------------------------------
  4605.     // QRRSBlock
  4606.     //---------------------------------------------------------------------
  4607.  
  4608.     QRCode.RSBlock = function (totalCount, dataCount) {
  4609.         this.totalCount = totalCount;
  4610.         this.dataCount = dataCount;
  4611.     }
  4612.  
  4613.     QRCode.RSBlock.RS_BLOCK_TABLE = [
  4614.  
  4615.     // L
  4616.     // M
  4617.     // Q
  4618.     // H
  4619.  
  4620.     // 1
  4621.     [1, 26, 19],
  4622.     [1, 26, 16],
  4623.     [1, 26, 13],
  4624.     [1, 26, 9],
  4625.  
  4626.     // 2
  4627.     [1, 44, 34],
  4628.     [1, 44, 28],
  4629.     [1, 44, 22],
  4630.     [1, 44, 16],
  4631.  
  4632.     // 3
  4633.     [1, 70, 55],
  4634.     [1, 70, 44],
  4635.     [2, 35, 17],
  4636.     [2, 35, 13],
  4637.  
  4638.     // 4       
  4639.     [1, 100, 80],
  4640.     [2, 50, 32],
  4641.     [2, 50, 24],
  4642.     [4, 25, 9],
  4643.  
  4644.     // 5
  4645.     [1, 134, 108],
  4646.     [2, 67, 43],
  4647.     [2, 33, 15, 2, 34, 16],
  4648.     [2, 33, 11, 2, 34, 12],
  4649.  
  4650.     // 6
  4651.     [2, 86, 68],
  4652.     [4, 43, 27],
  4653.     [4, 43, 19],
  4654.     [4, 43, 15],
  4655.  
  4656.     // 7       
  4657.     [2, 98, 78],
  4658.     [4, 49, 31],
  4659.     [2, 32, 14, 4, 33, 15],
  4660.     [4, 39, 13, 1, 40, 14],
  4661.  
  4662.     // 8
  4663.     [2, 121, 97],
  4664.     [2, 60, 38, 2, 61, 39],
  4665.     [4, 40, 18, 2, 41, 19],
  4666.     [4, 40, 14, 2, 41, 15],
  4667.  
  4668.     // 9
  4669.     [2, 146, 116],
  4670.     [3, 58, 36, 2, 59, 37],
  4671.     [4, 36, 16, 4, 37, 17],
  4672.     [4, 36, 12, 4, 37, 13],
  4673.  
  4674.     // 10      
  4675.     [2, 86, 68, 2, 87, 69],
  4676.     [4, 69, 43, 1, 70, 44],
  4677.     [6, 43, 19, 2, 44, 20],
  4678.     [6, 43, 15, 2, 44, 16]
  4679.  
  4680. ];
  4681.  
  4682.     QRCode.RSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
  4683.  
  4684.         var rsBlock = QRCode.RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
  4685.  
  4686.         if (rsBlock == undefined) {
  4687.             throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
  4688.         }
  4689.  
  4690.         var length = rsBlock.length / 3;
  4691.  
  4692.         var list = new Array();
  4693.  
  4694.         for (var i = 0; i < length; i++) {
  4695.  
  4696.             var count = rsBlock[i * 3 + 0];
  4697.             var totalCount = rsBlock[i * 3 + 1];
  4698.             var dataCount = rsBlock[i * 3 + 2];
  4699.  
  4700.             for (var j = 0; j < count; j++) {
  4701.                 list.push(new QRCode.RSBlock(totalCount, dataCount));
  4702.             }
  4703.         }
  4704.  
  4705.         return list;
  4706.     };
  4707.  
  4708.     QRCode.RSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
  4709.  
  4710.         switch (errorCorrectLevel) {
  4711.             case QRCode.ErrorCorrectLevel.L:
  4712.                 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  4713.             case QRCode.ErrorCorrectLevel.M:
  4714.                 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  4715.             case QRCode.ErrorCorrectLevel.Q:
  4716.                 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  4717.             case QRCode.ErrorCorrectLevel.H:
  4718.                 return QRCode.RSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
  4719.             default:
  4720.                 return undefined;
  4721.         }
  4722.     };
  4723.  
  4724.     //---------------------------------------------------------------------
  4725.     // QRBitBuffer
  4726.     //---------------------------------------------------------------------
  4727.  
  4728.     QRCode.BitBuffer = function () {
  4729.         this.buffer = new Array();
  4730.         this.length = 0;
  4731.     }
  4732.  
  4733.     QRCode.BitBuffer.prototype = {
  4734.  
  4735.         get: function (index) {
  4736.             var bufIndex = Math.floor(index / 8);
  4737.             return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
  4738.         },
  4739.  
  4740.         put: function (num, length) {
  4741.             for (var i = 0; i < length; i++) {
  4742.                 this.putBit(((num >>> (length - i - 1)) & 1) == 1);
  4743.             }
  4744.         },
  4745.  
  4746.         getLengthInBits: function () {
  4747.             return this.length;
  4748.         },
  4749.  
  4750.         putBit: function (bit) {
  4751.  
  4752.             var bufIndex = Math.floor(this.length / 8);
  4753.             if (this.buffer.length <= bufIndex) {
  4754.                 this.buffer.push(0);
  4755.             }
  4756.  
  4757.             if (bit) {
  4758.                 this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
  4759.             }
  4760.  
  4761.             this.length++;
  4762.         }
  4763.     };
  4764. })();
  4765.     </script>
  4766.     <script type="text/javascript">
  4767. /*
  4768. Copyright (c) 2011 Stefan Thomas
  4769.  
  4770. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  4771.  
  4772. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  4773.  
  4774. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  4775. */
  4776.  
  4777. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/1a7fc9d063f864058809d06ef4542af40be3558f/src/bitcoin.js
  4778. (function (exports) {
  4779.     var Bitcoin = exports;
  4780. })(
  4781.     'object' === typeof module ? module.exports : (window.Bitcoin = {})
  4782. );
  4783.     </script>
  4784.     <script type="text/javascript">
  4785. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/c952aaeb3ee472e3776655b8ea07299ebed702c7/src/base58.js
  4786. (function (Bitcoin) {
  4787.     Bitcoin.Base58 = {
  4788.         alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
  4789.         validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
  4790.         base: BigInteger.valueOf(58),
  4791.  
  4792.         /**
  4793.         * Convert a byte array to a base58-encoded string.
  4794.         *
  4795.         * Written by Mike Hearn for BitcoinJ.
  4796.         *   Copyright (c) 2011 Google Inc.
  4797.         *
  4798.         * Ported to JavaScript by Stefan Thomas.
  4799.         */
  4800.         encode: function (input) {
  4801.             var bi = BigInteger.fromByteArrayUnsigned(input);
  4802.             var chars = [];
  4803.  
  4804.             while (bi.compareTo(B58.base) >= 0) {
  4805.                 var mod = bi.mod(B58.base);
  4806.                 chars.unshift(B58.alphabet[mod.intValue()]);
  4807.                 bi = bi.subtract(mod).divide(B58.base);
  4808.             }
  4809.             chars.unshift(B58.alphabet[bi.intValue()]);
  4810.  
  4811.             // Convert leading zeros too.
  4812.             for (var i = 0; i < input.length; i++) {
  4813.                 if (input[i] == 0x00) {
  4814.                     chars.unshift(B58.alphabet[0]);
  4815.                 } else break;
  4816.             }
  4817.  
  4818.             return chars.join('');
  4819.         },
  4820.  
  4821.         /**
  4822.         * Convert a base58-encoded string to a byte array.
  4823.         *
  4824.         * Written by Mike Hearn for BitcoinJ.
  4825.         *   Copyright (c) 2011 Google Inc.
  4826.         *
  4827.         * Ported to JavaScript by Stefan Thomas.
  4828.         */
  4829.         decode: function (input) {
  4830.             var bi = BigInteger.valueOf(0);
  4831.             var leadingZerosNum = 0;
  4832.             for (var i = input.length - 1; i >= 0; i--) {
  4833.                 var alphaIndex = B58.alphabet.indexOf(input[i]);
  4834.                 if (alphaIndex < 0) {
  4835.                     throw "Invalid character";
  4836.                 }
  4837.                 bi = bi.add(BigInteger.valueOf(alphaIndex)
  4838.                                 .multiply(B58.base.pow(input.length - 1 - i)));
  4839.  
  4840.                 // This counts leading zero bytes
  4841.                 if (input[i] == "1") leadingZerosNum++;
  4842.                 else leadingZerosNum = 0;
  4843.             }
  4844.             var bytes = bi.toByteArrayUnsigned();
  4845.  
  4846.             // Add leading zeros
  4847.             while (leadingZerosNum-- > 0) bytes.unshift(0);
  4848.  
  4849.             return bytes;
  4850.         }
  4851.     };
  4852.  
  4853.     var B58 = Bitcoin.Base58;
  4854. })(
  4855.     'undefined' != typeof Bitcoin ? Bitcoin : module.exports
  4856. );
  4857.     </script>
  4858.     <script type="text/javascript">
  4859. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/address.js
  4860. Bitcoin.Address = function (bytes) {
  4861.     if ("string" == typeof bytes) {
  4862.         bytes = Bitcoin.Address.decodeString(bytes);
  4863.     }
  4864.     this.hash = bytes;
  4865.     this.version = Bitcoin.Address.networkVersion;
  4866. };
  4867.  
  4868. Bitcoin.Address.networkVersion = window.networkVersion; // multiple coin support
  4869.  
  4870. /**
  4871. * Serialize this object as a standard Bitcoin address.
  4872. *
  4873. * Returns the address as a base58-encoded string in the standardized format.
  4874. */
  4875. Bitcoin.Address.prototype.toString = function () {
  4876.     // Get a copy of the hash
  4877.     var hash = this.hash.slice(0);
  4878.  
  4879.     // Version
  4880.     hash.unshift(this.version);
  4881.     var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  4882.     var bytes = hash.concat(checksum.slice(0, 4));
  4883.     return Bitcoin.Base58.encode(bytes);
  4884. };
  4885.  
  4886. Bitcoin.Address.prototype.getHashBase64 = function () {
  4887.     return Crypto.util.bytesToBase64(this.hash);
  4888. };
  4889.  
  4890. /**
  4891. * Parse a Bitcoin address contained in a string.
  4892. */
  4893. Bitcoin.Address.decodeString = function (string) {
  4894.     var bytes = Bitcoin.Base58.decode(string);
  4895.     var hash = bytes.slice(0, 21);
  4896.     var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  4897.  
  4898.     if (checksum[0] != bytes[21] ||
  4899.             checksum[1] != bytes[22] ||
  4900.             checksum[2] != bytes[23] ||
  4901.             checksum[3] != bytes[24]) {
  4902.         throw "Checksum validation failed!";
  4903.     }
  4904.  
  4905.     var version = hash.shift();
  4906.  
  4907.     if (version != 0) {
  4908.         throw "Version " + version + " not supported!";
  4909.     }
  4910.  
  4911.     return hash;
  4912. };
  4913.     </script>
  4914.     <script type="text/javascript">
  4915. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/e90780d3d3b8fc0d027d2bcb38b80479902f223e/src/ecdsa.js
  4916. Bitcoin.ECDSA = (function () {
  4917.     var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  4918.     var rng = new SecureRandom();
  4919.  
  4920.     var P_OVER_FOUR = null;
  4921.  
  4922.     function implShamirsTrick(P, k, Q, l) {
  4923.         var m = Math.max(k.bitLength(), l.bitLength());
  4924.         var Z = P.add2D(Q);
  4925.         var R = P.curve.getInfinity();
  4926.  
  4927.         for (var i = m - 1; i >= 0; --i) {
  4928.             R = R.twice2D();
  4929.  
  4930.             R.z = BigInteger.ONE;
  4931.  
  4932.             if (k.testBit(i)) {
  4933.                 if (l.testBit(i)) {
  4934.                     R = R.add2D(Z);
  4935.                 } else {
  4936.                     R = R.add2D(P);
  4937.                 }
  4938.             } else {
  4939.                 if (l.testBit(i)) {
  4940.                     R = R.add2D(Q);
  4941.                 }
  4942.             }
  4943.         }
  4944.  
  4945.         return R;
  4946.     };
  4947.  
  4948.     var ECDSA = {
  4949.         getBigRandom: function (limit) {
  4950.             return new BigInteger(limit.bitLength(), rng)
  4951.                 .mod(limit.subtract(BigInteger.ONE))
  4952.                 .add(BigInteger.ONE);
  4953.         },
  4954.         sign: function (hash, priv) {
  4955.             var d = priv;
  4956.             var n = ecparams.getN();
  4957.             var e = BigInteger.fromByteArrayUnsigned(hash);
  4958.  
  4959.             do {
  4960.                 var k = ECDSA.getBigRandom(n);
  4961.                 var G = ecparams.getG();
  4962.                 var Q = G.multiply(k);
  4963.                 var r = Q.getX().toBigInteger().mod(n);
  4964.             } while (r.compareTo(BigInteger.ZERO) <= 0);
  4965.  
  4966.             var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
  4967.  
  4968.             return ECDSA.serializeSig(r, s);
  4969.         },
  4970.  
  4971.         verify: function (hash, sig, pubkey) {
  4972.             var r, s;
  4973.             if (Bitcoin.Util.isArray(sig)) {
  4974.                 var obj = ECDSA.parseSig(sig);
  4975.                 r = obj.r;
  4976.                 s = obj.s;
  4977.             } else if ("object" === typeof sig && sig.r && sig.s) {
  4978.                 r = sig.r;
  4979.                 s = sig.s;
  4980.             } else {
  4981.                 throw "Invalid value for signature";
  4982.             }
  4983.  
  4984.             var Q;
  4985.             if (pubkey instanceof ec.PointFp) {
  4986.                 Q = pubkey;
  4987.             } else if (Bitcoin.Util.isArray(pubkey)) {
  4988.                 Q = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), pubkey);
  4989.             } else {
  4990.                 throw "Invalid format for pubkey value, must be byte array or ec.PointFp";
  4991.             }
  4992.             var e = BigInteger.fromByteArrayUnsigned(hash);
  4993.  
  4994.             return ECDSA.verifyRaw(e, r, s, Q);
  4995.         },
  4996.  
  4997.         verifyRaw: function (e, r, s, Q) {
  4998.             var n = ecparams.getN();
  4999.             var G = ecparams.getG();
  5000.  
  5001.             if (r.compareTo(BigInteger.ONE) < 0 ||
  5002.          r.compareTo(n) >= 0)
  5003.                 return false;
  5004.  
  5005.             if (s.compareTo(BigInteger.ONE) < 0 ||
  5006.          s.compareTo(n) >= 0)
  5007.                 return false;
  5008.  
  5009.             var c = s.modInverse(n);
  5010.  
  5011.             var u1 = e.multiply(c).mod(n);
  5012.             var u2 = r.multiply(c).mod(n);
  5013.  
  5014.             // TODO(!!!): For some reason Shamir's trick isn't working with
  5015.             // signed message verification!? Probably an implementation
  5016.             // error!
  5017.             //var point = implShamirsTrick(G, u1, Q, u2);
  5018.             var point = G.multiply(u1).add(Q.multiply(u2));
  5019.  
  5020.             var v = point.getX().toBigInteger().mod(n);
  5021.  
  5022.             return v.equals(r);
  5023.         },
  5024.  
  5025.         /**
  5026.         * Serialize a signature into DER format.
  5027.         *
  5028.         * Takes two BigIntegers representing r and s and returns a byte array.
  5029.         */
  5030.         serializeSig: function (r, s) {
  5031.             var rBa = r.toByteArraySigned();
  5032.             var sBa = s.toByteArraySigned();
  5033.  
  5034.             var sequence = [];
  5035.             sequence.push(0x02); // INTEGER
  5036.             sequence.push(rBa.length);
  5037.             sequence = sequence.concat(rBa);
  5038.  
  5039.             sequence.push(0x02); // INTEGER
  5040.             sequence.push(sBa.length);
  5041.             sequence = sequence.concat(sBa);
  5042.  
  5043.             sequence.unshift(sequence.length);
  5044.             sequence.unshift(0x30); // SEQUENCE
  5045.  
  5046.             return sequence;
  5047.         },
  5048.  
  5049.         /**
  5050.         * Parses a byte array containing a DER-encoded signature.
  5051.         *
  5052.         * This function will return an object of the form:
  5053.         *
  5054.         * {
  5055.         *   r: BigInteger,
  5056.         *   s: BigInteger
  5057.         * }
  5058.         */
  5059.         parseSig: function (sig) {
  5060.             var cursor;
  5061.             if (sig[0] != 0x30)
  5062.                 throw new Error("Signature not a valid DERSequence");
  5063.  
  5064.             cursor = 2;
  5065.             if (sig[cursor] != 0x02)
  5066.                 throw new Error("First element in signature must be a DERInteger"); ;
  5067.             var rBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
  5068.  
  5069.             cursor += 2 + sig[cursor + 1];
  5070.             if (sig[cursor] != 0x02)
  5071.                 throw new Error("Second element in signature must be a DERInteger");
  5072.             var sBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
  5073.  
  5074.             cursor += 2 + sig[cursor + 1];
  5075.  
  5076.             //if (cursor != sig.length)
  5077.             //  throw new Error("Extra bytes in signature");
  5078.  
  5079.             var r = BigInteger.fromByteArrayUnsigned(rBa);
  5080.             var s = BigInteger.fromByteArrayUnsigned(sBa);
  5081.  
  5082.             return { r: r, s: s };
  5083.         },
  5084.  
  5085.         parseSigCompact: function (sig) {
  5086.             if (sig.length !== 65) {
  5087.                 throw "Signature has the wrong length";
  5088.             }
  5089.  
  5090.             // Signature is prefixed with a type byte storing three bits of
  5091.             // information.
  5092.             var i = sig[0] - 27;
  5093.             if (i < 0 || i > 7) {
  5094.                 throw "Invalid signature type";
  5095.             }
  5096.  
  5097.             var n = ecparams.getN();
  5098.             var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
  5099.             var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
  5100.  
  5101.             return { r: r, s: s, i: i };
  5102.         },
  5103.  
  5104.         /**
  5105.         * Recover a public key from a signature.
  5106.         *
  5107.         * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
  5108.         * Key Recovery Operation".
  5109.         *
  5110.         * http://www.secg.org/download/aid-780/sec1-v2.pdf
  5111.         */
  5112.         recoverPubKey: function (r, s, hash, i) {
  5113.             // The recovery parameter i has two bits.
  5114.             i = i & 3;
  5115.  
  5116.             // The less significant bit specifies whether the y coordinate
  5117.             // of the compressed point is even or not.
  5118.             var isYEven = i & 1;
  5119.  
  5120.             // The more significant bit specifies whether we should use the
  5121.             // first or second candidate key.
  5122.             var isSecondKey = i >> 1;
  5123.  
  5124.             var n = ecparams.getN();
  5125.             var G = ecparams.getG();
  5126.             var curve = ecparams.getCurve();
  5127.             var p = curve.getQ();
  5128.             var a = curve.getA().toBigInteger();
  5129.             var b = curve.getB().toBigInteger();
  5130.  
  5131.             // We precalculate (p + 1) / 4 where p is if the field order
  5132.             if (!P_OVER_FOUR) {
  5133.                 P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
  5134.             }
  5135.  
  5136.             // 1.1 Compute x
  5137.             var x = isSecondKey ? r.add(n) : r;
  5138.  
  5139.             // 1.3 Convert x to point
  5140.             var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
  5141.             var beta = alpha.modPow(P_OVER_FOUR, p);
  5142.  
  5143.             var xorOdd = beta.isEven() ? (i % 2) : ((i + 1) % 2);
  5144.             // If beta is even, but y isn't or vice versa, then convert it,
  5145.             // otherwise we're done and y == beta.
  5146.             var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
  5147.  
  5148.             // 1.4 Check that nR is at infinity
  5149.             var R = new EllipticCurve.PointFp(curve,
  5150.                             curve.fromBigInteger(x),
  5151.                             curve.fromBigInteger(y));
  5152.             R.validate();
  5153.  
  5154.             // 1.5 Compute e from M
  5155.             var e = BigInteger.fromByteArrayUnsigned(hash);
  5156.             var eNeg = BigInteger.ZERO.subtract(e).mod(n);
  5157.  
  5158.             // 1.6 Compute Q = r^-1 (sR - eG)
  5159.             var rInv = r.modInverse(n);
  5160.             var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
  5161.  
  5162.             Q.validate();
  5163.             if (!ECDSA.verifyRaw(e, r, s, Q)) {
  5164.                 throw "Pubkey recovery unsuccessful";
  5165.             }
  5166.  
  5167.             var pubKey = new Bitcoin.ECKey();
  5168.             pubKey.pub = Q;
  5169.             return pubKey;
  5170.         },
  5171.  
  5172.         /**
  5173.         * Calculate pubkey extraction parameter.
  5174.         *
  5175.         * When extracting a pubkey from a signature, we have to
  5176.         * distinguish four different cases. Rather than putting this
  5177.         * burden on the verifier, Bitcoin includes a 2-bit value with the
  5178.         * signature.
  5179.         *
  5180.         * This function simply tries all four cases and returns the value
  5181.         * that resulted in a successful pubkey recovery.
  5182.         */
  5183.         calcPubkeyRecoveryParam: function (address, r, s, hash) {
  5184.             for (var i = 0; i < 4; i++) {
  5185.                 try {
  5186.                     var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
  5187.                     if (pubkey.getBitcoinAddress().toString() == address) {
  5188.                         return i;
  5189.                     }
  5190.                 } catch (e) { }
  5191.             }
  5192.             throw "Unable to find valid recovery factor";
  5193.         }
  5194.     };
  5195.  
  5196.     return ECDSA;
  5197. })();
  5198.     </script>
  5199.     <script type="text/javascript">
  5200. //https://raw.github.com/pointbiz/bitcoinjs-lib/9b2f94a028a7bc9bed94e0722563e9ff1d8e8db8/src/eckey.js
  5201. Bitcoin.ECKey = (function () {
  5202.     var ECDSA = Bitcoin.ECDSA;
  5203.     var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  5204.     var rng = new SecureRandom();
  5205.  
  5206.     var ECKey = function (input) {
  5207.         if (!input) {
  5208.             // Generate new key
  5209.             var n = ecparams.getN();
  5210.             this.priv = ECDSA.getBigRandom(n);
  5211.         } else if (input instanceof BigInteger) {
  5212.             // Input is a private key value
  5213.             this.priv = input;
  5214.         } else if (Bitcoin.Util.isArray(input)) {
  5215.             // Prepend zero byte to prevent interpretation as negative integer
  5216.             this.priv = BigInteger.fromByteArrayUnsigned(input);
  5217.         } else if ("string" == typeof input) {
  5218.             var bytes = null;
  5219.             if (ECKey.isWalletImportFormat(input)) {
  5220.                 bytes = ECKey.decodeWalletImportFormat(input);
  5221.             } else if (ECKey.isCompressedWalletImportFormat(input)) {
  5222.                 bytes = ECKey.decodeCompressedWalletImportFormat(input);
  5223.                 this.compressed = true;
  5224.             } else if (ECKey.isMiniFormat(input)) {
  5225.                 bytes = Crypto.SHA256(input, { asBytes: true });
  5226.             } else if (ECKey.isHexFormat(input)) {
  5227.                 bytes = Crypto.util.hexToBytes(input);
  5228.             } else if (ECKey.isBase64Format(input)) {
  5229.                 bytes = Crypto.util.base64ToBytes(input);
  5230.             }
  5231.            
  5232.             if (ECKey.isBase6Format(input)) {
  5233.                 this.priv = new BigInteger(input, 6);
  5234.             } else if (bytes == null || bytes.length != 32) {
  5235.                 this.priv = null;
  5236.             } else {
  5237.                 // Prepend zero byte to prevent interpretation as negative integer
  5238.                 this.priv = BigInteger.fromByteArrayUnsigned(bytes);
  5239.             }
  5240.         }
  5241.  
  5242.         this.compressed = (this.compressed == undefined) ? !!ECKey.compressByDefault : this.compressed;
  5243.     };
  5244.  
  5245.     ECKey.privateKeyPrefix = window.privateKeyPrefix;
  5246.  
  5247.     /**
  5248.     * Whether public keys should be returned compressed by default.
  5249.     */
  5250.     ECKey.compressByDefault = false;
  5251.  
  5252.     /**
  5253.     * Set whether the public key should be returned compressed or not.
  5254.     */
  5255.     ECKey.prototype.setCompressed = function (v) {
  5256.         this.compressed = !!v;
  5257.         if (this.pubPoint) this.pubPoint.compressed = this.compressed;
  5258.         return this;
  5259.     };
  5260.  
  5261.     /*
  5262.     * Return public key as a byte array in DER encoding
  5263.     */
  5264.     ECKey.prototype.getPub = function () {
  5265.         if (this.compressed) {
  5266.             if (this.pubComp) return this.pubComp;
  5267.             return this.pubComp = this.getPubPoint().getEncoded(1);
  5268.         } else {
  5269.             if (this.pubUncomp) return this.pubUncomp;
  5270.             return this.pubUncomp = this.getPubPoint().getEncoded(0);
  5271.         }
  5272.     };
  5273.  
  5274.     /**
  5275.     * Return public point as ECPoint object.
  5276.     */
  5277.     ECKey.prototype.getPubPoint = function () {
  5278.         if (!this.pubPoint) {
  5279.             this.pubPoint = ecparams.getG().multiply(this.priv);
  5280.             this.pubPoint.compressed = this.compressed;
  5281.         }
  5282.         return this.pubPoint;
  5283.     };
  5284.  
  5285.     ECKey.prototype.getPubKeyHex = function () {
  5286.         if (this.compressed) {
  5287.             if (this.pubKeyHexComp) return this.pubKeyHexComp;
  5288.             return this.pubKeyHexComp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
  5289.         } else {
  5290.             if (this.pubKeyHexUncomp) return this.pubKeyHexUncomp;
  5291.             return this.pubKeyHexUncomp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
  5292.         }
  5293.     };
  5294.  
  5295.     /**
  5296.     * Get the pubKeyHash for this key.
  5297.     *
  5298.     * This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
  5299.     * a byte array.
  5300.     */
  5301.     ECKey.prototype.getPubKeyHash = function () {
  5302.         if (this.compressed) {
  5303.             if (this.pubKeyHashComp) return this.pubKeyHashComp;
  5304.             return this.pubKeyHashComp = Bitcoin.Util.sha256ripe160(this.getPub());
  5305.         } else {
  5306.             if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp;
  5307.             return this.pubKeyHashUncomp = Bitcoin.Util.sha256ripe160(this.getPub());
  5308.         }
  5309.     };
  5310.  
  5311.     ECKey.prototype.getBitcoinAddress = function () {
  5312.         var hash = this.getPubKeyHash();
  5313.         var addr = new Bitcoin.Address(hash);
  5314.         return addr.toString();
  5315.     };
  5316.  
  5317.     /*
  5318.     * Takes a public point as a hex string or byte array
  5319.     */
  5320.     ECKey.prototype.setPub = function (pub) {
  5321.         // byte array
  5322.         if (Bitcoin.Util.isArray(pub)) {
  5323.             pub = Crypto.util.bytesToHex(pub).toString().toUpperCase();
  5324.         }
  5325.         var ecPoint = ecparams.getCurve().decodePointHex(pub);
  5326.         this.setCompressed(ecPoint.compressed);
  5327.         this.pubPoint = ecPoint;
  5328.         return this;
  5329.     };
  5330.  
  5331.     // Sipa Private Key Wallet Import Format
  5332.     ECKey.prototype.getBitcoinWalletImportFormat = function () {
  5333.         var bytes = this.getBitcoinPrivateKeyByteArray();
  5334.         bytes.unshift(ECKey.privateKeyPrefix); // prepend 0x80 byte
  5335.         if (this.compressed) bytes.push(0x01); // append 0x01 byte for compressed format
  5336.         var checksum = Crypto.SHA256(Crypto.SHA256(bytes, { asBytes: true }), { asBytes: true });
  5337.         bytes = bytes.concat(checksum.slice(0, 4));
  5338.         var privWif = Bitcoin.Base58.encode(bytes);
  5339.         return privWif;
  5340.     };
  5341.  
  5342.     // Private Key Hex Format
  5343.     ECKey.prototype.getBitcoinHexFormat = function () {
  5344.         return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase();
  5345.     };
  5346.  
  5347.     // Private Key Base64 Format
  5348.     ECKey.prototype.getBitcoinBase64Format = function () {
  5349.         return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray());
  5350.     };
  5351.  
  5352.     ECKey.prototype.getBitcoinPrivateKeyByteArray = function () {
  5353.         // Get a copy of private key as a byte array
  5354.         var bytes = this.priv.toByteArrayUnsigned();
  5355.         // zero pad if private key is less than 32 bytes
  5356.         while (bytes.length < 32) bytes.unshift(0x00);
  5357.         return bytes;
  5358.     };
  5359.  
  5360.     ECKey.prototype.toString = function (format) {
  5361.         format = format || "";
  5362.         if (format.toString().toLowerCase() == "base64" || format.toString().toLowerCase() == "b64") {
  5363.             return this.getBitcoinBase64Format();
  5364.         }
  5365.         // Wallet Import Format
  5366.         else if (format.toString().toLowerCase() == "wif") {
  5367.             return this.getBitcoinWalletImportFormat();
  5368.         }
  5369.         else {
  5370.             return this.getBitcoinHexFormat();
  5371.         }
  5372.     };
  5373.  
  5374.     ECKey.prototype.sign = function (hash) {
  5375.         return ECDSA.sign(hash, this.priv);
  5376.     };
  5377.  
  5378.     ECKey.prototype.verify = function (hash, sig) {
  5379.         return ECDSA.verify(hash, sig, this.getPub());
  5380.     };
  5381.  
  5382.     /**
  5383.     * Parse a wallet import format private key contained in a string.
  5384.     */
  5385.     ECKey.decodeWalletImportFormat = function (privStr) {
  5386.         var bytes = Bitcoin.Base58.decode(privStr);
  5387.         var hash = bytes.slice(0, 33);
  5388.         var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  5389.         if (checksum[0] != bytes[33] ||
  5390.                     checksum[1] != bytes[34] ||
  5391.                     checksum[2] != bytes[35] ||
  5392.                     checksum[3] != bytes[36]) {
  5393.             throw "Checksum validation failed!";
  5394.         }
  5395.         var version = hash.shift();
  5396.         if (version != ECKey.privateKeyPrefix) {
  5397.             throw "Version " + version + " not supported!";
  5398.         }
  5399.         return hash;
  5400.     };
  5401.  
  5402.     /**
  5403.     * Parse a compressed wallet import format private key contained in a string.
  5404.     */
  5405.     ECKey.decodeCompressedWalletImportFormat = function (privStr) {
  5406.         var bytes = Bitcoin.Base58.decode(privStr);
  5407.         var hash = bytes.slice(0, 34);
  5408.         var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  5409.         if (checksum[0] != bytes[34] ||
  5410.                     checksum[1] != bytes[35] ||
  5411.                     checksum[2] != bytes[36] ||
  5412.                     checksum[3] != bytes[37]) {
  5413.             throw "Checksum validation failed!";
  5414.         }
  5415.         var version = hash.shift();
  5416.         if (version != ECKey.privateKeyPrefix) {
  5417.             throw "Version " + version + " not supported!";
  5418.         }
  5419.         hash.pop();
  5420.         return hash;
  5421.     };
  5422.  
  5423.     // 64 characters [0-9A-F]
  5424.     ECKey.isHexFormat = function (key) {
  5425.         key = key.toString();
  5426.         return /^[A-Fa-f0-9]{64}$/.test(key);
  5427.     };
  5428.  
  5429.     // 51 characters base58, bitcoin always starts with a 5, litecoin and dogecoin with a '6', testnet with a '9'
  5430.     ECKey.isWalletImportFormat = function (key) {
  5431.         key = key.toString();
  5432.         var matcher = new RegExp("^" + window.WIFPrefix + "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$", "g");
  5433.         return (ECKey.privateKeyPrefix == window.privateKeyPrefix) ? (matcher.test(key)) : false;
  5434.     };
  5435.  
  5436.     // 52 characters base58, bitcoin always starts with L or K, litecoin with a T, dogecoin with a 'Q', testnet with a 'c'
  5437.     ECKey.isCompressedWalletImportFormat = function (key) {
  5438.         key = key.toString();
  5439.         var matcher = new RegExp("^" + window.compressedWIFPrefix + "[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$", "g");
  5440.         return (ECKey.privateKeyPrefix == window.privateKeyPrefix) ? (matcher.test(key)) : false;
  5441.     };
  5442.  
  5443.     // 44 characters
  5444.     ECKey.isBase64Format = function (key) {
  5445.         key = key.toString();
  5446.         return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key));
  5447.     };
  5448.  
  5449.     // 99 characters, 1=1, if using dice convert 6 to 0
  5450.     ECKey.isBase6Format = function (key) {
  5451.         key = key.toString();
  5452.         return (/^[012345]{99}$/.test(key));
  5453.     };
  5454.  
  5455.     // 22, 26 or 30 characters, always starts with an 'S'
  5456.     ECKey.isMiniFormat = function (key) {
  5457.         key = key.toString();
  5458.         var validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key);
  5459.         var validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key);
  5460.         var validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key);
  5461.         var testBytes = Crypto.SHA256(key + "?", { asBytes: true });
  5462.  
  5463.         return ((testBytes[0] === 0x00 || testBytes[0] === 0x01) && (validChars22 || validChars26 || validChars30));
  5464.     };
  5465.  
  5466.     return ECKey;
  5467. })();
  5468.     </script>
  5469.     <script type="text/javascript">
  5470. //https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/util.js
  5471. // Bitcoin utility functions
  5472. Bitcoin.Util = {
  5473.     /**
  5474.     * Cross-browser compatibility version of Array.isArray.
  5475.     */
  5476.     isArray: Array.isArray || function (o) {
  5477.         return Object.prototype.toString.call(o) === '[object Array]';
  5478.     },
  5479.     /**
  5480.     * Create an array of a certain length filled with a specific value.
  5481.     */
  5482.     makeFilledArray: function (len, val) {
  5483.         var array = [];
  5484.         var i = 0;
  5485.         while (i < len) {
  5486.             array[i++] = val;
  5487.         }
  5488.         return array;
  5489.     },
  5490.     /**
  5491.     * Turn an integer into a "var_int".
  5492.     *
  5493.     * "var_int" is a variable length integer used by Bitcoin's binary format.
  5494.     *
  5495.     * Returns a byte array.
  5496.     */
  5497.     numToVarInt: function (i) {
  5498.         if (i < 0xfd) {
  5499.             // unsigned char
  5500.             return [i];
  5501.         } else if (i <= 1 << 16) {
  5502.             // unsigned short (LE)
  5503.             return [0xfd, i >>> 8, i & 255];
  5504.         } else if (i <= 1 << 32) {
  5505.             // unsigned int (LE)
  5506.             return [0xfe].concat(Crypto.util.wordsToBytes([i]));
  5507.         } else {
  5508.             // unsigned long long (LE)
  5509.             return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
  5510.         }
  5511.     },
  5512.     /**
  5513.     * Parse a Bitcoin value byte array, returning a BigInteger.
  5514.     */
  5515.     valueToBigInt: function (valueBuffer) {
  5516.         if (valueBuffer instanceof BigInteger) return valueBuffer;
  5517.  
  5518.         // Prepend zero byte to prevent interpretation as negative integer
  5519.         return BigInteger.fromByteArrayUnsigned(valueBuffer);
  5520.     },
  5521.     /**
  5522.     * Format a Bitcoin value as a string.
  5523.     *
  5524.     * Takes a BigInteger or byte-array and returns that amount of Bitcoins in a
  5525.     * nice standard formatting.
  5526.     *
  5527.     * Examples:
  5528.     * 12.3555
  5529.     * 0.1234
  5530.     * 900.99998888
  5531.     * 34.00
  5532.     */
  5533.     formatValue: function (valueBuffer) {
  5534.         var value = this.valueToBigInt(valueBuffer).toString();
  5535.         var integerPart = value.length > 8 ? value.substr(0, value.length - 8) : '0';
  5536.         var decimalPart = value.length > 8 ? value.substr(value.length - 8) : value;
  5537.         while (decimalPart.length < 8) decimalPart = "0" + decimalPart;
  5538.         decimalPart = decimalPart.replace(/0*$/, '');
  5539.         while (decimalPart.length < 2) decimalPart += "0";
  5540.         return integerPart + "." + decimalPart;
  5541.     },
  5542.     /**
  5543.     * Parse a floating point string as a Bitcoin value.
  5544.     *
  5545.     * Keep in mind that parsing user input is messy. You should always display
  5546.     * the parsed value back to the user to make sure we understood his input
  5547.     * correctly.
  5548.     */
  5549.     parseValue: function (valueString) {
  5550.         // TODO: Detect other number formats (e.g. comma as decimal separator)
  5551.         var valueComp = valueString.split('.');
  5552.         var integralPart = valueComp[0];
  5553.         var fractionalPart = valueComp[1] || "0";
  5554.         while (fractionalPart.length < 8) fractionalPart += "0";
  5555.         fractionalPart = fractionalPart.replace(/^0+/g, '');
  5556.         var value = BigInteger.valueOf(parseInt(integralPart));
  5557.         value = value.multiply(BigInteger.valueOf(100000000));
  5558.         value = value.add(BigInteger.valueOf(parseInt(fractionalPart)));
  5559.         return value;
  5560.     },
  5561.     /**
  5562.     * Calculate RIPEMD160(SHA256(data)).
  5563.     *
  5564.     * Takes an arbitrary byte array as inputs and returns the hash as a byte
  5565.     * array.
  5566.     */
  5567.     sha256ripe160: function (data) {
  5568.         return Crypto.RIPEMD160(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
  5569.     },
  5570.     // double sha256
  5571.     dsha256: function (data) {
  5572.         return Crypto.SHA256(Crypto.SHA256(data, { asBytes: true }), { asBytes: true });
  5573.     }
  5574. };
  5575.     </script>
  5576.     <script type="text/javascript">
  5577. /*
  5578. * Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
  5579. *
  5580. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5581. * of this software and associated documentation files (the "Software"), to deal
  5582. * in the Software without restriction, including without limitation the rights
  5583. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  5584. * copies of the Software, and to permit persons to whom the Software is
  5585. * furnished to do so, subject to the following conditions:
  5586. *
  5587. * The above copyright notice and this permission notice shall be included in
  5588. * all copies or substantial portions of the Software.
  5589. *
  5590. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5591. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5592. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5593. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5594. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  5595. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  5596. * THE SOFTWARE.
  5597. */
  5598. // https://github.com/cheongwy/node-scrypt-js
  5599. (function () {
  5600.  
  5601.     var MAX_VALUE = 2147483647;
  5602.     var workerUrl = null;
  5603.  
  5604.     //function scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen)
  5605.     /*
  5606.     * N = Cpu cost
  5607.     * r = Memory cost
  5608.     * p = parallelization cost
  5609.     *
  5610.     */
  5611.     window.Crypto_scrypt = function (passwd, salt, N, r, p, dkLen, callback) {
  5612.         if (N == 0 || (N & (N - 1)) != 0) throw Error("N must be > 0 and a power of 2");
  5613.  
  5614.         if (N > MAX_VALUE / 128 / r) throw Error("Parameter N is too large");
  5615.         if (r > MAX_VALUE / 128 / p) throw Error("Parameter r is too large");
  5616.  
  5617.         var PBKDF2_opts = { iterations: 1, hasher: Crypto.SHA256, asBytes: true };
  5618.  
  5619.         var B = Crypto.PBKDF2(passwd, salt, p * 128 * r, PBKDF2_opts);
  5620.  
  5621.         try {
  5622.             var i = 0;
  5623.             var worksDone = 0;
  5624.             var makeWorker = function () {
  5625.                 if (!workerUrl) {
  5626.                     var code = '(' + scryptCore.toString() + ')()';
  5627.                     var blob;
  5628.                     try {
  5629.                         blob = new Blob([code], { type: "text/javascript" });
  5630.                     } catch (e) {
  5631.                         window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
  5632.                         blob = new BlobBuilder();
  5633.                         blob.append(code);
  5634.                         blob = blob.getBlob("text/javascript");
  5635.                     }
  5636.                     workerUrl = URL.createObjectURL(blob);
  5637.                 }
  5638.                 var worker = new Worker(workerUrl);
  5639.                 worker.onmessage = function (event) {
  5640.                     var Bi = event.data[0], Bslice = event.data[1];
  5641.                     worksDone++;
  5642.  
  5643.                     if (i < p) {
  5644.                         worker.postMessage([N, r, p, B, i++]);
  5645.                     }
  5646.  
  5647.                     var length = Bslice.length, destPos = Bi * 128 * r, srcPos = 0;
  5648.                     while (length--) {
  5649.                         B[destPos++] = Bslice[srcPos++];
  5650.                     }
  5651.  
  5652.                     if (worksDone == p) {
  5653.                         callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
  5654.                     }
  5655.                 };
  5656.                 return worker;
  5657.             };
  5658.             var workers = [makeWorker(), makeWorker()];
  5659.             workers[0].postMessage([N, r, p, B, i++]);
  5660.             if (p > 1) {
  5661.                 workers[1].postMessage([N, r, p, B, i++]);
  5662.             }
  5663.         } catch (e) {
  5664.             window.setTimeout(function () {
  5665.                 scryptCore();
  5666.                 callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
  5667.             }, 0);
  5668.         }
  5669.  
  5670.         // using this function to enclose everything needed to create a worker (but also invokable directly for synchronous use)
  5671.         function scryptCore() {
  5672.             var XY = [], V = [];
  5673.            
  5674.             salsa20_8(new Array(32)); // dummy call added to work around problem with BIP38 encoding on Safari 6.05
  5675.  
  5676.             if (typeof B === 'undefined') {
  5677.                 onmessage = function (event) {
  5678.                     var data = event.data;
  5679.                     var N = data[0], r = data[1], p = data[2], B = data[3], i = data[4];
  5680.  
  5681.                     var Bslice = [];
  5682.                     arraycopy32(B, i * 128 * r, Bslice, 0, 128 * r);
  5683.                     smix(Bslice, 0, r, N, V, XY);
  5684.  
  5685.                     postMessage([i, Bslice]);
  5686.                 };
  5687.             } else {
  5688.                 for (var i = 0; i < p; i++) {
  5689.                     smix(B, i * 128 * r, r, N, V, XY);
  5690.                 }
  5691.             }
  5692.  
  5693.             function smix(B, Bi, r, N, V, XY) {
  5694.                 var Xi = 0;
  5695.                 var Yi = 128 * r;
  5696.                 var i;
  5697.  
  5698.                 arraycopy32(B, Bi, XY, Xi, Yi);
  5699.  
  5700.                 for (i = 0; i < N; i++) {
  5701.                     arraycopy32(XY, Xi, V, i * Yi, Yi);
  5702.                     blockmix_salsa8(XY, Xi, Yi, r);
  5703.                 }
  5704.  
  5705.                 for (i = 0; i < N; i++) {
  5706.                     var j = integerify(XY, Xi, r) & (N - 1);
  5707.                     blockxor(V, j * Yi, XY, Xi, Yi);
  5708.                     blockmix_salsa8(XY, Xi, Yi, r);
  5709.                 }
  5710.  
  5711.                 arraycopy32(XY, Xi, B, Bi, Yi);
  5712.             }
  5713.  
  5714.             function blockmix_salsa8(BY, Bi, Yi, r) {
  5715.                 var X = [];
  5716.                 var i;
  5717.  
  5718.                 arraycopy32(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
  5719.  
  5720.                 for (i = 0; i < 2 * r; i++) {
  5721.                     blockxor(BY, i * 64, X, 0, 64);
  5722.                     salsa20_8(X);
  5723.                     arraycopy32(X, 0, BY, Yi + (i * 64), 64);
  5724.                 }
  5725.  
  5726.                 for (i = 0; i < r; i++) {
  5727.                     arraycopy32(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
  5728.                 }
  5729.  
  5730.                 for (i = 0; i < r; i++) {
  5731.                     arraycopy32(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
  5732.                 }
  5733.             }
  5734.  
  5735.             function R(a, b) {
  5736.                 return (a << b) | (a >>> (32 - b));
  5737.             }
  5738.  
  5739.             function salsa20_8(B) {
  5740.                 var B32 = new Array(32);
  5741.                 var x = new Array(32);
  5742.                 var i;
  5743.  
  5744.                 for (i = 0; i < 16; i++) {
  5745.                     B32[i] = (B[i * 4 + 0] & 0xff) << 0;
  5746.                     B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
  5747.                     B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
  5748.                     B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
  5749.                 }
  5750.  
  5751.                 arraycopy(B32, 0, x, 0, 16);
  5752.  
  5753.                 for (i = 8; i > 0; i -= 2) {
  5754.                     x[4] ^= R(x[0] + x[12], 7); x[8] ^= R(x[4] + x[0], 9);
  5755.                     x[12] ^= R(x[8] + x[4], 13); x[0] ^= R(x[12] + x[8], 18);
  5756.                     x[9] ^= R(x[5] + x[1], 7); x[13] ^= R(x[9] + x[5], 9);
  5757.                     x[1] ^= R(x[13] + x[9], 13); x[5] ^= R(x[1] + x[13], 18);
  5758.                     x[14] ^= R(x[10] + x[6], 7); x[2] ^= R(x[14] + x[10], 9);
  5759.                     x[6] ^= R(x[2] + x[14], 13); x[10] ^= R(x[6] + x[2], 18);
  5760.                     x[3] ^= R(x[15] + x[11], 7); x[7] ^= R(x[3] + x[15], 9);
  5761.                     x[11] ^= R(x[7] + x[3], 13); x[15] ^= R(x[11] + x[7], 18);
  5762.                     x[1] ^= R(x[0] + x[3], 7); x[2] ^= R(x[1] + x[0], 9);
  5763.                     x[3] ^= R(x[2] + x[1], 13); x[0] ^= R(x[3] + x[2], 18);
  5764.                     x[6] ^= R(x[5] + x[4], 7); x[7] ^= R(x[6] + x[5], 9);
  5765.                     x[4] ^= R(x[7] + x[6], 13); x[5] ^= R(x[4] + x[7], 18);
  5766.                     x[11] ^= R(x[10] + x[9], 7); x[8] ^= R(x[11] + x[10], 9);
  5767.                     x[9] ^= R(x[8] + x[11], 13); x[10] ^= R(x[9] + x[8], 18);
  5768.                     x[12] ^= R(x[15] + x[14], 7); x[13] ^= R(x[12] + x[15], 9);
  5769.                     x[14] ^= R(x[13] + x[12], 13); x[15] ^= R(x[14] + x[13], 18);
  5770.                 }
  5771.  
  5772.                 for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
  5773.  
  5774.                 for (i = 0; i < 16; i++) {
  5775.                     var bi = i * 4;
  5776.                     B[bi + 0] = (B32[i] >> 0 & 0xff);
  5777.                     B[bi + 1] = (B32[i] >> 8 & 0xff);
  5778.                     B[bi + 2] = (B32[i] >> 16 & 0xff);
  5779.                     B[bi + 3] = (B32[i] >> 24 & 0xff);
  5780.                 }
  5781.             }
  5782.  
  5783.             function blockxor(S, Si, D, Di, len) {
  5784.                 var i = len >> 6;
  5785.                 while (i--) {
  5786.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5787.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5788.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5789.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5790.  
  5791.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5792.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5793.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5794.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5795.  
  5796.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5797.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5798.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5799.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5800.  
  5801.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5802.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5803.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5804.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5805.  
  5806.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5807.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5808.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5809.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5810.  
  5811.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5812.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5813.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5814.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5815.  
  5816.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5817.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5818.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5819.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5820.  
  5821.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5822.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5823.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5824.                     D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
  5825.                 }
  5826.             }
  5827.  
  5828.             function integerify(B, bi, r) {
  5829.                 var n;
  5830.  
  5831.                 bi += (2 * r - 1) * 64;
  5832.  
  5833.                 n = (B[bi + 0] & 0xff) << 0;
  5834.                 n |= (B[bi + 1] & 0xff) << 8;
  5835.                 n |= (B[bi + 2] & 0xff) << 16;
  5836.                 n |= (B[bi + 3] & 0xff) << 24;
  5837.  
  5838.                 return n;
  5839.             }
  5840.  
  5841.             function arraycopy(src, srcPos, dest, destPos, length) {
  5842.                 while (length--) {
  5843.                     dest[destPos++] = src[srcPos++];
  5844.                 }
  5845.             }
  5846.  
  5847.             function arraycopy32(src, srcPos, dest, destPos, length) {
  5848.                 var i = length >> 5;
  5849.                 while (i--) {
  5850.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5851.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5852.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5853.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5854.  
  5855.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5856.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5857.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5858.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5859.  
  5860.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5861.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5862.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5863.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5864.  
  5865.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5866.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5867.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5868.                     dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
  5869.                 }
  5870.             }
  5871.         } // scryptCore
  5872.     }; // window.Crypto_scrypt
  5873. })();
  5874.     </script>
  5875.  
  5876.  
  5877.  
  5878.  
  5879.     <script type="text/javascript">
  5880.     // User Agent Parser added by BitcoinPaperWallet.com for browser detection.
  5881.     // UAParser.js v0.6.1
  5882.     // Lightweight JavaScript-based User-Agent string parser
  5883.     // https://github.com/faisalman/ua-parser-js
  5884.     //
  5885.     // Copyright © 2012-2013 Faisalman <fyzlman@gmail.com>
  5886.     // Dual licensed under GPLv2 & MIT
  5887.    
  5888.     (function (window, undefined) {
  5889.    
  5890.         'use strict';
  5891.    
  5892.         //////////////
  5893.         // Constants
  5894.         /////////////
  5895.    
  5896.    
  5897.         var EMPTY       = '',
  5898.             UNKNOWN     = '?',
  5899.             FUNC_TYPE   = 'function',
  5900.             UNDEF_TYPE  = 'undefined',
  5901.             OBJ_TYPE    = 'object',
  5902.             MAJOR       = 'major',
  5903.             MODEL       = 'model',
  5904.             NAME        = 'name',
  5905.             TYPE        = 'type',
  5906.             VENDOR      = 'vendor',
  5907.             VERSION     = 'version',
  5908.             ARCHITECTURE= 'architecture',
  5909.             CONSOLE     = 'console',
  5910.             MOBILE      = 'mobile',
  5911.             TABLET      = 'tablet';
  5912.    
  5913.    
  5914.         ///////////
  5915.         // Helper
  5916.         //////////
  5917.    
  5918.    
  5919.         var util = {
  5920.             has : function (str1, str2) {
  5921.                 return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
  5922.             },
  5923.             lowerize : function (str) {
  5924.                 return str.toLowerCase();
  5925.             }
  5926.         };
  5927.    
  5928.    
  5929.         ///////////////
  5930.         // Map helper
  5931.         //////////////
  5932.    
  5933.    
  5934.         var mapper = {
  5935.    
  5936.             rgx : function () {
  5937.    
  5938.                 // loop through all regexes maps
  5939.                 for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
  5940.    
  5941.                     var regex = args[i],       // even sequence (0,2,4,..)
  5942.                         props = args[i + 1];   // odd sequence (1,3,5,..)
  5943.    
  5944.                     // construct object barebones
  5945.                     if (typeof(result) === UNDEF_TYPE) {
  5946.                         result = {};
  5947.                         for (p in props) {
  5948.                             q = props[p];
  5949.                             if (typeof(q) === OBJ_TYPE) {
  5950.                                 result[q[0]] = undefined;
  5951.                             } else {
  5952.                                 result[q] = undefined;
  5953.                             }
  5954.                         }
  5955.                     }
  5956.    
  5957.                     // try matching uastring with regexes
  5958.                     for (j = k = 0; j < regex.length; j++) {
  5959.                         matches = regex[j].exec(this.getUA());
  5960.                         if (!!matches) {
  5961.                             for (p in props) {
  5962.                                 match = matches[++k];
  5963.                                 q = props[p];
  5964.                                 // check if given property is actually array
  5965.                                 if (typeof(q) === OBJ_TYPE && q.length > 0) {
  5966.                                     if (q.length == 2) {
  5967.                                         if (typeof(q[1]) == FUNC_TYPE) {
  5968.                                             // assign modified match
  5969.                                             result[q[0]] = q[1].call(this, match);
  5970.                                         } else {
  5971.                                             // assign given value, ignore regex match
  5972.                                             result[q[0]] = q[1];
  5973.                                         }
  5974.                                     } else if (q.length == 3) {
  5975.                                         // check whether function or regex
  5976.                                         if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
  5977.                                             // call function (usually string mapper)
  5978.                                             result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
  5979.                                         } else {
  5980.                                             // sanitize match using given regex
  5981.                                             result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
  5982.                                         }
  5983.                                     } else if (q.length == 4) {
  5984.                                             result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
  5985.                                     }
  5986.                                 } else {
  5987.                                     result[q] = match ? match : undefined;
  5988.                                 }
  5989.                             }
  5990.                             break;
  5991.                         }
  5992.                     }
  5993.    
  5994.                     if(!!matches) break; // break the loop immediately if match found
  5995.                 }
  5996.                 return result;
  5997.             },
  5998.    
  5999.             str : function (str, map) {
  6000.    
  6001.                 for (var i in map) {
  6002.                     // check if array
  6003.                     if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
  6004.                         for (var j in map[i]) {
  6005.                             if (util.has(map[i][j], str)) {
  6006.                                 return (i === UNKNOWN) ? undefined : i;
  6007.                             }
  6008.                         }
  6009.                     } else if (util.has(map[i], str)) {
  6010.                         return (i === UNKNOWN) ? undefined : i;
  6011.                     }
  6012.                 }
  6013.                 return str;
  6014.             }
  6015.         };
  6016.    
  6017.    
  6018.         ///////////////
  6019.         // String map
  6020.         //////////////
  6021.    
  6022.    
  6023.         var maps = {
  6024.    
  6025.             browser : {
  6026.                 oldsafari : {
  6027.                     major : {
  6028.                         '1' : ['/8', '/1', '/3'],
  6029.                         '2' : '/4',
  6030.                         '?' : '/'
  6031.                     },
  6032.                     version : {
  6033.                         '1.0'   : '/8',
  6034.                         '1.2'   : '/1',
  6035.                         '1.3'   : '/3',
  6036.                         '2.0'   : '/412',
  6037.                         '2.0.2' : '/416',
  6038.                         '2.0.3' : '/417',
  6039.                         '2.0.4' : '/419',
  6040.                         '?'     : '/'
  6041.                     }
  6042.                 }
  6043.             },
  6044.    
  6045.             device : {
  6046.                 sprint : {
  6047.                     model : {
  6048.                         'Evo Shift 4G' : '7373KT'
  6049.                     },
  6050.                     vendor : {
  6051.                         'HTC'       : 'APA',
  6052.                         'Sprint'    : 'Sprint'
  6053.                     }
  6054.                 }
  6055.             },
  6056.    
  6057.             os : {
  6058.                 windows : {
  6059.                     version : {
  6060.                         'ME'        : '4.90',
  6061.                         'NT 3.11'   : 'NT3.51',
  6062.                         'NT 4.0'    : 'NT4.0',
  6063.                         '2000'      : 'NT 5.0',
  6064.                         'XP'        : ['NT 5.1', 'NT 5.2'],
  6065.                         'Vista'     : 'NT 6.0',
  6066.                         '7'         : 'NT 6.1',
  6067.                         '8'         : 'NT 6.2',
  6068.                         'RT'        : 'ARM'
  6069.                     }
  6070.                 }
  6071.             }
  6072.         };
  6073.    
  6074.    
  6075.         //////////////
  6076.         // Regex map
  6077.         /////////////
  6078.    
  6079.    
  6080.         var regexes = {
  6081.    
  6082.             browser : [[
  6083.    
  6084.                 // Presto based
  6085.                 /(opera\smini)\/((\d+)?[\w\.-]+)/i,                                 // Opera Mini
  6086.                 /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i,                // Opera Mobi/Tablet
  6087.                 /(opera).+version\/((\d+)?[\w\.]+)/i,                               // Opera > 9.80
  6088.                 /(opera)[\/\s]+((\d+)?[\w\.]+)/i                                    // Opera < 9.80
  6089.                
  6090.                 ], [NAME, VERSION, MAJOR], [
  6091.    
  6092.                 /\s(opr)\/((\d+)?[\w\.]+)/i                                         // Opera Webkit
  6093.                 ], [[NAME, 'Opera'], VERSION, MAJOR], [
  6094.    
  6095.                 // Mixed
  6096.                 /(kindle)\/((\d+)?[\w\.]+)/i,                                       // Kindle
  6097.                 /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i,
  6098.                                                                                     // Lunascape/Maxthon/Netfront/Jasmine/Blazer
  6099.    
  6100.                 // Trident based
  6101.                 /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i,
  6102.                                                                                     // Avant/IEMobile/SlimBrowser/Baidu
  6103.                 /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i,                                  // Internet Explorer
  6104.    
  6105.                 // Webkit/KHTML based
  6106.                 /(rekonq)((?:\/)[\w\.]+)*/i,                                        // Rekonq
  6107.                 /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt)\/((\d+)?[\w\.-]+)/i
  6108.                                                                                     // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt
  6109.                 ], [NAME, VERSION, MAJOR], [
  6110.    
  6111.                 /(yabrowser)\/((\d+)?[\w\.]+)/i                                     // Yandex
  6112.                 ], [[NAME, 'Yandex'], VERSION, MAJOR], [
  6113.    
  6114.                 /(comodo_dragon)\/((\d+)?[\w\.]+)/i                                 // Comodo Dragon
  6115.                 ], [[NAME, /_/g, ' '], VERSION, MAJOR], [
  6116.    
  6117.                 /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i
  6118.                                                                                     // Chrome/OmniWeb/Arora/Tizen/Nokia
  6119.                 ], [NAME, VERSION, MAJOR], [
  6120.    
  6121.                 /(dolfin)\/((\d+)?[\w\.]+)/i                                        // Dolphin
  6122.                 ], [[NAME, 'Dolphin'], VERSION, MAJOR], [
  6123.    
  6124.                 /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i                       // Chrome for Android/iOS
  6125.                 ], [[NAME, 'Chrome'], VERSION, MAJOR], [
  6126.    
  6127.                 /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i                 // Mobile Safari
  6128.                 ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [
  6129.    
  6130.                 /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i              // Safari & Safari Mobile
  6131.                 ], [VERSION, MAJOR, NAME], [
  6132.    
  6133.                 /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i                   // Safari < 3.0
  6134.                 ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [
  6135.    
  6136.                 /(konqueror)\/((\d+)?[\w\.]+)/i,                                    // Konqueror
  6137.                 /(webkit|khtml)\/((\d+)?[\w\.]+)/i
  6138.                 ], [NAME, VERSION, MAJOR], [
  6139.    
  6140.                 // Gecko based
  6141.                 /(navigator|netscape)\/((\d+)?[\w\.-]+)/i                           // Netscape
  6142.                 ], [[NAME, 'Netscape'], VERSION, MAJOR], [
  6143.                 /(swiftfox)/i,                                                      // Swiftfox
  6144.                 /(iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i,
  6145.                                                                                     // Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
  6146.                 /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i,
  6147.                                                                                     // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
  6148.                 /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i,                    // Mozilla
  6149.    
  6150.                 // Other
  6151.                 /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?((\d+)?[\w\.]+)/i,
  6152.                                                                                     // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
  6153.                 /(links)\s\(((\d+)?[\w\.]+)/i,                                      // Links
  6154.                 /(gobrowser)\/?((\d+)?[\w\.]+)*/i,                                  // GoBrowser
  6155.                 /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i,                             // ICE Browser
  6156.                 /(mosaic)[\/\s]((\d+)?[\w\.]+)/i                                    // Mosaic
  6157.                 ], [NAME, VERSION, MAJOR]
  6158.             ],
  6159.    
  6160.             cpu : [[
  6161.    
  6162.                 /(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i                     // AMD64
  6163.                 ], [[ARCHITECTURE, 'amd64']], [
  6164.    
  6165.                 /((?:i[346]|x)86)[;\)]/i                                            // IA32
  6166.                 ], [[ARCHITECTURE, 'ia32']], [
  6167.    
  6168.                 // PocketPC mistakenly identified as PowerPC
  6169.                 /windows\s(ce|mobile);\sppc;/i
  6170.                 ], [[ARCHITECTURE, 'arm']], [
  6171.    
  6172.                 /((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i                           // PowerPC
  6173.                 ], [[ARCHITECTURE, /ower/, '', util.lowerize]], [
  6174.    
  6175.                 /(sun4\w)[;\)]/i                                                    // SPARC
  6176.                 ], [[ARCHITECTURE, 'sparc']], [
  6177.    
  6178.                 /(ia64(?=;)|68k(?=\))|arm(?=v\d+;)|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)/i
  6179.                                                                                     // IA64, 68K, ARM, IRIX, MIPS, SPARC, PA-RISC
  6180.                 ], [ARCHITECTURE, util.lowerize]
  6181.             ],
  6182.    
  6183.             device : [[
  6184.    
  6185.                 /\((ipad|playbook);[\w\s\);-]+(rim|apple)/i                         // iPad/PlayBook
  6186.                 ], [MODEL, VENDOR, [TYPE, TABLET]], [
  6187.    
  6188.                 /(hp).+(touchpad)/i,                                                // HP TouchPad
  6189.                 /(kindle)\/([\w\.]+)/i,                                             // Kindle
  6190.                 /\s(nook)[\w\s]+build\/(\w+)/i,                                     // Nook
  6191.                 /(dell)\s(strea[kpr\s\d]*[\dko])/i                                  // Dell Streak
  6192.                 ], [VENDOR, MODEL, [TYPE, TABLET]], [
  6193.    
  6194.                 /\((ip[honed]+);.+(apple)/i                                         // iPod/iPhone
  6195.                 ], [MODEL, VENDOR, [TYPE, MOBILE]], [
  6196.    
  6197.                 /(blackberry)[\s-]?(\w+)/i,                                         // BlackBerry
  6198.                 /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola)[\s_-]?([\w-]+)*/i,
  6199.                                                                                     // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola
  6200.                 /(hp)\s([\w\s]+\w)/i,                                               // HP iPAQ
  6201.                 /(asus)-?(\w+)/i                                                    // Asus
  6202.                 ], [VENDOR, MODEL, [TYPE, MOBILE]], [
  6203.                 /\((bb10);\s(\w+)/i                                                 // BlackBerry 10
  6204.                 ], [[VENDOR, 'BlackBerry'], MODEL, [TYPE, MOBILE]], [
  6205.    
  6206.                 /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i       // Asus Tablets
  6207.                 ], [[VENDOR, 'Asus'], MODEL, [TYPE, TABLET]], [
  6208.    
  6209.                 /(sony)\s(tablet\s[ps])/i                                           // Sony Tablets
  6210.                 ], [VENDOR, MODEL, [TYPE, TABLET]], [
  6211.    
  6212.                 /(nintendo)\s([wids3u]+)/i                                          // Nintendo
  6213.                 ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
  6214.    
  6215.                 /((playstation)\s[3portablevi]+)/i                                  // Playstation
  6216.                 ], [[VENDOR, 'Sony'], MODEL, [TYPE, CONSOLE]], [
  6217.    
  6218.                 /(sprint\s(\w+))/i                                                  // Sprint Phones
  6219.                 ], [[VENDOR, mapper.str, maps.device.sprint.vendor], [MODEL, mapper.str, maps.device.sprint.model], [TYPE, MOBILE]], [
  6220.    
  6221.                 /(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i,                               // HTC
  6222.                 /(zte)-(\w+)*/i,                                                    // ZTE
  6223.                 /(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i
  6224.                                                                                     // Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony
  6225.                 ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [
  6226.    
  6227.                 /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i,                   // Motorola
  6228.                 /(mot)[\s-]?(\w+)*/i
  6229.                 ], [[VENDOR, 'Motorola'], MODEL, [TYPE, MOBILE]], [
  6230.                 /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i
  6231.                 ], [[VENDOR, 'Motorola'], MODEL, [TYPE, TABLET]], [
  6232.    
  6233.                 /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i
  6234.                 ], [[VENDOR, 'Samsung'], MODEL, [TYPE, TABLET]], [                  // Samsung
  6235.                 /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i,
  6236.                 /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i,
  6237.                 /sec-((sgh\w+))/i
  6238.                 ], [[VENDOR, 'Samsung'], MODEL, [TYPE, MOBILE]], [
  6239.                 /(sie)-(\w+)*/i                                                     // Siemens
  6240.                 ], [[VENDOR, 'Siemens'], MODEL, [TYPE, MOBILE]], [
  6241.    
  6242.                 /(maemo|nokia).*(n900|lumia\s\d+)/i,                                // Nokia
  6243.                 /(nokia)[\s_-]?([\w-]+)*/i
  6244.                 ], [[VENDOR, 'Nokia'], MODEL, [TYPE, MOBILE]], [
  6245.    
  6246.                 /android\s3\.[\s\w-;]{10}((a\d{3}))/i                               // Acer
  6247.                 ], [[VENDOR, 'Acer'], MODEL, [TYPE, TABLET]], [
  6248.    
  6249.                 /android\s3\.[\s\w-;]{10}(lg?)-([06cv9]{3,4})/i                     // LG
  6250.                 ], [[VENDOR, 'LG'], MODEL, [TYPE, TABLET]], [
  6251.                 /((nexus\s4))/i,
  6252.                 /(lg)[e;\s-\/]+(\w+)*/i
  6253.                 ], [[VENDOR, 'LG'], MODEL, [TYPE, MOBILE]], [
  6254.    
  6255.                 /(mobile|tablet);.+rv\:.+gecko\//i                                  // Unidentifiable
  6256.                 ], [TYPE, VENDOR, MODEL]
  6257.             ],
  6258.    
  6259.             engine : [[
  6260.    
  6261.                 /(presto)\/([\w\.]+)/i,                                             // Presto
  6262.                 /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,     // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
  6263.                 /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,                          // KHTML/Tasman/Links
  6264.                 /(icab)[\/\s]([23]\.[\d\.]+)/i                                      // iCab
  6265.                 ], [NAME, VERSION], [
  6266.    
  6267.                 /rv\:([\w\.]+).*(gecko)/i                                           // Gecko
  6268.                 ], [VERSION, NAME]
  6269.             ],
  6270.    
  6271.             os : [[
  6272.    
  6273.                 // Windows based
  6274.                 /(windows)\snt\s6\.2;\s(arm)/i,                                     // Windows RT
  6275.                 /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
  6276.                 ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
  6277.                 /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
  6278.                 ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
  6279.    
  6280.                 // Mobile/Embedded OS
  6281.                 /\((bb)(10);/i                                                      // BlackBerry 10
  6282.                 ], [[NAME, 'BlackBerry'], VERSION], [
  6283.                 /(blackberry)\w*\/?([\w\.]+)*/i,                                    // Blackberry
  6284.                 /(tizen)\/([\w\.]+)/i,                                              // Tizen
  6285.                 /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i
  6286.                                                                                     // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo
  6287.                 ], [NAME, VERSION], [
  6288.                 /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i                 // Symbian
  6289.                 ], [[NAME, 'Symbian'], VERSION],[
  6290.                 /mozilla.+\(mobile;.+gecko.+firefox/i                               // Firefox OS
  6291.                 ], [[NAME, 'Firefox OS'], VERSION], [
  6292.    
  6293.                 // Console
  6294.                 /(nintendo|playstation)\s([wids3portablevu]+)/i,                    // Nintendo/Playstation
  6295.    
  6296.                 // GNU/Linux based
  6297.                 /(mint)[\/\s\(]?(\w+)*/i,                                           // Mint
  6298.                 /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i,
  6299.                                                                                     // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
  6300.                                                                                     // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk
  6301.                 /(hurd|linux)\s?([\w\.]+)*/i,                                       // Hurd/Linux
  6302.                 /(gnu)\s?([\w\.]+)*/i                                               // GNU
  6303.                 ], [NAME, VERSION], [
  6304.    
  6305.                 /(cros)\s[\w]+\s([\w\.]+\w)/i                                       // Chromium OS
  6306.                 ], [[NAME, 'Chromium OS'], VERSION],[
  6307.    
  6308.                 // Solaris
  6309.                 /(sunos)\s?([\w\.]+\d)*/i                                           // Solaris
  6310.                 ], [[NAME, 'Solaris'], VERSION], [
  6311.    
  6312.                 // BSD based
  6313.                 /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i                   // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
  6314.                 ], [NAME, VERSION],[
  6315.    
  6316.                 /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i             // iOS
  6317.                 ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
  6318.    
  6319.                 /(mac\sos\sx)\s?([\w\s\.]+\w)*/i                                    // Mac OS
  6320.                 ], [NAME, [VERSION, /_/g, '.']], [
  6321.    
  6322.                 // Other
  6323.                 /(haiku)\s(\w+)/i,                                                  // Haiku
  6324.                 /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,                               // AIX
  6325.                 /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i,
  6326.                                                                                     // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS
  6327.                 /(unix)\s?([\w\.]+)*/i                                              // UNIX
  6328.                 ], [NAME, VERSION]
  6329.             ]
  6330.         };
  6331.    
  6332.    
  6333.         /////////////////
  6334.         // Constructor
  6335.         ////////////////
  6336.    
  6337.    
  6338.         var UAParser = function (uastring) {
  6339.    
  6340.             var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
  6341.    
  6342.             if (!(this instanceof UAParser)) {
  6343.                 return new UAParser(uastring).getResult();
  6344.             }
  6345.             this.getBrowser = function () {
  6346.                 return mapper.rgx.apply(this, regexes.browser);
  6347.             };
  6348.             this.getCPU = function () {
  6349.                 return mapper.rgx.apply(this, regexes.cpu);
  6350.             };
  6351.             this.getDevice = function () {
  6352.                 return mapper.rgx.apply(this, regexes.device);
  6353.             };
  6354.             this.getEngine = function () {
  6355.                 return mapper.rgx.apply(this, regexes.engine);
  6356.             };
  6357.             this.getOS = function () {
  6358.                 return mapper.rgx.apply(this, regexes.os);
  6359.             };
  6360.             this.getResult = function() {
  6361.                 return {
  6362.                     ua      : this.getUA(),
  6363.                     browser : this.getBrowser(),
  6364.                     engine  : this.getEngine(),
  6365.                     os      : this.getOS(),
  6366.                     device  : this.getDevice(),
  6367.                     cpu     : this.getCPU()
  6368.                 };
  6369.             };
  6370.             this.getUA = function () {
  6371.                 return ua;
  6372.             };
  6373.             this.setUA = function (uastring) {
  6374.                 ua = uastring;
  6375.                 return this;
  6376.             };
  6377.             this.setUA(ua);
  6378.         };
  6379.    
  6380.    
  6381.         ///////////
  6382.         // Export
  6383.         //////////
  6384.    
  6385.    
  6386.         // check js environment
  6387.         if (typeof(exports) !== UNDEF_TYPE) {
  6388.             // nodejs env
  6389.             if (typeof(module) !== UNDEF_TYPE && module.exports) {
  6390.                 exports = module.exports = UAParser;
  6391.             }
  6392.             exports.UAParser = UAParser;
  6393.         } else {
  6394.             // browser env
  6395.             window.UAParser = UAParser;        
  6396.             // requirejs env (optional)
  6397.             if (typeof(define) === FUNC_TYPE && define.amd) {
  6398.                 define(function () {
  6399.                     return UAParser;
  6400.                 });
  6401.             }
  6402.             // jQuery specific (optional)
  6403.             if (typeof(window.jQuery) !== UNDEF_TYPE) {
  6404.                 var $ = window.jQuery;
  6405.                 var parser = new UAParser();
  6406.                 $.ua = parser.getResult();
  6407.                 $.ua.get = function() {
  6408.                     return parser.getUA();
  6409.                 };
  6410.                 $.ua.set = function (uastring) {
  6411.                     parser.setUA(uastring);
  6412.                     var result = parser.getResult();
  6413.                     for (var prop in result) {
  6414.                         $.ua[prop] = result[prop];
  6415.                     }
  6416.                 };
  6417.             }
  6418.         }
  6419.    
  6420.     })(this);
  6421.     </script>
  6422.  
  6423.     <script type="text/javascript">
  6424.     // Included by bitcoinpaperwallet.com to support QR code scanning
  6425.     //https://github.com/LazarSoft/jsqrcode
  6426.     /*
  6427.       Ported to JavaScript by Lazar Laszlo 2011
  6428.  
  6429.       lazarsoft@gmail.com, www.lazarsoft.info
  6430.  
  6431.       Updated to replace Array.prototype.remove with an arrayRemove function to avoid conflicts
  6432.     */
  6433.  
  6434.     /*
  6435.     *
  6436.     * Copyright 2007 ZXing authors
  6437.     *
  6438.     * Licensed under the Apache License, Version 2.0 (the "License");
  6439.     * you may not use this file except in compliance with the License.
  6440.     * You may obtain a copy of the License at
  6441.     *
  6442.     *      http://www.apache.org/licenses/LICENSE-2.0
  6443.     *
  6444.     * Unless required by applicable law or agreed to in writing, software
  6445.     * distributed under the License is distributed on an "AS IS" BASIS,
  6446.     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6447.     * See the License for the specific language governing permissions and
  6448.     * limitations under the License.
  6449.     */
  6450.     GridSampler = {};
  6451.  
  6452.     GridSampler.checkAndNudgePoints=function( image,  points)
  6453.                     {
  6454.                             var width = qrcode.width;
  6455.                             var height = qrcode.height;
  6456.                             // Check and nudge points from start until we see some that are OK:
  6457.                             var nudged = true;
  6458.                             for (var offset = 0; offset < points.length && nudged; offset += 2)
  6459.                             {
  6460.                                     var x = Math.floor (points[offset]);
  6461.                                     var y = Math.floor( points[offset + 1]);
  6462.                                     if (x < - 1 || x > width || y < - 1 || y > height)
  6463.                                     {
  6464.                                             throw "Error.checkAndNudgePoints ";
  6465.                                     }
  6466.                                     nudged = false;
  6467.                                     if (x == - 1)
  6468.                                     {
  6469.                                             points[offset] = 0.0;
  6470.                                             nudged = true;
  6471.                                     }
  6472.                                     else if (x == width)
  6473.                                     {
  6474.                                             points[offset] = width - 1;
  6475.                                             nudged = true;
  6476.                                     }
  6477.                                     if (y == - 1)
  6478.                                     {
  6479.                                             points[offset + 1] = 0.0;
  6480.                                             nudged = true;
  6481.                                     }
  6482.                                     else if (y == height)
  6483.                                     {
  6484.                                             points[offset + 1] = height - 1;
  6485.                                             nudged = true;
  6486.                                     }
  6487.                             }
  6488.                             // Check and nudge points from end:
  6489.                             nudged = true;
  6490.                             for (var offset = points.length - 2; offset >= 0 && nudged; offset -= 2)
  6491.                             {
  6492.                                     var x = Math.floor( points[offset]);
  6493.                                     var y = Math.floor( points[offset + 1]);
  6494.                                     if (x < - 1 || x > width || y < - 1 || y > height)
  6495.                                     {
  6496.                                             throw "Error.checkAndNudgePoints ";
  6497.                                     }
  6498.                                     nudged = false;
  6499.                                     if (x == - 1)
  6500.                                     {
  6501.                                             points[offset] = 0.0;
  6502.                                             nudged = true;
  6503.                                     }
  6504.                                     else if (x == width)
  6505.                                     {
  6506.                                             points[offset] = width - 1;
  6507.                                             nudged = true;
  6508.                                     }
  6509.                                     if (y == - 1)
  6510.                                     {
  6511.                                             points[offset + 1] = 0.0;
  6512.                                             nudged = true;
  6513.                                     }
  6514.                                     else if (y == height)
  6515.                                     {
  6516.                                             points[offset + 1] = height - 1;
  6517.                                             nudged = true;
  6518.                                     }
  6519.                             }
  6520.                     }
  6521.        
  6522.  
  6523.  
  6524.     GridSampler.sampleGrid3=function( image,  dimension,  transform)
  6525.                     {
  6526.                             var bits = new BitMatrix(dimension);
  6527.                             var points = new Array(dimension << 1);
  6528.                             for (var y = 0; y < dimension; y++)
  6529.                             {
  6530.                                     var max = points.length;
  6531.                                     var iValue =  y + 0.5;
  6532.                                     for (var x = 0; x < max; x += 2)
  6533.                                     {
  6534.                                             points[x] =  (x >> 1) + 0.5;
  6535.                                             points[x + 1] = iValue;
  6536.                                     }
  6537.                                     transform.transformPoints1(points);
  6538.                                     // Quick check to see if points transformed to something inside the image;
  6539.                                     // sufficient to check the endpoints
  6540.                                     GridSampler.checkAndNudgePoints(image, points);
  6541.                                     try
  6542.                                     {
  6543.                                             for (var x = 0; x < max; x += 2)
  6544.                                             {
  6545.                                                     var xpoint = (Math.floor( points[x]) * 4) + (Math.floor( points[x + 1]) * qrcode.width * 4);
  6546.                             var bit = image[Math.floor( points[x])+ qrcode.width* Math.floor( points[x + 1])];
  6547.                                                     qrcode.imagedata.data[xpoint] = bit?255:0;
  6548.                                                     qrcode.imagedata.data[xpoint+1] = bit?255:0;
  6549.                                                     qrcode.imagedata.data[xpoint+2] = 0;
  6550.                                                     qrcode.imagedata.data[xpoint+3] = 255;
  6551.                                                     //bits[x >> 1][ y]=bit;
  6552.                                                     if(bit)
  6553.                                                             bits.set_Renamed(x >> 1, y);
  6554.                                             }
  6555.                                     }
  6556.                                     catch ( aioobe)
  6557.                                     {
  6558.                                             // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
  6559.                                             // transform gets "twisted" such that it maps a straight line of points to a set of points
  6560.                                             // whose endpoints are in bounds, but others are not. There is probably some mathematical
  6561.                                             // way to detect this about the transformation that I don't know yet.
  6562.                                             // This results in an ugly runtime exception despite our clever checks above -- can't have
  6563.                                             // that. We could check each point's coordinates but that feels duplicative. We settle for
  6564.                                             // catching and wrapping ArrayIndexOutOfBoundsException.
  6565.                                             throw "Error.checkAndNudgePoints";
  6566.                                     }
  6567.                             }
  6568.                             return bits;
  6569.                     }
  6570.  
  6571.     GridSampler.sampleGridx=function( image,  dimension,  p1ToX,  p1ToY,  p2ToX,  p2ToY,  p3ToX,  p3ToY,  p4ToX,  p4ToY,  p1FromX,  p1FromY,  p2FromX,  p2FromY,  p3FromX,  p3FromY,  p4FromX,  p4FromY)
  6572.     {
  6573.             var transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
  6574.                        
  6575.             return GridSampler.sampleGrid3(image, dimension, transform);
  6576.     }
  6577.  
  6578.     function ECB(count,  dataCodewords)
  6579.     {
  6580.             this.count = count;
  6581.             this.dataCodewords = dataCodewords;
  6582.        
  6583.             this.__defineGetter__("Count", function()
  6584.             {
  6585.                     return this.count;
  6586.             });
  6587.             this.__defineGetter__("DataCodewords", function()
  6588.             {
  6589.                     return this.dataCodewords;
  6590.             });
  6591.     }
  6592.  
  6593.     function ECBlocks( ecCodewordsPerBlock,  ecBlocks1,  ecBlocks2)
  6594.     {
  6595.             this.ecCodewordsPerBlock = ecCodewordsPerBlock;
  6596.             if(ecBlocks2)
  6597.                     this.ecBlocks = new Array(ecBlocks1, ecBlocks2);
  6598.             else
  6599.                     this.ecBlocks = new Array(ecBlocks1);
  6600.        
  6601.             this.__defineGetter__("ECCodewordsPerBlock", function()
  6602.             {
  6603.                     return this.ecCodewordsPerBlock;
  6604.             });
  6605.        
  6606.             this.__defineGetter__("TotalECCodewords", function()
  6607.             {
  6608.                     return  this.ecCodewordsPerBlock * this.NumBlocks;
  6609.             });
  6610.        
  6611.             this.__defineGetter__("NumBlocks", function()
  6612.             {
  6613.                     var total = 0;
  6614.                     for (var i = 0; i < this.ecBlocks.length; i++)
  6615.                     {
  6616.                             total += this.ecBlocks[i].length;
  6617.                     }
  6618.                     return total;
  6619.             });
  6620.        
  6621.             this.getECBlocks=function()
  6622.                             {
  6623.                                     return this.ecBlocks;
  6624.                             }
  6625.     }
  6626.  
  6627.     function Version( versionNumber,  alignmentPatternCenters,  ecBlocks1,  ecBlocks2,  ecBlocks3,  ecBlocks4)
  6628.     {
  6629.             this.versionNumber = versionNumber;
  6630.             this.alignmentPatternCenters = alignmentPatternCenters;
  6631.             this.ecBlocks = new Array(ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4);
  6632.        
  6633.             var total = 0;
  6634.             var ecCodewords = ecBlocks1.ECCodewordsPerBlock;
  6635.             var ecbArray = ecBlocks1.getECBlocks();
  6636.             for (var i = 0; i < ecbArray.length; i++)
  6637.             {
  6638.                     var ecBlock = ecbArray[i];
  6639.                     total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
  6640.             }
  6641.             this.totalCodewords = total;
  6642.        
  6643.             this.__defineGetter__("VersionNumber", function()
  6644.             {
  6645.                     return  this.versionNumber;
  6646.             });
  6647.        
  6648.             this.__defineGetter__("AlignmentPatternCenters", function()
  6649.             {
  6650.                     return  this.alignmentPatternCenters;
  6651.             });
  6652.             this.__defineGetter__("TotalCodewords", function()
  6653.             {
  6654.                     return  this.totalCodewords;
  6655.             });
  6656.             this.__defineGetter__("DimensionForVersion", function()
  6657.             {
  6658.                     return  17 + 4 * this.versionNumber;
  6659.             });
  6660.        
  6661.             this.buildFunctionPattern=function()
  6662.                     {
  6663.                             var dimension = this.DimensionForVersion;
  6664.                             var bitMatrix = new BitMatrix(dimension);
  6665.                        
  6666.                             // Top left finder pattern + separator + format
  6667.                             bitMatrix.setRegion(0, 0, 9, 9);
  6668.                             // Top right finder pattern + separator + format
  6669.                             bitMatrix.setRegion(dimension - 8, 0, 8, 9);
  6670.                             // Bottom left finder pattern + separator + format
  6671.                             bitMatrix.setRegion(0, dimension - 8, 9, 8);
  6672.                        
  6673.                             // Alignment patterns
  6674.                             var max = this.alignmentPatternCenters.length;
  6675.                             for (var x = 0; x < max; x++)
  6676.                             {
  6677.                                     var i = this.alignmentPatternCenters[x] - 2;
  6678.                                     for (var y = 0; y < max; y++)
  6679.                                     {
  6680.                                             if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
  6681.                                             {
  6682.                                                     // No alignment patterns near the three finder paterns
  6683.                                                     continue;
  6684.                                             }
  6685.                                             bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5);
  6686.                                     }
  6687.                             }
  6688.                        
  6689.                             // Vertical timing pattern
  6690.                             bitMatrix.setRegion(6, 9, 1, dimension - 17);
  6691.                             // Horizontal timing pattern
  6692.                             bitMatrix.setRegion(9, 6, dimension - 17, 1);
  6693.                        
  6694.                             if (this.versionNumber > 6)
  6695.                             {
  6696.                                     // Version info, top right
  6697.                                     bitMatrix.setRegion(dimension - 11, 0, 3, 6);
  6698.                                     // Version info, bottom left
  6699.                                     bitMatrix.setRegion(0, dimension - 11, 6, 3);
  6700.                             }
  6701.                        
  6702.                             return bitMatrix;
  6703.                     }
  6704.             this.getECBlocksForLevel=function( ecLevel)
  6705.             {
  6706.                     return this.ecBlocks[ecLevel.ordinal()];
  6707.             }
  6708.     }
  6709.  
  6710.     Version.VERSION_DECODE_INFO = new Array(0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69);
  6711.  
  6712.     Version.VERSIONS = buildVersions();
  6713.  
  6714.     Version.getVersionForNumber=function( versionNumber)
  6715.     {
  6716.             if (versionNumber < 1 || versionNumber > 40)
  6717.             {
  6718.                     throw "ArgumentException";
  6719.             }
  6720.             return Version.VERSIONS[versionNumber - 1];
  6721.     }
  6722.  
  6723.     Version.getProvisionalVersionForDimension=function(dimension)
  6724.     {
  6725.             if (dimension % 4 != 1)
  6726.             {
  6727.                     throw "Error getProvisionalVersionForDimension";
  6728.             }
  6729.             try
  6730.             {
  6731.                     return Version.getVersionForNumber((dimension - 17) >> 2);
  6732.             }
  6733.             catch ( iae)
  6734.             {
  6735.                     throw "Error getVersionForNumber";
  6736.             }
  6737.     }
  6738.  
  6739.     Version.decodeVersionInformation=function( versionBits)
  6740.     {
  6741.             var bestDifference = 0xffffffff;
  6742.             var bestVersion = 0;
  6743.             for (var i = 0; i < Version.VERSION_DECODE_INFO.length; i++)
  6744.             {
  6745.                     var targetVersion = Version.VERSION_DECODE_INFO[i];
  6746.                     // Do the version info bits match exactly? done.
  6747.                     if (targetVersion == versionBits)
  6748.                     {
  6749.                             return this.getVersionForNumber(i + 7);
  6750.                     }
  6751.                     // Otherwise see if this is the closest to a real version info bit string
  6752.                     // we have seen so far
  6753.                     var bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
  6754.                     if (bitsDifference < bestDifference)
  6755.                     {
  6756.                             bestVersion = i + 7;
  6757.                             bestDifference = bitsDifference;
  6758.                     }
  6759.             }
  6760.             // We can tolerate up to 3 bits of error since no two version info codewords will
  6761.             // differ in less than 4 bits.
  6762.             if (bestDifference <= 3)
  6763.             {
  6764.                     return this.getVersionForNumber(bestVersion);
  6765.             }
  6766.             // If we didn't find a close enough match, fail
  6767.             return null;
  6768.     }
  6769.     function buildVersions()
  6770.     {
  6771.             return new Array(new Version(1, new Array(), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))),
  6772.             new Version(2, new Array(6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))),
  6773.             new Version(3, new Array(6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))),
  6774.             new Version(4, new Array(6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))),
  6775.             new Version(5, new Array(6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))),
  6776.             new Version(6, new Array(6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))),
  6777.             new Version(7, new Array(6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))),
  6778.             new Version(8, new Array(6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))),
  6779.             new Version(9, new Array(6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))),
  6780.             new Version(10, new Array(6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))),
  6781.             new Version(11, new Array(6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))),
  6782.             new Version(12, new Array(6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))),
  6783.             new Version(13, new Array(6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))),
  6784.             new Version(14, new Array(6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))),
  6785.             new Version(15, new Array(6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))),
  6786.             new Version(16, new Array(6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))),
  6787.             new Version(17, new Array(6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))),
  6788.             new Version(18, new Array(6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))),
  6789.             new Version(19, new Array(6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))),
  6790.             new Version(20, new Array(6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))),
  6791.             new Version(21, new Array(6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))),
  6792.             new Version(22, new Array(6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))),
  6793.             new Version(23, new Array(6, 30, 54, 74, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))),
  6794.             new Version(24, new Array(6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))),
  6795.             new Version(25, new Array(6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))),
  6796.             new Version(26, new Array(6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))),
  6797.             new Version(27, new Array(6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15),                 new ECB(28, 16))),
  6798.             new Version(28, new Array(6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))),
  6799.             new Version(29, new Array(6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))),
  6800.             new Version(30, new Array(6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))),
  6801.             new Version(31, new Array(6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))),
  6802.             new Version(32, new Array(6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))),
  6803.             new Version(33, new Array(6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))),
  6804.             new Version(34, new Array(6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))),
  6805.             new Version(35, new Array(6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)),new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))),
  6806.             new Version(36, new Array(6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))),
  6807.             new Version(37, new Array(6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))),
  6808.             new Version(38, new Array(6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))),
  6809.             new Version(39, new Array(6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))),
  6810.             new Version(40, new Array(6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16))));
  6811.     }
  6812.     function PerspectiveTransform( a11,  a21,  a31,  a12,  a22,  a32,  a13,  a23,  a33)
  6813.     {
  6814.             this.a11 = a11;
  6815.             this.a12 = a12;
  6816.             this.a13 = a13;
  6817.             this.a21 = a21;
  6818.             this.a22 = a22;
  6819.             this.a23 = a23;
  6820.             this.a31 = a31;
  6821.             this.a32 = a32;
  6822.             this.a33 = a33;
  6823.             this.transformPoints1=function( points)
  6824.                     {
  6825.                             var max = points.length;
  6826.                             var a11 = this.a11;
  6827.                             var a12 = this.a12;
  6828.                             var a13 = this.a13;
  6829.                             var a21 = this.a21;
  6830.                             var a22 = this.a22;
  6831.                             var a23 = this.a23;
  6832.                             var a31 = this.a31;
  6833.                             var a32 = this.a32;
  6834.                             var a33 = this.a33;
  6835.                             for (var i = 0; i < max; i += 2)
  6836.                             {
  6837.                                     var x = points[i];
  6838.                                     var y = points[i + 1];
  6839.                                     var denominator = a13 * x + a23 * y + a33;
  6840.                                     points[i] = (a11 * x + a21 * y + a31) / denominator;
  6841.                                     points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
  6842.                             }
  6843.                     }
  6844.             this. transformPoints2=function(xValues, yValues)
  6845.                     {
  6846.                             var n = xValues.length;
  6847.                             for (var i = 0; i < n; i++)
  6848.                             {
  6849.                                     var x = xValues[i];
  6850.                                     var y = yValues[i];
  6851.                                     var denominator = this.a13 * x + this.a23 * y + this.a33;
  6852.                                     xValues[i] = (this.a11 * x + this.a21 * y + this.a31) / denominator;
  6853.                                     yValues[i] = (this.a12 * x + this.a22 * y + this.a32) / denominator;
  6854.                             }
  6855.                     }
  6856.             this.buildAdjoint=function()
  6857.                     {
  6858.                             // Adjoint is the transpose of the cofactor matrix:
  6859.                             return new PerspectiveTransform(this.a22 * this.a33 - this.a23 * this.a32, this.a23 * this.a31 - this.a21 * this.a33, this.a21 * this.a32 - this.a22 * this.a31, this.a13 * this.a32 - this.a12 * this.a33, this.a11 * this.a33 - this.a13 * this.a31, this.a12 * this.a31 - this.a11 * this.a32, this.a12 * this.a23 - this.a13 * this.a22, this.a13 * this.a21 - this.a11 * this.a23, this.a11 * this.a22 - this.a12 * this.a21);
  6860.                     }
  6861.             this.times=function( other)
  6862.                     {
  6863.                             return new PerspectiveTransform(this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13, this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23, this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33, this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13, this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23, this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33, this.a13 * other.a11 + this.a23 * other.a12 +this.a33 * other.a13, this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23, this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33);
  6864.                     }
  6865.     }
  6866.     PerspectiveTransform.quadrilateralToQuadrilateral=function( x0,  y0,  x1,  y1,  x2,  y2,  x3,  y3,  x0p,  y0p,  x1p,  y1p,  x2p,  y2p,  x3p,  y3p)
  6867.     {
  6868.        
  6869.             var qToS = this.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  6870.             var sToQ = this.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  6871.             return sToQ.times(qToS);
  6872.     }
  6873.     PerspectiveTransform.squareToQuadrilateral=function( x0,  y0,  x1,  y1,  x2,  y2,  x3,  y3)
  6874.     {
  6875.              dy2 = y3 - y2;
  6876.              dy3 = y0 - y1 + y2 - y3;
  6877.             if (dy2 == 0.0 && dy3 == 0.0)
  6878.             {
  6879.                     return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0);
  6880.             }
  6881.             else
  6882.             {
  6883.                      dx1 = x1 - x2;
  6884.                      dx2 = x3 - x2;
  6885.                      dx3 = x0 - x1 + x2 - x3;
  6886.                      dy1 = y1 - y2;
  6887.                      denominator = dx1 * dy2 - dx2 * dy1;
  6888.                      a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
  6889.                      a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
  6890.                     return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0);
  6891.             }
  6892.     }
  6893.     PerspectiveTransform.quadrilateralToSquare=function( x0,  y0,  x1,  y1,  x2,  y2,  x3,  y3)
  6894.     {
  6895.             // Here, the adjoint serves as the inverse:
  6896.             return this.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
  6897.     }
  6898.     function DetectorResult(bits,  points)
  6899.     {
  6900.             this.bits = bits;
  6901.             this.points = points;
  6902.     }
  6903.     function Detector(image)
  6904.     {
  6905.             this.image=image;
  6906.             this.resultPointCallback = null;
  6907.        
  6908.             this.sizeOfBlackWhiteBlackRun=function( fromX,  fromY,  toX,  toY)
  6909.                     {
  6910.                             // Mild variant of Bresenham's algorithm;
  6911.                             // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
  6912.                             var steep = Math.abs(toY - fromY) > Math.abs(toX - fromX);
  6913.                             if (steep)
  6914.                             {
  6915.                                     var temp = fromX;
  6916.                                     fromX = fromY;
  6917.                                     fromY = temp;
  6918.                                     temp = toX;
  6919.                                     toX = toY;
  6920.                                     toY = temp;
  6921.                             }
  6922.                        
  6923.                             var dx = Math.abs(toX - fromX);
  6924.                             var dy = Math.abs(toY - fromY);
  6925.                             var error = - dx >> 1;
  6926.                             var ystep = fromY < toY?1:- 1;
  6927.                             var xstep = fromX < toX?1:- 1;
  6928.                             var state = 0; // In black pixels, looking for white, first or second time
  6929.                             for (var x = fromX, y = fromY; x != toX; x += xstep)
  6930.                             {
  6931.                                
  6932.                                     var realX = steep?y:x;
  6933.                                     var realY = steep?x:y;
  6934.                                     if (state == 1)
  6935.                                     {
  6936.                                             // In white pixels, looking for black
  6937.                                             if (this.image[realX + realY*qrcode.width])
  6938.                                             {
  6939.                                                     state++;
  6940.                                             }
  6941.                                     }
  6942.                                     else
  6943.                                     {
  6944.                                             if (!this.image[realX + realY*qrcode.width])
  6945.                                             {
  6946.                                                     state++;
  6947.                                             }
  6948.                                     }
  6949.                                
  6950.                                     if (state == 3)
  6951.                                     {
  6952.                                             // Found black, white, black, and stumbled back onto white; done
  6953.                                             var diffX = x - fromX;
  6954.                                             var diffY = y - fromY;
  6955.                                             return  Math.sqrt( (diffX * diffX + diffY * diffY));
  6956.                                     }
  6957.                                     error += dy;
  6958.                                     if (error > 0)
  6959.                                     {
  6960.                                             if (y == toY)
  6961.                                             {
  6962.                                                     break;
  6963.                                             }
  6964.                                             y += ystep;
  6965.                                             error -= dx;
  6966.                                     }
  6967.                             }
  6968.                             var diffX2 = toX - fromX;
  6969.                             var diffY2 = toY - fromY;
  6970.                             return  Math.sqrt( (diffX2 * diffX2 + diffY2 * diffY2));
  6971.                     }
  6972.  
  6973.        
  6974.             this.sizeOfBlackWhiteBlackRunBothWays=function( fromX,  fromY,  toX,  toY)
  6975.                     {
  6976.                        
  6977.                             var result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
  6978.                        
  6979.                             // Now count other way -- don't run off image though of course
  6980.                             var scale = 1.0;
  6981.                             var otherToX = fromX - (toX - fromX);
  6982.                             if (otherToX < 0)
  6983.                             {
  6984.                                     scale =  fromX /  (fromX - otherToX);
  6985.                                     otherToX = 0;
  6986.                             }
  6987.                             else if (otherToX >= qrcode.width)
  6988.                             {
  6989.                                     scale =  (qrcode.width - 1 - fromX) /  (otherToX - fromX);
  6990.                                     otherToX = qrcode.width - 1;
  6991.                             }
  6992.                             var otherToY = Math.floor (fromY - (toY - fromY) * scale);
  6993.                        
  6994.                             scale = 1.0;
  6995.                             if (otherToY < 0)
  6996.                             {
  6997.                                     scale =  fromY /  (fromY - otherToY);
  6998.                                     otherToY = 0;
  6999.                             }
  7000.                             else if (otherToY >= qrcode.height)
  7001.                             {
  7002.                                     scale =  (qrcode.height - 1 - fromY) /  (otherToY - fromY);
  7003.                                     otherToY = qrcode.height - 1;
  7004.                             }
  7005.                             otherToX = Math.floor (fromX + (otherToX - fromX) * scale);
  7006.                        
  7007.                             result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
  7008.                             return result - 1.0; // -1 because we counted the middle pixel twice
  7009.                     }
  7010.                
  7011.  
  7012.        
  7013.             this.calculateModuleSizeOneWay=function( pattern,  otherPattern)
  7014.                     {
  7015.                             var moduleSizeEst1 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor( pattern.X), Math.floor( pattern.Y), Math.floor( otherPattern.X), Math.floor(otherPattern.Y));
  7016.                             var moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(otherPattern.X), Math.floor(otherPattern.Y), Math.floor( pattern.X), Math.floor(pattern.Y));
  7017.                             if (isNaN(moduleSizeEst1))
  7018.                             {
  7019.                                     return moduleSizeEst2 / 7.0;
  7020.                             }
  7021.                             if (isNaN(moduleSizeEst2))
  7022.                             {
  7023.                                     return moduleSizeEst1 / 7.0;
  7024.                             }
  7025.                             // Average them, and divide by 7 since we've counted the width of 3 black modules,
  7026.                             // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
  7027.                             return (moduleSizeEst1 + moduleSizeEst2) / 14.0;
  7028.                     }
  7029.  
  7030.        
  7031.             this.calculateModuleSize=function( topLeft,  topRight,  bottomLeft)
  7032.                     {
  7033.                             // Take the average
  7034.                             return (this.calculateModuleSizeOneWay(topLeft, topRight) + this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0;
  7035.                     }
  7036.  
  7037.             this.distance=function( pattern1,  pattern2)
  7038.             {
  7039.                     xDiff = pattern1.X - pattern2.X;
  7040.                     yDiff = pattern1.Y - pattern2.Y;
  7041.                     return  Math.sqrt( (xDiff * xDiff + yDiff * yDiff));
  7042.             }
  7043.             this.computeDimension=function( topLeft,  topRight,  bottomLeft,  moduleSize)
  7044.                     {
  7045.                        
  7046.                             var tltrCentersDimension = Math.round(this.distance(topLeft, topRight) / moduleSize);
  7047.                             var tlblCentersDimension = Math.round(this.distance(topLeft, bottomLeft) / moduleSize);
  7048.                             var dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
  7049.                             switch (dimension & 0x03)
  7050.                             {
  7051.                                
  7052.                                     // mod 4
  7053.                                     case 0:
  7054.                                             dimension++;
  7055.                                             break;
  7056.                                             // 1? do nothing
  7057.                                
  7058.                                     case 2:
  7059.                                             dimension--;
  7060.                                             break;
  7061.                                
  7062.                                     case 3:
  7063.                                             throw "Error";
  7064.                                     }
  7065.                             return dimension;
  7066.                     }
  7067.  
  7068.             this.findAlignmentInRegion=function( overallEstModuleSize,  estAlignmentX,  estAlignmentY,  allowanceFactor)
  7069.                     {
  7070.                             // Look for an alignment pattern (3 modules in size) around where it
  7071.                             // should be
  7072.                             var allowance = Math.floor (allowanceFactor * overallEstModuleSize);
  7073.                             var alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
  7074.                             var alignmentAreaRightX = Math.min(qrcode.width - 1, estAlignmentX + allowance);
  7075.                             if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3)
  7076.                             {
  7077.                                     throw "Error";
  7078.                             }
  7079.                        
  7080.                             var alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
  7081.                             var alignmentAreaBottomY = Math.min(qrcode.height - 1, estAlignmentY + allowance);
  7082.                        
  7083.                             var alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback);
  7084.                             return alignmentFinder.find();
  7085.                     }
  7086.                
  7087.             this.createTransform=function( topLeft,  topRight,  bottomLeft, alignmentPattern, dimension)
  7088.                     {
  7089.                             var dimMinusThree =  dimension - 3.5;
  7090.                             var bottomRightX;
  7091.                             var bottomRightY;
  7092.                             var sourceBottomRightX;
  7093.                             var sourceBottomRightY;
  7094.                             if (alignmentPattern != null)
  7095.                             {
  7096.                                     bottomRightX = alignmentPattern.X;
  7097.                                     bottomRightY = alignmentPattern.Y;
  7098.                                     sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0;
  7099.                             }
  7100.                             else
  7101.                             {
  7102.                                     // Don't have an alignment pattern, just make up the bottom-right point
  7103.                                     bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X;
  7104.                                     bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y;
  7105.                                     sourceBottomRightX = sourceBottomRightY = dimMinusThree;
  7106.                             }
  7107.                        
  7108.                             var transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y);
  7109.                        
  7110.                             return transform;
  7111.                     }                
  7112.        
  7113.             this.sampleGrid=function( image,  transform,  dimension)
  7114.                     {
  7115.                        
  7116.                             var sampler = GridSampler;
  7117.                             return sampler.sampleGrid3(image, dimension, transform);
  7118.                     }
  7119.        
  7120.             this.processFinderPatternInfo = function( info)
  7121.                     {
  7122.                        
  7123.                             var topLeft = info.TopLeft;
  7124.                             var topRight = info.TopRight;
  7125.                             var bottomLeft = info.BottomLeft;
  7126.                        
  7127.                             var moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft);
  7128.                             if (moduleSize < 1.0)
  7129.                             {
  7130.                                     throw "Error";
  7131.                             }
  7132.                             var dimension = this.computeDimension(topLeft, topRight, bottomLeft, moduleSize);
  7133.                             var provisionalVersion = Version.getProvisionalVersionForDimension(dimension);
  7134.                             var modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7;
  7135.                        
  7136.                             var alignmentPattern = null;
  7137.                             // Anything above version 1 has an alignment pattern
  7138.                             if (provisionalVersion.AlignmentPatternCenters.length > 0)
  7139.                             {
  7140.                                
  7141.                                     // Guess where a "bottom right" finder pattern would have been
  7142.                                     var bottomRightX = topRight.X - topLeft.X + bottomLeft.X;
  7143.                                     var bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y;
  7144.                                
  7145.                                     // Estimate that alignment pattern is closer by 3 modules
  7146.                                     // from "bottom right" to known top left location
  7147.                                     var correctionToTopLeft = 1.0 - 3.0 /  modulesBetweenFPCenters;
  7148.                                     var estAlignmentX = Math.floor (topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X));
  7149.                                     var estAlignmentY = Math.floor (topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y));
  7150.                                
  7151.                                     // Kind of arbitrary -- expand search radius before giving up
  7152.                                     for (var i = 4; i <= 16; i <<= 1)
  7153.                                     {
  7154.                                             //try
  7155.                                             //{
  7156.                                                     alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY,  i);
  7157.                                                     break;
  7158.                                             //}
  7159.                                             //catch (re)
  7160.                                             //{
  7161.                                                     // try next round
  7162.                                             //}
  7163.                                     }
  7164.                                     // If we didn't find alignment pattern... well try anyway without it
  7165.                             }
  7166.                        
  7167.                             var transform = this.createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
  7168.                        
  7169.                             var bits = this.sampleGrid(this.image, transform, dimension);
  7170.                        
  7171.                             var points;
  7172.                             if (alignmentPattern == null)
  7173.                             {
  7174.                                     points = new Array(bottomLeft, topLeft, topRight);
  7175.                             }
  7176.                             else
  7177.                             {
  7178.                                     points = new Array(bottomLeft, topLeft, topRight, alignmentPattern);
  7179.                             }
  7180.                             return new DetectorResult(bits, points);
  7181.                     }
  7182.                
  7183.        
  7184.             this.detect=function()
  7185.             {
  7186.                     var info =  new FinderPatternFinder().findFinderPattern(this.image);
  7187.                        
  7188.                     return this.processFinderPatternInfo(info);
  7189.             }
  7190.     }
  7191.     var FORMAT_INFO_MASK_QR = 0x5412;
  7192.     var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F));
  7193.     var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
  7194.     function FormatInformation(formatInfo)
  7195.     {
  7196.             this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
  7197.             this.dataMask =  (formatInfo & 0x07);
  7198.  
  7199.             this.__defineGetter__("ErrorCorrectionLevel", function()
  7200.             {
  7201.                     return this.errorCorrectionLevel;
  7202.             });
  7203.             this.__defineGetter__("DataMask", function()
  7204.             {
  7205.                     return this.dataMask;
  7206.             });
  7207.             this.GetHashCode=function()
  7208.             {
  7209.                     return (this.errorCorrectionLevel.ordinal() << 3) |  dataMask;
  7210.             }
  7211.             this.Equals=function( o)
  7212.             {
  7213.                     var other =  o;
  7214.                     return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask;
  7215.             }
  7216.     }
  7217.  
  7218.     FormatInformation.numBitsDiffering=function( a,  b)
  7219.     {
  7220.             a ^= b; // a now has a 1 bit exactly where its bit differs with b's
  7221.             // Count bits set quickly with a series of lookups:
  7222.             return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 28) & 0x0F)];
  7223.     }
  7224.     FormatInformation.decodeFormatInformation=function( maskedFormatInfo)
  7225.     {
  7226.             var formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo);
  7227.             if (formatInfo != null)
  7228.             {
  7229.                     return formatInfo;
  7230.             }
  7231.             // Should return null, but, some QR codes apparently
  7232.             // do not mask this info. Try again by actually masking the pattern
  7233.             // first
  7234.             return FormatInformation.doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR);
  7235.     }
  7236.     FormatInformation.doDecodeFormatInformation=function( maskedFormatInfo)
  7237.     {
  7238.             // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
  7239.             var bestDifference = 0xffffffff;
  7240.             var bestFormatInfo = 0;
  7241.             for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++)
  7242.             {
  7243.                     var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
  7244.                     var targetInfo = decodeInfo[0];
  7245.                     if (targetInfo == maskedFormatInfo)
  7246.                     {
  7247.                             // Found an exact match
  7248.                             return new FormatInformation(decodeInfo[1]);
  7249.                     }
  7250.                     var bitsDifference = this.numBitsDiffering(maskedFormatInfo, targetInfo);
  7251.                     if (bitsDifference < bestDifference)
  7252.                     {
  7253.                             bestFormatInfo = decodeInfo[1];
  7254.                             bestDifference = bitsDifference;
  7255.                     }
  7256.             }
  7257.             // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
  7258.             // differing means we found a match
  7259.             if (bestDifference <= 3)
  7260.             {
  7261.                     return new FormatInformation(bestFormatInfo);
  7262.             }
  7263.             return null;
  7264.     }
  7265.     function ErrorCorrectionLevel(ordinal,  bits, name)
  7266.     {
  7267.             this.ordinal_Renamed_Field = ordinal;
  7268.             this.bits = bits;
  7269.             this.name = name;
  7270.             this.__defineGetter__("Bits", function()
  7271.             {
  7272.                     return this.bits;
  7273.             });
  7274.             this.__defineGetter__("Name", function()
  7275.             {
  7276.                     return this.name;
  7277.             });
  7278.             this.ordinal=function()
  7279.             {
  7280.                     return this.ordinal_Renamed_Field;
  7281.             }
  7282.     }
  7283.     ErrorCorrectionLevel.forBits=function( bits)
  7284.     {
  7285.             if (bits < 0 || bits >= FOR_BITS.length)
  7286.             {
  7287.                     throw "ArgumentException";
  7288.             }
  7289.             return FOR_BITS[bits];
  7290.     }
  7291.  
  7292.     var L = new ErrorCorrectionLevel(0, 0x01, "L");
  7293.     var M = new ErrorCorrectionLevel(1, 0x00, "M");
  7294.     var Q = new ErrorCorrectionLevel(2, 0x03, "Q");
  7295.     var H = new ErrorCorrectionLevel(3, 0x02, "H");
  7296.     var FOR_BITS = new Array( M, L, H, Q);
  7297.  
  7298.     function BitMatrix( width,  height)
  7299.     {
  7300.             if(!height)
  7301.                     height=width;
  7302.             if (width < 1 || height < 1)
  7303.             {
  7304.                     throw "Both dimensions must be greater than 0";
  7305.             }
  7306.             this.width = width;
  7307.             this.height = height;
  7308.             var rowSize = width >> 5;
  7309.             if ((width & 0x1f) != 0)
  7310.             {
  7311.                     rowSize++;
  7312.             }
  7313.             this.rowSize = rowSize;
  7314.             this.bits = new Array(rowSize * height);
  7315.             for(var i=0;i<this.bits.length;i++)
  7316.                     this.bits[i]=0;
  7317.        
  7318.             this.__defineGetter__("Width", function()
  7319.             {
  7320.                     return this.width;
  7321.             });
  7322.             this.__defineGetter__("Height", function()
  7323.             {
  7324.                     return this.height;
  7325.             });
  7326.             this.__defineGetter__("Dimension", function()
  7327.             {
  7328.                     if (this.width != this.height)
  7329.                     {
  7330.                             throw "Can't call getDimension() on a non-square matrix";
  7331.                     }
  7332.                     return this.width;
  7333.             });
  7334.        
  7335.             this.get_Renamed=function( x,  y)
  7336.                     {
  7337.                             var offset = y * this.rowSize + (x >> 5);
  7338.                             return ((URShift(this.bits[offset], (x & 0x1f))) & 1) != 0;
  7339.                     }
  7340.             this.set_Renamed=function( x,  y)
  7341.                     {
  7342.                             var offset = y * this.rowSize + (x >> 5);
  7343.                             this.bits[offset] |= 1 << (x & 0x1f);
  7344.                     }
  7345.             this.flip=function( x,  y)
  7346.                     {
  7347.                             var offset = y * this.rowSize + (x >> 5);
  7348.                             this.bits[offset] ^= 1 << (x & 0x1f);
  7349.                     }
  7350.             this.clear=function()
  7351.                     {
  7352.                             var max = this.bits.length;
  7353.                             for (var i = 0; i < max; i++)
  7354.                             {
  7355.                                     this.bits[i] = 0;
  7356.                             }
  7357.                     }
  7358.             this.setRegion=function( left,  top,  width,  height)
  7359.                     {
  7360.                             if (top < 0 || left < 0)
  7361.                             {
  7362.                                     throw "Left and top must be nonnegative";
  7363.                             }
  7364.                             if (height < 1 || width < 1)
  7365.                             {
  7366.                                     throw "Height and width must be at least 1";
  7367.                             }
  7368.                             var right = left + width;
  7369.                             var bottom = top + height;
  7370.                             if (bottom > this.height || right > this.width)
  7371.                             {
  7372.                                     throw "The region must fit inside the matrix";
  7373.                             }
  7374.                             for (var y = top; y < bottom; y++)
  7375.                             {
  7376.                                     var offset = y * this.rowSize;
  7377.                                     for (var x = left; x < right; x++)
  7378.                                     {
  7379.                                             this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
  7380.                                     }
  7381.                             }
  7382.                     }
  7383.     }
  7384.  
  7385.     function DataBlock(numDataCodewords,  codewords)
  7386.     {
  7387.             this.numDataCodewords = numDataCodewords;
  7388.             this.codewords = codewords;
  7389.        
  7390.             this.__defineGetter__("NumDataCodewords", function()
  7391.             {
  7392.                     return this.numDataCodewords;
  7393.             });
  7394.             this.__defineGetter__("Codewords", function()
  7395.             {
  7396.                     return this.codewords;
  7397.             });
  7398.     }        
  7399.        
  7400.     DataBlock.getDataBlocks=function(rawCodewords,  version,  ecLevel)
  7401.     {
  7402.        
  7403.             if (rawCodewords.length != version.TotalCodewords)
  7404.             {
  7405.                     throw "ArgumentException";
  7406.             }
  7407.        
  7408.             // Figure out the number and size of data blocks used by this version and
  7409.             // error correction level
  7410.             var ecBlocks = version.getECBlocksForLevel(ecLevel);
  7411.        
  7412.             // First count the total number of data blocks
  7413.             var totalBlocks = 0;
  7414.             var ecBlockArray = ecBlocks.getECBlocks();
  7415.             for (var i = 0; i < ecBlockArray.length; i++)
  7416.             {
  7417.                     totalBlocks += ecBlockArray[i].Count;
  7418.             }
  7419.        
  7420.             // Now establish DataBlocks of the appropriate size and number of data codewords
  7421.             var result = new Array(totalBlocks);
  7422.             var numResultBlocks = 0;
  7423.             for (var j = 0; j < ecBlockArray.length; j++)
  7424.             {
  7425.                     var ecBlock = ecBlockArray[j];
  7426.                     for (var i = 0; i < ecBlock.Count; i++)
  7427.                     {
  7428.                             var numDataCodewords = ecBlock.DataCodewords;
  7429.                             var numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords;
  7430.                             result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords));
  7431.                     }
  7432.             }
  7433.        
  7434.             // All blocks have the same amount of data, except that the last n
  7435.             // (where n may be 0) have 1 more byte. Figure out where these start.
  7436.             var shorterBlocksTotalCodewords = result[0].codewords.length;
  7437.             var longerBlocksStartAt = result.length - 1;
  7438.             while (longerBlocksStartAt >= 0)
  7439.             {
  7440.                     var numCodewords = result[longerBlocksStartAt].codewords.length;
  7441.                     if (numCodewords == shorterBlocksTotalCodewords)
  7442.                     {
  7443.                             break;
  7444.                     }
  7445.                     longerBlocksStartAt--;
  7446.             }
  7447.             longerBlocksStartAt++;
  7448.        
  7449.             var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock;
  7450.             // The last elements of result may be 1 element longer;
  7451.             // first fill out as many elements as all of them have
  7452.             var rawCodewordsOffset = 0;
  7453.             for (var i = 0; i < shorterBlocksNumDataCodewords; i++)
  7454.             {
  7455.                     for (var j = 0; j < numResultBlocks; j++)
  7456.                     {
  7457.                             result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
  7458.                     }
  7459.             }
  7460.             // Fill out the last data block in the longer ones
  7461.             for (var j = longerBlocksStartAt; j < numResultBlocks; j++)
  7462.             {
  7463.                     result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
  7464.             }
  7465.             // Now add in error correction blocks
  7466.             var max = result[0].codewords.length;
  7467.             for (var i = shorterBlocksNumDataCodewords; i < max; i++)
  7468.             {
  7469.                     for (var j = 0; j < numResultBlocks; j++)
  7470.                     {
  7471.                             var iOffset = j < longerBlocksStartAt?i:i + 1;
  7472.                             result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
  7473.                     }
  7474.             }
  7475.             return result;
  7476.     }
  7477.  
  7478.     function BitMatrixParser(bitMatrix)
  7479.     {
  7480.             var dimension = bitMatrix.Dimension;
  7481.             if (dimension < 21 || (dimension & 0x03) != 1)
  7482.             {
  7483.                     throw "Error BitMatrixParser";
  7484.             }
  7485.             this.bitMatrix = bitMatrix;
  7486.             this.parsedVersion = null;
  7487.             this.parsedFormatInfo = null;
  7488.        
  7489.             this.copyBit=function( i,  j,  versionBits)
  7490.             {
  7491.                     return this.bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1;
  7492.             }
  7493.        
  7494.             this.readFormatInformation=function()
  7495.             {
  7496.                             if (this.parsedFormatInfo != null)
  7497.                             {
  7498.                                     return this.parsedFormatInfo;
  7499.                             }
  7500.                        
  7501.                             // Read top-left format info bits
  7502.                             var formatInfoBits = 0;
  7503.                             for (var i = 0; i < 6; i++)
  7504.                             {
  7505.                                     formatInfoBits = this.copyBit(i, 8, formatInfoBits);
  7506.                             }
  7507.                             // .. and skip a bit in the timing pattern ...
  7508.                             formatInfoBits = this.copyBit(7, 8, formatInfoBits);
  7509.                             formatInfoBits = this.copyBit(8, 8, formatInfoBits);
  7510.                             formatInfoBits = this.copyBit(8, 7, formatInfoBits);
  7511.                             // .. and skip a bit in the timing pattern ...
  7512.                             for (var j = 5; j >= 0; j--)
  7513.                             {
  7514.                                     formatInfoBits = this.copyBit(8, j, formatInfoBits);
  7515.                             }
  7516.                        
  7517.                             this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
  7518.                             if (this.parsedFormatInfo != null)
  7519.                             {
  7520.                                     return this.parsedFormatInfo;
  7521.                             }
  7522.                        
  7523.                             // Hmm, failed. Try the top-right/bottom-left pattern
  7524.                             var dimension = this.bitMatrix.Dimension;
  7525.                             formatInfoBits = 0;
  7526.                             var iMin = dimension - 8;
  7527.                             for (var i = dimension - 1; i >= iMin; i--)
  7528.                             {
  7529.                                     formatInfoBits = this.copyBit(i, 8, formatInfoBits);
  7530.                             }
  7531.                             for (var j = dimension - 7; j < dimension; j++)
  7532.                             {
  7533.                                     formatInfoBits = this.copyBit(8, j, formatInfoBits);
  7534.                             }
  7535.                        
  7536.                             this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
  7537.                             if (this.parsedFormatInfo != null)
  7538.                             {
  7539.                                     return this.parsedFormatInfo;
  7540.                             }
  7541.                             throw "Error readFormatInformation";        
  7542.             }
  7543.             this.readVersion=function()
  7544.                     {
  7545.                        
  7546.                             if (this.parsedVersion != null)
  7547.                             {
  7548.                                     return this.parsedVersion;
  7549.                             }
  7550.                        
  7551.                             var dimension = this.bitMatrix.Dimension;
  7552.                        
  7553.                             var provisionalVersion = (dimension - 17) >> 2;
  7554.                             if (provisionalVersion <= 6)
  7555.                             {
  7556.                                     return Version.getVersionForNumber(provisionalVersion);
  7557.                             }
  7558.                        
  7559.                             // Read top-right version info: 3 wide by 6 tall
  7560.                             var versionBits = 0;
  7561.                             var ijMin = dimension - 11;
  7562.                             for (var j = 5; j >= 0; j--)
  7563.                             {
  7564.                                     for (var i = dimension - 9; i >= ijMin; i--)
  7565.                                     {
  7566.                                             versionBits = this.copyBit(i, j, versionBits);
  7567.                                     }
  7568.                             }
  7569.                        
  7570.                             this.parsedVersion = Version.decodeVersionInformation(versionBits);
  7571.                             if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension)
  7572.                             {
  7573.                                     return this.parsedVersion;
  7574.                             }
  7575.                        
  7576.                             // Hmm, failed. Try bottom left: 6 wide by 3 tall
  7577.                             versionBits = 0;
  7578.                             for (var i = 5; i >= 0; i--)
  7579.                             {
  7580.                                     for (var j = dimension - 9; j >= ijMin; j--)
  7581.                                     {
  7582.                                             versionBits = this.copyBit(i, j, versionBits);
  7583.                                     }
  7584.                             }
  7585.                        
  7586.                             this.parsedVersion = Version.decodeVersionInformation(versionBits);
  7587.                             if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension)
  7588.                             {
  7589.                                     return this.parsedVersion;
  7590.                             }
  7591.                             throw "Error readVersion";
  7592.                     }
  7593.             this.readCodewords=function()
  7594.                     {
  7595.                        
  7596.                             var formatInfo = this.readFormatInformation();
  7597.                             var version = this.readVersion();
  7598.                        
  7599.                             // Get the data mask for the format used in this QR Code. This will exclude
  7600.                             // some bits from reading as we wind through the bit matrix.
  7601.                             var dataMask = DataMask.forReference( formatInfo.DataMask);
  7602.                             var dimension = this.bitMatrix.Dimension;
  7603.                             dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
  7604.                        
  7605.                             var functionPattern = version.buildFunctionPattern();
  7606.                        
  7607.                             var readingUp = true;
  7608.                             var result = new Array(version.TotalCodewords);
  7609.                             var resultOffset = 0;
  7610.                             var currentByte = 0;
  7611.                             var bitsRead = 0;
  7612.                             // Read columns in pairs, from right to left
  7613.                             for (var j = dimension - 1; j > 0; j -= 2)
  7614.                             {
  7615.                                     if (j == 6)
  7616.                                     {
  7617.                                             // Skip whole column with vertical alignment pattern;
  7618.                                             // saves time and makes the other code proceed more cleanly
  7619.                                             j--;
  7620.                                     }
  7621.                                     // Read alternatingly from bottom to top then top to bottom
  7622.                                     for (var count = 0; count < dimension; count++)
  7623.                                     {
  7624.                                             var i = readingUp?dimension - 1 - count:count;
  7625.                                             for (var col = 0; col < 2; col++)
  7626.                                             {
  7627.                                                     // Ignore bits covered by the function pattern
  7628.                                                     if (!functionPattern.get_Renamed(j - col, i))
  7629.                                                     {
  7630.                                                             // Read a bit
  7631.                                                             bitsRead++;
  7632.                                                             currentByte <<= 1;
  7633.                                                             if (this.bitMatrix.get_Renamed(j - col, i))
  7634.                                                             {
  7635.                                                                     currentByte |= 1;
  7636.                                                             }
  7637.                                                             // If we've made a whole byte, save it off
  7638.                                                             if (bitsRead == 8)
  7639.                                                             {
  7640.                                                                     result[resultOffset++] =  currentByte;
  7641.                                                                     bitsRead = 0;
  7642.                                                                     currentByte = 0;
  7643.                                                             }
  7644.                                                     }
  7645.                                             }
  7646.                                     }
  7647.                                     readingUp ^= true; // readingUp = !readingUp; // switch directions
  7648.                             }
  7649.                             if (resultOffset != version.TotalCodewords)
  7650.                             {
  7651.                                     throw "Error readCodewords";
  7652.                             }
  7653.                             return result;
  7654.                     }
  7655.     }
  7656.     DataMask = {};
  7657.     DataMask.forReference = function(reference)
  7658.     {
  7659.             if (reference < 0 || reference > 7)
  7660.             {
  7661.                     throw "System.ArgumentException";
  7662.             }
  7663.             return DataMask.DATA_MASKS[reference];
  7664.     }
  7665.  
  7666.     function DataMask000()
  7667.     {
  7668.             this.unmaskBitMatrix=function(bits,  dimension)
  7669.             {
  7670.                     for (var i = 0; i < dimension; i++)
  7671.                     {
  7672.                             for (var j = 0; j < dimension; j++)
  7673.                             {
  7674.                                     if (this.isMasked(i, j))
  7675.                                     {
  7676.                                             bits.flip(j, i);
  7677.                                     }
  7678.                             }
  7679.                     }
  7680.             }
  7681.             this.isMasked=function( i,  j)
  7682.             {
  7683.                     return ((i + j) & 0x01) == 0;
  7684.             }
  7685.     }
  7686.  
  7687.     function DataMask001()
  7688.     {
  7689.             this.unmaskBitMatrix=function(bits,  dimension)
  7690.             {
  7691.                     for (var i = 0; i < dimension; i++)
  7692.                     {
  7693.                             for (var j = 0; j < dimension; j++)
  7694.                             {
  7695.                                     if (this.isMasked(i, j))
  7696.                                     {
  7697.                                             bits.flip(j, i);
  7698.                                     }
  7699.                             }
  7700.                     }
  7701.             }
  7702.             this.isMasked=function( i,  j)
  7703.             {
  7704.                     return (i & 0x01) == 0;
  7705.             }
  7706.     }
  7707.  
  7708.     function DataMask010()
  7709.     {
  7710.             this.unmaskBitMatrix=function(bits,  dimension)
  7711.             {
  7712.                     for (var i = 0; i < dimension; i++)
  7713.                     {
  7714.                             for (var j = 0; j < dimension; j++)
  7715.                             {
  7716.                                     if (this.isMasked(i, j))
  7717.                                     {
  7718.                                             bits.flip(j, i);
  7719.                                     }
  7720.                             }
  7721.                     }
  7722.             }
  7723.             this.isMasked=function( i,  j)
  7724.             {
  7725.                     return j % 3 == 0;
  7726.             }
  7727.     }
  7728.  
  7729.     function DataMask011()
  7730.     {
  7731.             this.unmaskBitMatrix=function(bits,  dimension)
  7732.             {
  7733.                     for (var i = 0; i < dimension; i++)
  7734.                     {
  7735.                             for (var j = 0; j < dimension; j++)
  7736.                             {
  7737.                                     if (this.isMasked(i, j))
  7738.                                     {
  7739.                                             bits.flip(j, i);
  7740.                                     }
  7741.                             }
  7742.                     }
  7743.             }
  7744.             this.isMasked=function( i,  j)
  7745.             {
  7746.                     return (i + j) % 3 == 0;
  7747.             }
  7748.     }
  7749.  
  7750.     function DataMask100()
  7751.     {
  7752.             this.unmaskBitMatrix=function(bits,  dimension)
  7753.             {
  7754.                     for (var i = 0; i < dimension; i++)
  7755.                     {
  7756.                             for (var j = 0; j < dimension; j++)
  7757.                             {
  7758.                                     if (this.isMasked(i, j))
  7759.                                     {
  7760.                                             bits.flip(j, i);
  7761.                                     }
  7762.                             }
  7763.                     }
  7764.             }
  7765.             this.isMasked=function( i,  j)
  7766.             {
  7767.                     return (((URShift(i, 1)) + (j / 3)) & 0x01) == 0;
  7768.             }
  7769.     }
  7770.  
  7771.     function DataMask101()
  7772.     {
  7773.             this.unmaskBitMatrix=function(bits,  dimension)
  7774.             {
  7775.                     for (var i = 0; i < dimension; i++)
  7776.                     {
  7777.                             for (var j = 0; j < dimension; j++)
  7778.                             {
  7779.                                     if (this.isMasked(i, j))
  7780.                                     {
  7781.                                             bits.flip(j, i);
  7782.                                     }
  7783.                             }
  7784.                     }
  7785.             }
  7786.             this.isMasked=function( i,  j)
  7787.             {
  7788.                     var temp = i * j;
  7789.                     return (temp & 0x01) + (temp % 3) == 0;
  7790.             }
  7791.     }
  7792.  
  7793.     function DataMask110()
  7794.     {
  7795.             this.unmaskBitMatrix=function(bits,  dimension)
  7796.             {
  7797.                     for (var i = 0; i < dimension; i++)
  7798.                     {
  7799.                             for (var j = 0; j < dimension; j++)
  7800.                             {
  7801.                                     if (this.isMasked(i, j))
  7802.                                     {
  7803.                                             bits.flip(j, i);
  7804.                                     }
  7805.                             }
  7806.                     }
  7807.             }
  7808.             this.isMasked=function( i,  j)
  7809.             {
  7810.                     var temp = i * j;
  7811.                     return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
  7812.             }
  7813.     }
  7814.     function DataMask111()
  7815.     {
  7816.             this.unmaskBitMatrix=function(bits,  dimension)
  7817.             {
  7818.                     for (var i = 0; i < dimension; i++)
  7819.                     {
  7820.                             for (var j = 0; j < dimension; j++)
  7821.                             {
  7822.                                     if (this.isMasked(i, j))
  7823.                                     {
  7824.                                             bits.flip(j, i);
  7825.                                     }
  7826.                             }
  7827.                     }
  7828.             }
  7829.             this.isMasked=function( i,  j)
  7830.             {
  7831.                     return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
  7832.             }
  7833.     }
  7834.  
  7835.     DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111());
  7836.  
  7837.     function ReedSolomonDecoder(field)
  7838.     {
  7839.             this.field = field;
  7840.             this.decode=function(received,  twoS)
  7841.             {
  7842.                             var poly = new GF256Poly(this.field, received);
  7843.                             var syndromeCoefficients = new Array(twoS);
  7844.                             for(var i=0;i<syndromeCoefficients.length;i++)syndromeCoefficients[i]=0;
  7845.                             var dataMatrix = false;//this.field.Equals(GF256.DATA_MATRIX_FIELD);
  7846.                             var noError = true;
  7847.                             for (var i = 0; i < twoS; i++)
  7848.                             {
  7849.                                     // Thanks to sanfordsquires for this fix:
  7850.                                     var eval = poly.evaluateAt(this.field.exp(dataMatrix?i + 1:i));
  7851.                                     syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
  7852.                                     if (eval != 0)
  7853.                                     {
  7854.                                             noError = false;
  7855.                                     }
  7856.                             }
  7857.                             if (noError)
  7858.                             {
  7859.                                     return ;
  7860.                             }
  7861.                             var syndrome = new GF256Poly(this.field, syndromeCoefficients);
  7862.                             var sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(twoS, 1), syndrome, twoS);
  7863.                             var sigma = sigmaOmega[0];
  7864.                             var omega = sigmaOmega[1];
  7865.                             var errorLocations = this.findErrorLocations(sigma);
  7866.                             var errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations, dataMatrix);
  7867.                             for (var i = 0; i < errorLocations.length; i++)
  7868.                             {
  7869.                                     var position = received.length - 1 - this.field.log(errorLocations[i]);
  7870.                                     if (position < 0)
  7871.                                     {
  7872.                                             throw "ReedSolomonException Bad error location";
  7873.                                     }
  7874.                                     received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
  7875.                             }
  7876.             }
  7877.        
  7878.             this.runEuclideanAlgorithm=function( a,  b,  R)
  7879.                     {
  7880.                             // Assume a's degree is >= b's
  7881.                             if (a.Degree < b.Degree)
  7882.                             {
  7883.                                     var temp = a;
  7884.                                     a = b;
  7885.                                     b = temp;
  7886.                             }
  7887.                        
  7888.                             var rLast = a;
  7889.                             var r = b;
  7890.                             var sLast = this.field.One;
  7891.                             var s = this.field.Zero;
  7892.                             var tLast = this.field.Zero;
  7893.                             var t = this.field.One;
  7894.                        
  7895.                             // Run Euclidean algorithm until r's degree is less than R/2
  7896.                             while (r.Degree >= Math.floor(R / 2))
  7897.                             {
  7898.                                     var rLastLast = rLast;
  7899.                                     var sLastLast = sLast;
  7900.                                     var tLastLast = tLast;
  7901.                                     rLast = r;
  7902.                                     sLast = s;
  7903.                                     tLast = t;
  7904.                                
  7905.                                     // Divide rLastLast by rLast, with quotient in q and remainder in r
  7906.                                     if (rLast.Zero)
  7907.                                     {
  7908.                                             // Oops, Euclidean algorithm already terminated?
  7909.                                             throw "r_{i-1} was zero";
  7910.                                     }
  7911.                                     r = rLastLast;
  7912.                                     var q = this.field.Zero;
  7913.                                     var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree);
  7914.                                     var dltInverse = this.field.inverse(denominatorLeadingTerm);
  7915.                                     while (r.Degree >= rLast.Degree && !r.Zero)
  7916.                                     {
  7917.                                             var degreeDiff = r.Degree - rLast.Degree;
  7918.                                             var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse);
  7919.                                             q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale));
  7920.                                             r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
  7921.                                             //r.EXE();
  7922.                                     }
  7923.                                
  7924.                                     s = q.multiply1(sLast).addOrSubtract(sLastLast);
  7925.                                     t = q.multiply1(tLast).addOrSubtract(tLastLast);
  7926.                             }
  7927.                        
  7928.                             var sigmaTildeAtZero = t.getCoefficient(0);
  7929.                             if (sigmaTildeAtZero == 0)
  7930.                             {
  7931.                                     throw "ReedSolomonException sigmaTilde(0) was zero";
  7932.                             }
  7933.                        
  7934.                             var inverse = this.field.inverse(sigmaTildeAtZero);
  7935.                             var sigma = t.multiply2(inverse);
  7936.                             var omega = r.multiply2(inverse);
  7937.                             return new Array(sigma, omega);
  7938.                     }
  7939.             this.findErrorLocations=function( errorLocator)
  7940.                     {
  7941.                             // This is a direct application of Chien's search
  7942.                             var numErrors = errorLocator.Degree;
  7943.                             if (numErrors == 1)
  7944.                             {
  7945.                                     // shortcut
  7946.                                     return new Array(errorLocator.getCoefficient(1));
  7947.                             }
  7948.                             var result = new Array(numErrors);
  7949.                             var e = 0;
  7950.                             for (var i = 1; i < 256 && e < numErrors; i++)
  7951.                             {
  7952.                                     if (errorLocator.evaluateAt(i) == 0)
  7953.                                     {
  7954.                                             result[e] = this.field.inverse(i);
  7955.                                             e++;
  7956.                                     }
  7957.                             }
  7958.                             if (e != numErrors)
  7959.                             {
  7960.                                     throw "Error locator degree does not match number of roots";
  7961.                             }
  7962.                             return result;
  7963.                     }
  7964.             this.findErrorMagnitudes=function( errorEvaluator,  errorLocations,  dataMatrix)
  7965.                     {
  7966.                             // This is directly applying Forney's Formula
  7967.                             var s = errorLocations.length;
  7968.                             var result = new Array(s);
  7969.                             for (var i = 0; i < s; i++)
  7970.                             {
  7971.                                     var xiInverse = this.field.inverse(errorLocations[i]);
  7972.                                     var denominator = 1;
  7973.                                     for (var j = 0; j < s; j++)
  7974.                                     {
  7975.                                             if (i != j)
  7976.                                             {
  7977.                                                     denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse)));
  7978.                                             }
  7979.                                     }
  7980.                                     result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator));
  7981.                                     // Thanks to sanfordsquires for this fix:
  7982.                                     if (dataMatrix)
  7983.                                     {
  7984.                                             result[i] = this.field.multiply(result[i], xiInverse);
  7985.                                     }
  7986.                             }
  7987.                             return result;
  7988.                     }
  7989.     }
  7990.     function GF256Poly(field,  coefficients)
  7991.     {
  7992.             if (coefficients == null || coefficients.length == 0)
  7993.             {
  7994.                     throw "System.ArgumentException";
  7995.             }
  7996.             this.field = field;
  7997.             var coefficientsLength = coefficients.length;
  7998.             if (coefficientsLength > 1 && coefficients[0] == 0)
  7999.             {
  8000.                     // Leading term must be non-zero for anything except the constant polynomial "0"
  8001.                     var firstNonZero = 1;
  8002.                     while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0)
  8003.                     {
  8004.                             firstNonZero++;
  8005.                     }
  8006.                     if (firstNonZero == coefficientsLength)
  8007.                     {
  8008.                             this.coefficients = field.Zero.coefficients;
  8009.                     }
  8010.                     else
  8011.                     {
  8012.                             this.coefficients = new Array(coefficientsLength - firstNonZero);
  8013.                             for(var i=0;i<this.coefficients.length;i++)this.coefficients[i]=0;
  8014.                             //Array.Copy(coefficients, firstNonZero, this.coefficients, 0, this.coefficients.length);
  8015.                             for(var ci=0;ci<this.coefficients.length;ci++)this.coefficients[ci]=coefficients[firstNonZero+ci];
  8016.                     }
  8017.             }
  8018.             else
  8019.             {
  8020.                     this.coefficients = coefficients;
  8021.             }
  8022.        
  8023.             this.__defineGetter__("Zero", function()
  8024.             {
  8025.                     return this.coefficients[0] == 0;
  8026.             });
  8027.             this.__defineGetter__("Degree", function()
  8028.             {
  8029.                     return this.coefficients.length - 1;
  8030.             });
  8031.             this.__defineGetter__("Coefficients", function()
  8032.             {
  8033.                     return this.coefficients;
  8034.             });
  8035.        
  8036.             this.getCoefficient=function( degree)
  8037.             {
  8038.                     return this.coefficients[this.coefficients.length - 1 - degree];
  8039.             }
  8040.        
  8041.             this.evaluateAt=function( a)
  8042.             {
  8043.                     if (a == 0)
  8044.                     {
  8045.                             // Just return the x^0 coefficient
  8046.                             return this.getCoefficient(0);
  8047.                     }
  8048.                     var size = this.coefficients.length;
  8049.                     if (a == 1)
  8050.                     {
  8051.                             // Just the sum of the coefficients
  8052.                             var result = 0;
  8053.                             for (var i = 0; i < size; i++)
  8054.                             {
  8055.                                     result = GF256.addOrSubtract(result, this.coefficients[i]);
  8056.                             }
  8057.                             return result;
  8058.                     }
  8059.                     var result2 = this.coefficients[0];
  8060.                     for (var i = 1; i < size; i++)
  8061.                     {
  8062.                             result2 = GF256.addOrSubtract(this.field.multiply(a, result2), this.coefficients[i]);
  8063.                     }
  8064.                     return result2;
  8065.             }
  8066.        
  8067.             this.addOrSubtract=function( other)
  8068.                     {
  8069.                             if (this.field != other.field)
  8070.                             {
  8071.                                     throw "GF256Polys do not have same GF256 field";
  8072.                             }
  8073.                             if (this.Zero)
  8074.                             {
  8075.                                     return other;
  8076.                             }
  8077.                             if (other.Zero)
  8078.                             {
  8079.                                     return this;
  8080.                             }
  8081.                        
  8082.                             var smallerCoefficients = this.coefficients;
  8083.                             var largerCoefficients = other.coefficients;
  8084.                             if (smallerCoefficients.length > largerCoefficients.length)
  8085.                             {
  8086.                                     var temp = smallerCoefficients;
  8087.                                     smallerCoefficients = largerCoefficients;
  8088.                                     largerCoefficients = temp;
  8089.                             }
  8090.                             var sumDiff = new Array(largerCoefficients.length);
  8091.                             var lengthDiff = largerCoefficients.length - smallerCoefficients.length;
  8092.                             // Copy high-order terms only found in higher-degree polynomial's coefficients
  8093.                             //Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
  8094.                             for(var ci=0;ci<lengthDiff;ci++)sumDiff[ci]=largerCoefficients[ci];
  8095.                        
  8096.                             for (var i = lengthDiff; i < largerCoefficients.length; i++)
  8097.                             {
  8098.                                     sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
  8099.                             }
  8100.                        
  8101.                             return new GF256Poly(field, sumDiff);
  8102.             }
  8103.             this.multiply1=function( other)
  8104.                     {
  8105.                             if (this.field!=other.field)
  8106.                             {
  8107.                                     throw "GF256Polys do not have same GF256 field";
  8108.                             }
  8109.                             if (this.Zero || other.Zero)
  8110.                             {
  8111.                                     return this.field.Zero;
  8112.                             }
  8113.                             var aCoefficients = this.coefficients;
  8114.                             var aLength = aCoefficients.length;
  8115.                             var bCoefficients = other.coefficients;
  8116.                             var bLength = bCoefficients.length;
  8117.                             var product = new Array(aLength + bLength - 1);
  8118.                             for (var i = 0; i < aLength; i++)
  8119.                             {
  8120.                                     var aCoeff = aCoefficients[i];
  8121.                                     for (var j = 0; j < bLength; j++)
  8122.                                     {
  8123.                                             product[i + j] = GF256.addOrSubtract(product[i + j], this.field.multiply(aCoeff, bCoefficients[j]));
  8124.                                     }
  8125.                             }
  8126.                             return new GF256Poly(this.field, product);
  8127.                     }
  8128.             this.multiply2=function( scalar)
  8129.                     {
  8130.                             if (scalar == 0)
  8131.                             {
  8132.                                     return this.field.Zero;
  8133.                             }
  8134.                             if (scalar == 1)
  8135.                             {
  8136.                                     return this;
  8137.                             }
  8138.                             var size = this.coefficients.length;
  8139.                             var product = new Array(size);
  8140.                             for (var i = 0; i < size; i++)
  8141.                             {
  8142.                                     product[i] = this.field.multiply(this.coefficients[i], scalar);
  8143.                             }
  8144.                             return new GF256Poly(this.field, product);
  8145.                     }
  8146.             this.multiplyByMonomial=function( degree,  coefficient)
  8147.                     {
  8148.                             if (degree < 0)
  8149.                             {
  8150.                                     throw "System.ArgumentException";
  8151.                             }
  8152.                             if (coefficient == 0)
  8153.                             {
  8154.                                     return this.field.Zero;
  8155.                             }
  8156.                             var size = this.coefficients.length;
  8157.                             var product = new Array(size + degree);
  8158.                             for(var i=0;i<product.length;i++)product[i]=0;
  8159.                             for (var i = 0; i < size; i++)
  8160.                             {
  8161.                                     product[i] = this.field.multiply(this.coefficients[i], coefficient);
  8162.                             }
  8163.                             return new GF256Poly(this.field, product);
  8164.                     }
  8165.             this.divide=function( other)
  8166.                     {
  8167.                             if (this.field!=other.field)
  8168.                             {
  8169.                                     throw "GF256Polys do not have same GF256 field";
  8170.                             }
  8171.                             if (other.Zero)
  8172.                             {
  8173.                                     throw "Divide by 0";
  8174.                             }
  8175.                        
  8176.                             var quotient = this.field.Zero;
  8177.                             var remainder = this;
  8178.                        
  8179.                             var denominatorLeadingTerm = other.getCoefficient(other.Degree);
  8180.                             var inverseDenominatorLeadingTerm = this.field.inverse(denominatorLeadingTerm);
  8181.                        
  8182.                             while (remainder.Degree >= other.Degree && !remainder.Zero)
  8183.                             {
  8184.                                     var degreeDifference = remainder.Degree - other.Degree;
  8185.                                     var scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
  8186.                                     var term = other.multiplyByMonomial(degreeDifference, scale);
  8187.                                     var iterationQuotient = this.field.buildMonomial(degreeDifference, scale);
  8188.                                     quotient = quotient.addOrSubtract(iterationQuotient);
  8189.                                     remainder = remainder.addOrSubtract(term);
  8190.                             }
  8191.                        
  8192.                             return new Array(quotient, remainder);
  8193.                     }
  8194.     }
  8195.  
  8196.     function GF256( primitive)
  8197.     {
  8198.             this.expTable = new Array(256);
  8199.             this.logTable = new Array(256);
  8200.             var x = 1;
  8201.             for (var i = 0; i < 256; i++)
  8202.             {
  8203.                     this.expTable[i] = x;
  8204.                     x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
  8205.                     if (x >= 0x100)
  8206.                     {
  8207.                             x ^= primitive;
  8208.                     }
  8209.             }
  8210.             for (var i = 0; i < 255; i++)
  8211.             {
  8212.                     this.logTable[this.expTable[i]] = i;
  8213.             }
  8214.             // logTable[0] == 0 but this should never be used
  8215.             var at0=new Array(1);at0[0]=0;
  8216.             this.zero = new GF256Poly(this, new Array(at0));
  8217.             var at1=new Array(1);at1[0]=1;
  8218.             this.one = new GF256Poly(this, new Array(at1));
  8219.        
  8220.             this.__defineGetter__("Zero", function()
  8221.             {
  8222.                     return this.zero;
  8223.             });
  8224.             this.__defineGetter__("One", function()
  8225.             {
  8226.                     return this.one;
  8227.             });
  8228.             this.buildMonomial=function( degree,  coefficient)
  8229.                     {
  8230.                             if (degree < 0)
  8231.                             {
  8232.                                     throw "System.ArgumentException";
  8233.                             }
  8234.                             if (coefficient == 0)
  8235.                             {
  8236.                                     return zero;
  8237.                             }
  8238.                             var coefficients = new Array(degree + 1);
  8239.                             for(var i=0;i<coefficients.length;i++)coefficients[i]=0;
  8240.                             coefficients[0] = coefficient;
  8241.                             return new GF256Poly(this, coefficients);
  8242.                     }
  8243.             this.exp=function( a)
  8244.                     {
  8245.                             return this.expTable[a];
  8246.                     }
  8247.             this.log=function( a)
  8248.                     {
  8249.                             if (a == 0)
  8250.                             {
  8251.                                     throw "System.ArgumentException";
  8252.                             }
  8253.                             return this.logTable[a];
  8254.                     }
  8255.             this.inverse=function( a)
  8256.                     {
  8257.                             if (a == 0)
  8258.                             {
  8259.                                     throw "System.ArithmeticException";
  8260.                             }
  8261.                             return this.expTable[255 - this.logTable[a]];
  8262.                     }
  8263.             this.multiply=function( a,  b)
  8264.                     {
  8265.                             if (a == 0 || b == 0)
  8266.                             {
  8267.                                     return 0;
  8268.                             }
  8269.                             if (a == 1)
  8270.                             {
  8271.                                     return b;
  8272.                             }
  8273.                             if (b == 1)
  8274.                             {
  8275.                                     return a;
  8276.                             }
  8277.                             return this.expTable[(this.logTable[a] + this.logTable[b]) % 255];
  8278.                     }                
  8279.     }
  8280.  
  8281.     GF256.QR_CODE_FIELD = new GF256(0x011D);
  8282.     GF256.DATA_MATRIX_FIELD = new GF256(0x012D);
  8283.  
  8284.     GF256.addOrSubtract=function( a,  b)
  8285.     {
  8286.             return a ^ b;
  8287.     }
  8288.  
  8289.     Decoder={};
  8290.     Decoder.rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
  8291.  
  8292.     Decoder.correctErrors=function( codewordBytes,  numDataCodewords)
  8293.     {
  8294.             var numCodewords = codewordBytes.length;
  8295.             // First read into an array of ints
  8296.             var codewordsInts = new Array(numCodewords);
  8297.             for (var i = 0; i < numCodewords; i++)
  8298.             {
  8299.                     codewordsInts[i] = codewordBytes[i] & 0xFF;
  8300.             }
  8301.             var numECCodewords = codewordBytes.length - numDataCodewords;
  8302.             try
  8303.             {
  8304.                     Decoder.rsDecoder.decode(codewordsInts, numECCodewords);
  8305.                     //var corrector = new ReedSolomon(codewordsInts, numECCodewords);
  8306.                     //corrector.correct();
  8307.             }
  8308.             catch ( rse)
  8309.             {
  8310.                     throw rse;
  8311.             }
  8312.             // Copy back into array of bytes -- only need to worry about the bytes that were data
  8313.             // We don't care about errors in the error-correction codewords
  8314.             for (var i = 0; i < numDataCodewords; i++)
  8315.             {
  8316.                     codewordBytes[i] =  codewordsInts[i];
  8317.             }
  8318.     }
  8319.     Decoder.decode=function(bits)
  8320.     {
  8321.             var parser = new BitMatrixParser(bits);
  8322.             var version = parser.readVersion();
  8323.             var ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;
  8324.        
  8325.             // Read codewords
  8326.             var codewords = parser.readCodewords();
  8327.             // Separate into data blocks
  8328.             var dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
  8329.        
  8330.             // Count total number of data bytes
  8331.             var totalBytes = 0;
  8332.             for (var i = 0; i < dataBlocks.length; i++)
  8333.             {
  8334.                     totalBytes += dataBlocks[i].NumDataCodewords;
  8335.             }
  8336.             var resultBytes = new Array(totalBytes);
  8337.             var resultOffset = 0;
  8338.        
  8339.             // Error-correct and copy data blocks together into a stream of bytes
  8340.             for (var j = 0; j < dataBlocks.length; j++)
  8341.             {
  8342.                     var dataBlock = dataBlocks[j];
  8343.                     var codewordBytes = dataBlock.Codewords;
  8344.                     var numDataCodewords = dataBlock.NumDataCodewords;
  8345.                     Decoder.correctErrors(codewordBytes, numDataCodewords);
  8346.                     for (var i = 0; i < numDataCodewords; i++)
  8347.                     {
  8348.                             resultBytes[resultOffset++] = codewordBytes[i];
  8349.                     }
  8350.             }
  8351.        
  8352.             // Decode the contents of that stream of bytes
  8353.             var reader = new QRCodeDataBlockReader(resultBytes, version.VersionNumber, ecLevel.Bits);
  8354.             return reader;
  8355.             //return DecodedBitStreamParser.decode(resultBytes, version, ecLevel);
  8356.     }
  8357.     qrcode = {};
  8358.     qrcode.imagedata = null;
  8359.     qrcode.width = 0;
  8360.     qrcode.height = 0;
  8361.     qrcode.qrCodeSymbol = null;
  8362.     qrcode.debug = false;
  8363.     qrcode.sizeOfDataLengthInfo =  [  [ 10, 9, 8, 8 ],  [ 12, 11, 16, 10 ],  [ 14, 13, 16, 12 ] ];
  8364.     qrcode.callback = null;
  8365.     qrcode.decode = function(src){
  8366.        
  8367.             if(arguments.length==0)
  8368.             {
  8369.                     var canvas_qr = document.getElementById("qr-canvas");
  8370.                     var context = canvas_qr.getContext('2d');
  8371.                     qrcode.width = canvas_qr.width;
  8372.                     qrcode.height = canvas_qr.height;
  8373.                     qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height);
  8374.             qrcode.result = qrcode.process(context);
  8375.             if(qrcode.callback!=null)
  8376.                 qrcode.callback(qrcode.result);
  8377.                     return qrcode.result;
  8378.             }
  8379.             else
  8380.             {
  8381.                     var image = new Image();
  8382.                     image.onload=function(){
  8383.                             //var canvas_qr = document.getElementById("qr-canvas");
  8384.                             var canvas_qr = document.createElement('canvas');
  8385.                             var context = canvas_qr.getContext('2d');
  8386.                             var canvas_out = document.getElementById("out-canvas");
  8387.                             if(canvas_out!=null)
  8388.                 {
  8389.                     var outctx = canvas_out.getContext('2d');
  8390.                     outctx.clearRect(0, 0, 320, 240);
  8391.                                     outctx.drawImage(image, 0, 0, 320, 240);
  8392.                 }
  8393.                             canvas_qr.width = image.width;
  8394.                             canvas_qr.height = image.height;
  8395.                 context.drawImage(image, 0, 0);
  8396.                             qrcode.width = image.width;
  8397.                             qrcode.height = image.height;
  8398.                             try{
  8399.                                     qrcode.imagedata = context.getImageData(0, 0, image.width, image.height);
  8400.                             }catch(e){
  8401.                                     qrcode.result = "Cross domain image reading not supported in your browser! Save it to your computer then drag and drop the file!";
  8402.                                     if(qrcode.callback!=null)
  8403.                                             qrcode.callback(qrcode.result);
  8404.                                     return;
  8405.                             }
  8406.                        
  8407.                 try
  8408.                 {
  8409.                     qrcode.result = qrcode.process(context);
  8410.                 }
  8411.                 catch(e)
  8412.                 {
  8413.                                     console.log(e);
  8414.                     qrcode.result = "error decoding QR Code";
  8415.                 }
  8416.                             if(qrcode.callback!=null)
  8417.                                     qrcode.callback(qrcode.result);
  8418.                     }
  8419.                     image.src = src;
  8420.             }
  8421.     }
  8422.     qrcode.decode_utf8 = function ( s )
  8423.     {
  8424.       return decodeURIComponent( escape( s ) );
  8425.     }
  8426.     qrcode.process = function(ctx){
  8427.        
  8428.             var start = new Date().getTime();
  8429.             var image = qrcode.grayScaleToBitmap(qrcode.grayscale());
  8430.         //var image = qrcode.binarize(128);
  8431.        
  8432.         if(qrcode.debug)
  8433.         {
  8434.             for (var y = 0; y < qrcode.height; y++)
  8435.             {
  8436.                 for (var x = 0; x < qrcode.width; x++)
  8437.                 {
  8438.                     var point = (x * 4) + (y * qrcode.width * 4);
  8439.                     qrcode.imagedata.data[point] = image[x+y*qrcode.width]?0:0;
  8440.                     qrcode.imagedata.data[point+1] = image[x+y*qrcode.width]?0:0;
  8441.                     qrcode.imagedata.data[point+2] = image[x+y*qrcode.width]?255:0;
  8442.                 }
  8443.             }
  8444.             ctx.putImageData(qrcode.imagedata, 0, 0);
  8445.         }
  8446.        
  8447.             //var finderPatternInfo = new FinderPatternFinder().findFinderPattern(image);
  8448.        
  8449.             var detector = new Detector(image);
  8450.             var qRCodeMatrix = detector.detect();
  8451.        
  8452.             /*for (var y = 0; y < qRCodeMatrix.bits.Height; y++)
  8453.             {
  8454.                     for (var x = 0; x < qRCodeMatrix.bits.Width; x++)
  8455.                     {
  8456.                             var point = (x * 4*2) + (y*2 * qrcode.width * 4);
  8457.                             qrcode.imagedata.data[point] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0;
  8458.                             qrcode.imagedata.data[point+1] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0;
  8459.                             qrcode.imagedata.data[point+2] = qRCodeMatrix.bits.get_Renamed(x,y)?255:0;
  8460.                     }
  8461.             }*/
  8462.         if(qrcode.debug)
  8463.             ctx.putImageData(qrcode.imagedata, 0, 0);
  8464.        
  8465.             var reader = Decoder.decode(qRCodeMatrix.bits);
  8466.             var data = reader.DataByte;
  8467.             var str="";
  8468.             for(var i=0;i<data.length;i++)
  8469.             {
  8470.                     for(var j=0;j<data[i].length;j++)
  8471.                             str+=String.fromCharCode(data[i][j]);
  8472.             }
  8473.        
  8474.             var end = new Date().getTime();
  8475.             var time = end - start;
  8476.             console.log(time);
  8477.    
  8478.             return qrcode.decode_utf8(str);
  8479.             //alert("Time:" + time + " Code: "+str);
  8480.     }
  8481.     qrcode.getPixel = function(x,y){
  8482.             if (qrcode.width < x) {
  8483.                     throw "point error";
  8484.             }
  8485.             if (qrcode.height < y) {
  8486.                     throw "point error";
  8487.             }
  8488.             point = (x * 4) + (y * qrcode.width * 4);
  8489.             p = (qrcode.imagedata.data[point]*33 + qrcode.imagedata.data[point + 1]*34 + qrcode.imagedata.data[point + 2]*33)/100;
  8490.             return p;
  8491.     }
  8492.     qrcode.binarize = function(th){
  8493.             var ret = new Array(qrcode.width*qrcode.height);
  8494.             for (var y = 0; y < qrcode.height; y++)
  8495.             {
  8496.                     for (var x = 0; x < qrcode.width; x++)
  8497.                     {
  8498.                             var gray = qrcode.getPixel(x, y);
  8499.                        
  8500.                             ret[x+y*qrcode.width] = gray<=th?true:false;
  8501.                     }
  8502.             }
  8503.             return ret;
  8504.     }
  8505.     qrcode.getMiddleBrightnessPerArea=function(image)
  8506.     {
  8507.             var numSqrtArea = 4;
  8508.             //obtain middle brightness((min + max) / 2) per area
  8509.             var areaWidth = Math.floor(qrcode.width / numSqrtArea);
  8510.             var areaHeight = Math.floor(qrcode.height / numSqrtArea);
  8511.             var minmax = new Array(numSqrtArea);
  8512.             for (var i = 0; i < numSqrtArea; i++)
  8513.             {
  8514.                     minmax[i] = new Array(numSqrtArea);
  8515.                     for (var i2 = 0; i2 < numSqrtArea; i2++)
  8516.                     {
  8517.                             minmax[i][i2] = new Array(0,0);
  8518.                     }
  8519.             }
  8520.             for (var ay = 0; ay < numSqrtArea; ay++)
  8521.             {
  8522.                     for (var ax = 0; ax < numSqrtArea; ax++)
  8523.                     {
  8524.                             minmax[ax][ay][0] = 0xFF;
  8525.                             for (var dy = 0; dy < areaHeight; dy++)
  8526.                             {
  8527.                                     for (var dx = 0; dx < areaWidth; dx++)
  8528.                                     {
  8529.                                             var target = image[areaWidth * ax + dx+(areaHeight * ay + dy)*qrcode.width];
  8530.                                             if (target < minmax[ax][ay][0])
  8531.                                                     minmax[ax][ay][0] = target;
  8532.                                             if (target > minmax[ax][ay][1])
  8533.                                                     minmax[ax][ay][1] = target;
  8534.                                     }
  8535.                             }
  8536.                             //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
  8537.                     }
  8538.             }
  8539.             var middle = new Array(numSqrtArea);
  8540.             for (var i3 = 0; i3 < numSqrtArea; i3++)
  8541.             {
  8542.                     middle[i3] = new Array(numSqrtArea);
  8543.             }
  8544.             for (var ay = 0; ay < numSqrtArea; ay++)
  8545.             {
  8546.                     for (var ax = 0; ax < numSqrtArea; ax++)
  8547.                     {
  8548.                             middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2);
  8549.                             //Console.out.print(middle[ax][ay] + ",");
  8550.                     }
  8551.                     //Console.out.println("");
  8552.             }
  8553.             //Console.out.println("");
  8554.        
  8555.             return middle;
  8556.     }
  8557.  
  8558.     qrcode.grayScaleToBitmap=function(grayScale)
  8559.     {
  8560.             var middle = qrcode.getMiddleBrightnessPerArea(grayScale);
  8561.             var sqrtNumArea = middle.length;
  8562.             var areaWidth = Math.floor(qrcode.width / sqrtNumArea);
  8563.             var areaHeight = Math.floor(qrcode.height / sqrtNumArea);
  8564.             var bitmap = new Array(qrcode.height*qrcode.width);
  8565.        
  8566.             for (var ay = 0; ay < sqrtNumArea; ay++)
  8567.             {
  8568.                     for (var ax = 0; ax < sqrtNumArea; ax++)
  8569.                     {
  8570.                             for (var dy = 0; dy < areaHeight; dy++)
  8571.                             {
  8572.                                     for (var dx = 0; dx < areaWidth; dx++)
  8573.                                     {
  8574.                                             bitmap[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] = (grayScale[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] < middle[ax][ay])?true:false;
  8575.                                     }
  8576.                             }
  8577.                     }
  8578.             }
  8579.             return bitmap;
  8580.     }
  8581.  
  8582.     qrcode.grayscale = function(){
  8583.             var ret = new Array(qrcode.width*qrcode.height);
  8584.             for (var y = 0; y < qrcode.height; y++)
  8585.             {
  8586.                     for (var x = 0; x < qrcode.width; x++)
  8587.                     {
  8588.                             var gray = qrcode.getPixel(x, y);
  8589.                        
  8590.                             ret[x+y*qrcode.width] = gray;
  8591.                     }
  8592.             }
  8593.             return ret;
  8594.     }
  8595.  
  8596.  
  8597.  
  8598.  
  8599.     function URShift( number,  bits)
  8600.     {
  8601.             if (number >= 0)
  8602.                     return number >> bits;
  8603.             else
  8604.                     return (number >> bits) + (2 << ~bits);
  8605.     }
  8606.  
  8607.  
  8608.     function arrayRemove(array, from, to) {
  8609.       var rest = array.slice((to || from) + 1 || array.length);
  8610.       array.length = from < 0 ? array.length + from : from;
  8611.       return array.push.apply(array, rest);
  8612.     }
  8613.  
  8614.     var MIN_SKIP = 3;
  8615.     var MAX_MODULES = 57;
  8616.     var INTEGER_MATH_SHIFT = 8;
  8617.     var CENTER_QUORUM = 2;
  8618.  
  8619.     qrcode.orderBestPatterns=function(patterns)
  8620.                     {
  8621.                        
  8622.                             function distance( pattern1,  pattern2)
  8623.                             {
  8624.                                     xDiff = pattern1.X - pattern2.X;
  8625.                                     yDiff = pattern1.Y - pattern2.Y;
  8626.                                     return  Math.sqrt( (xDiff * xDiff + yDiff * yDiff));
  8627.                             }
  8628.                        
  8629.                             /// <summary> Returns the z component of the cross product between vectors BC and BA.</summary>
  8630.                             function crossProductZ( pointA,  pointB,  pointC)
  8631.                             {
  8632.                                     var bX = pointB.x;
  8633.                                     var bY = pointB.y;
  8634.                                     return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
  8635.                             }
  8636.  
  8637.                        
  8638.                             // Find distances between pattern centers
  8639.                             var zeroOneDistance = distance(patterns[0], patterns[1]);
  8640.                             var oneTwoDistance = distance(patterns[1], patterns[2]);
  8641.                             var zeroTwoDistance = distance(patterns[0], patterns[2]);
  8642.                        
  8643.                             var pointA, pointB, pointC;
  8644.                             // Assume one closest to other two is B; A and C will just be guesses at first
  8645.                             if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance)
  8646.                             {
  8647.                                     pointB = patterns[0];
  8648.                                     pointA = patterns[1];
  8649.                                     pointC = patterns[2];
  8650.                             }
  8651.                             else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance)
  8652.                             {
  8653.                                     pointB = patterns[1];
  8654.                                     pointA = patterns[0];
  8655.                                     pointC = patterns[2];
  8656.                             }
  8657.                             else
  8658.                             {
  8659.                                     pointB = patterns[2];
  8660.                                     pointA = patterns[0];
  8661.                                     pointC = patterns[1];
  8662.                             }
  8663.                        
  8664.                             // Use cross product to figure out whether A and C are correct or flipped.
  8665.                             // This asks whether BC x BA has a positive z component, which is the arrangement
  8666.                             // we want for A, B, C. If it's negative, then we've got it flipped around and
  8667.                             // should swap A and C.
  8668.                             if (crossProductZ(pointA, pointB, pointC) < 0.0)
  8669.                             {
  8670.                                     var temp = pointA;
  8671.                                     pointA = pointC;
  8672.                                     pointC = temp;
  8673.                             }
  8674.                        
  8675.                             patterns[0] = pointA;
  8676.                             patterns[1] = pointB;
  8677.                             patterns[2] = pointC;
  8678.                     }
  8679.  
  8680.  
  8681.     function FinderPattern(posX, posY,  estimatedModuleSize)
  8682.     {
  8683.             this.x=posX;
  8684.             this.y=posY;
  8685.             this.count = 1;
  8686.             this.estimatedModuleSize = estimatedModuleSize;
  8687.        
  8688.             this.__defineGetter__("EstimatedModuleSize", function()
  8689.             {
  8690.                     return this.estimatedModuleSize;
  8691.             });
  8692.             this.__defineGetter__("Count", function()
  8693.             {
  8694.                     return this.count;
  8695.             });
  8696.             this.__defineGetter__("X", function()
  8697.             {
  8698.                     return this.x;
  8699.             });
  8700.             this.__defineGetter__("Y", function()
  8701.             {
  8702.                     return this.y;
  8703.             });
  8704.             this.incrementCount = function()
  8705.             {
  8706.                     this.count++;
  8707.             }
  8708.             this.aboutEquals=function( moduleSize,  i,  j)
  8709.                     {
  8710.                             if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize)
  8711.                             {
  8712.                                     var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
  8713.                                     return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0;
  8714.                             }
  8715.                             return false;
  8716.                     }
  8717.        
  8718.     }
  8719.  
  8720.     function FinderPatternInfo(patternCenters)
  8721.     {
  8722.             this.bottomLeft = patternCenters[0];
  8723.             this.topLeft = patternCenters[1];
  8724.             this.topRight = patternCenters[2];
  8725.             this.__defineGetter__("BottomLeft", function()
  8726.             {
  8727.                     return this.bottomLeft;
  8728.             });
  8729.             this.__defineGetter__("TopLeft", function()
  8730.             {
  8731.                     return this.topLeft;
  8732.             });
  8733.             this.__defineGetter__("TopRight", function()
  8734.             {
  8735.                     return this.topRight;
  8736.             });
  8737.     }
  8738.  
  8739.     function FinderPatternFinder()
  8740.     {
  8741.             this.image=null;
  8742.             this.possibleCenters = [];
  8743.             this.hasSkipped = false;
  8744.             this.crossCheckStateCount = new Array(0,0,0,0,0);
  8745.             this.resultPointCallback = null;
  8746.        
  8747.             this.__defineGetter__("CrossCheckStateCount", function()
  8748.             {
  8749.                     this.crossCheckStateCount[0] = 0;
  8750.                     this.crossCheckStateCount[1] = 0;
  8751.                     this.crossCheckStateCount[2] = 0;
  8752.                     this.crossCheckStateCount[3] = 0;
  8753.                     this.crossCheckStateCount[4] = 0;
  8754.                     return this.crossCheckStateCount;
  8755.             });
  8756.        
  8757.             this.foundPatternCross=function( stateCount)
  8758.                     {
  8759.                             var totalModuleSize = 0;
  8760.                             for (var i = 0; i < 5; i++)
  8761.                             {
  8762.                                     var count = stateCount[i];
  8763.                                     if (count == 0)
  8764.                                     {
  8765.                                             return false;
  8766.                                     }
  8767.                                     totalModuleSize += count;
  8768.                             }
  8769.                             if (totalModuleSize < 7)
  8770.                             {
  8771.                                     return false;
  8772.                             }
  8773.                             var moduleSize = Math.floor((totalModuleSize << INTEGER_MATH_SHIFT) / 7);
  8774.                             var maxVariance = Math.floor(moduleSize / 2);
  8775.                             // Allow less than 50% variance from 1-1-3-1-1 proportions
  8776.                             return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;
  8777.                     }
  8778.             this.centerFromEnd=function( stateCount,  end)
  8779.                     {
  8780.                             return  (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0;
  8781.                     }
  8782.             this.crossCheckVertical=function( startI,  centerJ,  maxCount,  originalStateCountTotal)
  8783.                     {
  8784.                             var image = this.image;
  8785.                        
  8786.                             var maxI = qrcode.height;
  8787.                             var stateCount = this.CrossCheckStateCount;
  8788.                        
  8789.                             // Start counting up from center
  8790.                             var i = startI;
  8791.                             while (i >= 0 && image[centerJ + i*qrcode.width])
  8792.                             {
  8793.                                     stateCount[2]++;
  8794.                                     i--;
  8795.                             }
  8796.                             if (i < 0)
  8797.                             {
  8798.                                     return NaN;
  8799.                             }
  8800.                             while (i >= 0 && !image[centerJ +i*qrcode.width] && stateCount[1] <= maxCount)
  8801.                             {
  8802.                                     stateCount[1]++;
  8803.                                     i--;
  8804.                             }
  8805.                             // If already too many modules in this state or ran off the edge:
  8806.                             if (i < 0 || stateCount[1] > maxCount)
  8807.                             {
  8808.                                     return NaN;
  8809.                             }
  8810.                             while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount)
  8811.                             {
  8812.                                     stateCount[0]++;
  8813.                                     i--;
  8814.                             }
  8815.                             if (stateCount[0] > maxCount)
  8816.                             {
  8817.                                     return NaN;
  8818.                             }
  8819.                        
  8820.                             // Now also count down from center
  8821.                             i = startI + 1;
  8822.                             while (i < maxI && image[centerJ +i*qrcode.width])
  8823.                             {
  8824.                                     stateCount[2]++;
  8825.                                     i++;
  8826.                             }
  8827.                             if (i == maxI)
  8828.                             {
  8829.                                     return NaN;
  8830.                             }
  8831.                             while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[3] < maxCount)
  8832.                             {
  8833.                                     stateCount[3]++;
  8834.                                     i++;
  8835.                             }
  8836.                             if (i == maxI || stateCount[3] >= maxCount)
  8837.                             {
  8838.                                     return NaN;
  8839.                             }
  8840.                             while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[4] < maxCount)
  8841.                             {
  8842.                                     stateCount[4]++;
  8843.                                     i++;
  8844.                             }
  8845.                             if (stateCount[4] >= maxCount)
  8846.                             {
  8847.                                     return NaN;
  8848.                             }
  8849.                        
  8850.                             // If we found a finder-pattern-like section, but its size is more than 40% different than
  8851.                             // the original, assume it's a false positive
  8852.                             var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  8853.                             if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal)
  8854.                             {
  8855.                                     return NaN;
  8856.                             }
  8857.                        
  8858.                             return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN;
  8859.                     }
  8860.             this.crossCheckHorizontal=function( startJ,  centerI,  maxCount, originalStateCountTotal)
  8861.                     {
  8862.                             var image = this.image;
  8863.                        
  8864.                             var maxJ = qrcode.width;
  8865.                             var stateCount = this.CrossCheckStateCount;
  8866.                        
  8867.                             var j = startJ;
  8868.                             while (j >= 0 && image[j+ centerI*qrcode.width])
  8869.                             {
  8870.                                     stateCount[2]++;
  8871.                                     j--;
  8872.                             }
  8873.                             if (j < 0)
  8874.                             {
  8875.                                     return NaN;
  8876.                             }
  8877.                             while (j >= 0 && !image[j+ centerI*qrcode.width] && stateCount[1] <= maxCount)
  8878.                             {
  8879.                                     stateCount[1]++;
  8880.                                     j--;
  8881.                             }
  8882.                             if (j < 0 || stateCount[1] > maxCount)
  8883.                             {
  8884.                                     return NaN;
  8885.                             }
  8886.                             while (j >= 0 && image[j+ centerI*qrcode.width] && stateCount[0] <= maxCount)
  8887.                             {
  8888.                                     stateCount[0]++;
  8889.                                     j--;
  8890.                             }
  8891.                             if (stateCount[0] > maxCount)
  8892.                             {
  8893.                                     return NaN;
  8894.                             }
  8895.                        
  8896.                             j = startJ + 1;
  8897.                             while (j < maxJ && image[j+ centerI*qrcode.width])
  8898.                             {
  8899.                                     stateCount[2]++;
  8900.                                     j++;
  8901.                             }
  8902.                             if (j == maxJ)
  8903.                             {
  8904.                                     return NaN;
  8905.                             }
  8906.                             while (j < maxJ && !image[j+ centerI*qrcode.width] && stateCount[3] < maxCount)
  8907.                             {
  8908.                                     stateCount[3]++;
  8909.                                     j++;
  8910.                             }
  8911.                             if (j == maxJ || stateCount[3] >= maxCount)
  8912.                             {
  8913.                                     return NaN;
  8914.                             }
  8915.                             while (j < maxJ && image[j+ centerI*qrcode.width] && stateCount[4] < maxCount)
  8916.                             {
  8917.                                     stateCount[4]++;
  8918.                                     j++;
  8919.                             }
  8920.                             if (stateCount[4] >= maxCount)
  8921.                             {
  8922.                                     return NaN;
  8923.                             }
  8924.                        
  8925.                             // If we found a finder-pattern-like section, but its size is significantly different than
  8926.                             // the original, assume it's a false positive
  8927.                             var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  8928.                             if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal)
  8929.                             {
  8930.                                     return NaN;
  8931.                             }
  8932.                        
  8933.                             return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, j):NaN;
  8934.                     }
  8935.             this.handlePossibleCenter=function( stateCount,  i,  j)
  8936.                     {
  8937.                             var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  8938.                             var centerJ = this.centerFromEnd(stateCount, j); //float
  8939.                             var centerI = this.crossCheckVertical(i, Math.floor( centerJ), stateCount[2], stateCountTotal); //float
  8940.                             if (!isNaN(centerI))
  8941.                             {
  8942.                                     // Re-cross check
  8943.                                     centerJ = this.crossCheckHorizontal(Math.floor( centerJ), Math.floor( centerI), stateCount[2], stateCountTotal);
  8944.                                     if (!isNaN(centerJ))
  8945.                                     {
  8946.                                             var estimatedModuleSize =   stateCountTotal / 7.0;
  8947.                                             var found = false;
  8948.                                             var max = this.possibleCenters.length;
  8949.                                             for (var index = 0; index < max; index++)
  8950.                                             {
  8951.                                                     var center = this.possibleCenters[index];
  8952.                                                     // Look for about the same center and module size:
  8953.                                                     if (center.aboutEquals(estimatedModuleSize, centerI, centerJ))
  8954.                                                     {
  8955.                                                             center.incrementCount();
  8956.                                                             found = true;
  8957.                                                             break;
  8958.                                                     }
  8959.                                             }
  8960.                                             if (!found)
  8961.                                             {
  8962.                                                     var point = new FinderPattern(centerJ, centerI, estimatedModuleSize);
  8963.                                                     this.possibleCenters.push(point);
  8964.                                                     if (this.resultPointCallback != null)
  8965.                                                     {
  8966.                                                             this.resultPointCallback.foundPossibleResultPoint(point);
  8967.                                                     }
  8968.                                             }
  8969.                                             return true;
  8970.                                     }
  8971.                             }
  8972.                             return false;
  8973.                     }
  8974.                
  8975.             this.selectBestPatterns=function()
  8976.                     {
  8977.                        
  8978.                             var startSize = this.possibleCenters.length;
  8979.                             if (startSize < 3)
  8980.                             {
  8981.                                     // Couldn't find enough finder patterns
  8982.                                     throw "Couldn't find enough finder patterns";
  8983.                             }
  8984.                        
  8985.                             // Filter outlier possibilities whose module size is too different
  8986.                             if (startSize > 3)
  8987.                             {
  8988.                                     // But we can only afford to do so if we have at least 4 possibilities to choose from
  8989.                                     var totalModuleSize = 0.0;
  8990.                     var square = 0.0;
  8991.                                     for (var i = 0; i < startSize; i++)
  8992.                                     {
  8993.                                             //totalModuleSize +=  this.possibleCenters[i].EstimatedModuleSize;
  8994.                         var        centerValue=this.possibleCenters[i].EstimatedModuleSize;
  8995.                                             totalModuleSize += centerValue;
  8996.                                             square += (centerValue * centerValue);
  8997.                                     }
  8998.                                     var average = totalModuleSize /  startSize;
  8999.                     this.possibleCenters.sort(function(center1,center2) {
  9000.                                           var dA=Math.abs(center2.EstimatedModuleSize - average);
  9001.                                           var dB=Math.abs(center1.EstimatedModuleSize - average);
  9002.                                           if (dA < dB) {
  9003.                                                   return (-1);
  9004.                                           } else if (dA == dB) {
  9005.                                                   return 0;
  9006.                                           } else {
  9007.                                                   return 1;
  9008.                                           }
  9009.                                             });
  9010.  
  9011.                                     var stdDev = Math.sqrt(square / startSize - average * average);
  9012.                                     var limit = Math.max(0.2 * average, stdDev);
  9013.                                     for (var i = 0; i < this.possibleCenters.length && this.possibleCenters.length > 3; i++)
  9014.                                     {
  9015.                                             var pattern =  this.possibleCenters[i];
  9016.                                             //if (Math.abs(pattern.EstimatedModuleSize - average) > 0.2 * average)
  9017.                         if (Math.abs(pattern.EstimatedModuleSize - average) > limit)
  9018.                                             {
  9019.                                                     arrayRemove(this.possibleCenters, i);
  9020.                                                     i--;
  9021.                                             }
  9022.                                     }
  9023.                             }
  9024.                        
  9025.                             if (this.possibleCenters.length > 3)
  9026.                             {
  9027.                                     // Throw away all but those first size candidate points we found.
  9028.                                     this.possibleCenters.sort(function(a, b){
  9029.                                             if (a.count > b.count){return -1;}
  9030.                                             if (a.count < b.count){return 1;}
  9031.                                             return 0;
  9032.                                     });
  9033.                             }
  9034.                        
  9035.                             return new Array( this.possibleCenters[0],  this.possibleCenters[1],  this.possibleCenters[2]);
  9036.                     }
  9037.                
  9038.             this.findRowSkip=function()
  9039.                     {
  9040.                             var max = this.possibleCenters.length;
  9041.                             if (max <= 1)
  9042.                             {
  9043.                                     return 0;
  9044.                             }
  9045.                             var firstConfirmedCenter = null;
  9046.                             for (var i = 0; i < max; i++)
  9047.                             {
  9048.                                     var center =  this.possibleCenters[i];
  9049.                                     if (center.Count >= CENTER_QUORUM)
  9050.                                     {
  9051.                                             if (firstConfirmedCenter == null)
  9052.                                             {
  9053.                                                     firstConfirmedCenter = center;
  9054.                                             }
  9055.                                             else
  9056.                                             {
  9057.                                                     // We have two confirmed centers
  9058.                                                     // How far down can we skip before resuming looking for the next
  9059.                                                     // pattern? In the worst case, only the difference between the
  9060.                                                     // difference in the x / y coordinates of the two centers.
  9061.                                                     // This is the case where you find top left last.
  9062.                                                     this.hasSkipped = true;
  9063.                                                     return Math.floor ((Math.abs(firstConfirmedCenter.X - center.X) - Math.abs(firstConfirmedCenter.Y - center.Y)) / 2);
  9064.                                             }
  9065.                                     }
  9066.                             }
  9067.                             return 0;
  9068.                     }
  9069.        
  9070.             this.haveMultiplyConfirmedCenters=function()
  9071.                     {
  9072.                             var confirmedCount = 0;
  9073.                             var totalModuleSize = 0.0;
  9074.                             var max = this.possibleCenters.length;
  9075.                             for (var i = 0; i < max; i++)
  9076.                             {
  9077.                                     var pattern =  this.possibleCenters[i];
  9078.                                     if (pattern.Count >= CENTER_QUORUM)
  9079.                                     {
  9080.                                             confirmedCount++;
  9081.                                             totalModuleSize += pattern.EstimatedModuleSize;
  9082.                                     }
  9083.                             }
  9084.                             if (confirmedCount < 3)
  9085.                             {
  9086.                                     return false;
  9087.                             }
  9088.                             // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
  9089.                             // and that we need to keep looking. We detect this by asking if the estimated module sizes
  9090.                             // vary too much. We arbitrarily say that when the total deviation from average exceeds
  9091.                             // 5% of the total module size estimates, it's too much.
  9092.                             var average = totalModuleSize / max;
  9093.                             var totalDeviation = 0.0;
  9094.                             for (var i = 0; i < max; i++)
  9095.                             {
  9096.                                     pattern = this.possibleCenters[i];
  9097.                                     totalDeviation += Math.abs(pattern.EstimatedModuleSize - average);
  9098.                             }
  9099.                             return totalDeviation <= 0.05 * totalModuleSize;
  9100.                     }
  9101.                
  9102.             this.findFinderPattern = function(image){
  9103.                     var tryHarder = false;
  9104.                     this.image=image;
  9105.                     var maxI = qrcode.height;
  9106.                     var maxJ = qrcode.width;
  9107.                     var iSkip = Math.floor((3 * maxI) / (4 * MAX_MODULES));
  9108.                     if (iSkip < MIN_SKIP || tryHarder)
  9109.                     {
  9110.                                     iSkip = MIN_SKIP;
  9111.                     }
  9112.                
  9113.                     var done = false;
  9114.                     var stateCount = new Array(5);
  9115.                     for (var i = iSkip - 1; i < maxI && !done; i += iSkip)
  9116.                     {
  9117.                             // Get a row of black/white values
  9118.                             stateCount[0] = 0;
  9119.                             stateCount[1] = 0;
  9120.                             stateCount[2] = 0;
  9121.                             stateCount[3] = 0;
  9122.                             stateCount[4] = 0;
  9123.                             var currentState = 0;
  9124.                             for (var j = 0; j < maxJ; j++)
  9125.                             {
  9126.                                     if (image[j+i*qrcode.width] )
  9127.                                     {
  9128.                                             // Black pixel
  9129.                                             if ((currentState & 1) == 1)
  9130.                                             {
  9131.                                                     // Counting white pixels
  9132.                                                     currentState++;
  9133.                                             }
  9134.                                             stateCount[currentState]++;
  9135.                                     }
  9136.                                     else
  9137.                                     {
  9138.                                             // White pixel
  9139.                                             if ((currentState & 1) == 0)
  9140.                                             {
  9141.                                                     // Counting black pixels
  9142.                                                     if (currentState == 4)
  9143.                                                     {
  9144.                                                             // A winner?
  9145.                                                             if (this.foundPatternCross(stateCount))
  9146.                                                             {
  9147.                                                                     // Yes
  9148.                                                                     var confirmed = this.handlePossibleCenter(stateCount, i, j);
  9149.                                                                     if (confirmed)
  9150.                                                                     {
  9151.                                                                             // Start examining every other line. Checking each line turned out to be too
  9152.                                                                             // expensive and didn't improve performance.
  9153.                                                                             iSkip = 2;
  9154.                                                                             if (this.hasSkipped)
  9155.                                                                             {
  9156.                                                                                     done = this.haveMultiplyConfirmedCenters();
  9157.                                                                             }
  9158.                                                                             else
  9159.                                                                             {
  9160.                                                                                     var rowSkip = this.findRowSkip();
  9161.                                                                                     if (rowSkip > stateCount[2])
  9162.                                                                                     {
  9163.                                                                                             // Skip rows between row of lower confirmed center
  9164.                                                                                             // and top of presumed third confirmed center
  9165.                                                                                             // but back up a bit to get a full chance of detecting
  9166.                                                                                             // it, entire width of center of finder pattern
  9167.                                                                                        
  9168.                                                                                             // Skip by rowSkip, but back off by stateCount[2] (size of last center
  9169.                                                                                             // of pattern we saw) to be conservative, and also back off by iSkip which
  9170.                                                                                             // is about to be re-added
  9171.                                                                                             i += rowSkip - stateCount[2] - iSkip;
  9172.                                                                                             j = maxJ - 1;
  9173.                                                                                     }
  9174.                                                                             }
  9175.                                                                     }
  9176.                                                                     else
  9177.                                                                     {
  9178.                                                                             // Advance to next black pixel
  9179.                                                                             do
  9180.                                                                             {
  9181.                                                                                     j++;
  9182.                                                                             }
  9183.                                                                             while (j < maxJ && !image[j + i*qrcode.width]);
  9184.                                                                             j--; // back up to that last white pixel
  9185.                                                                     }
  9186.                                                                     // Clear state to start looking again
  9187.                                                                     currentState = 0;
  9188.                                                                     stateCount[0] = 0;
  9189.                                                                     stateCount[1] = 0;
  9190.                                                                     stateCount[2] = 0;
  9191.                                                                     stateCount[3] = 0;
  9192.                                                                     stateCount[4] = 0;
  9193.                                                             }
  9194.                                                             else
  9195.                                                             {
  9196.                                                                     // No, shift counts back by two
  9197.                                                                     stateCount[0] = stateCount[2];
  9198.                                                                     stateCount[1] = stateCount[3];
  9199.                                                                     stateCount[2] = stateCount[4];
  9200.                                                                     stateCount[3] = 1;
  9201.                                                                     stateCount[4] = 0;
  9202.                                                                     currentState = 3;
  9203.                                                             }
  9204.                                                     }
  9205.                                                     else
  9206.                                                     {
  9207.                                                             stateCount[++currentState]++;
  9208.                                                     }
  9209.                                             }
  9210.                                             else
  9211.                                             {
  9212.                                                     // Counting white pixels
  9213.                                                     stateCount[currentState]++;
  9214.                                             }
  9215.                                     }
  9216.                             }
  9217.                             if (this.foundPatternCross(stateCount))
  9218.                             {
  9219.                                     var confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
  9220.                                     if (confirmed)
  9221.                                     {
  9222.                                             iSkip = stateCount[0];
  9223.                                             if (this.hasSkipped)
  9224.                                             {
  9225.                                                     // Found a third one
  9226.                                                     done = haveMultiplyConfirmedCenters();
  9227.                                             }
  9228.                                     }
  9229.                             }
  9230.                     }
  9231.                
  9232.                     var patternInfo = this.selectBestPatterns();
  9233.                     qrcode.orderBestPatterns(patternInfo);
  9234.                
  9235.                     return new FinderPatternInfo(patternInfo);
  9236.             };
  9237.     }
  9238.  
  9239.     function AlignmentPattern(posX, posY,  estimatedModuleSize)
  9240.     {
  9241.             this.x=posX;
  9242.             this.y=posY;
  9243.             this.count = 1;
  9244.             this.estimatedModuleSize = estimatedModuleSize;
  9245.        
  9246.             this.__defineGetter__("EstimatedModuleSize", function()
  9247.             {
  9248.                     return this.estimatedModuleSize;
  9249.             });
  9250.             this.__defineGetter__("Count", function()
  9251.             {
  9252.                     return this.count;
  9253.             });
  9254.             this.__defineGetter__("X", function()
  9255.             {
  9256.                     return Math.floor(this.x);
  9257.             });
  9258.             this.__defineGetter__("Y", function()
  9259.             {
  9260.                     return Math.floor(this.y);
  9261.             });
  9262.             this.incrementCount = function()
  9263.             {
  9264.                     this.count++;
  9265.             }
  9266.             this.aboutEquals=function( moduleSize,  i,  j)
  9267.                     {
  9268.                             if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize)
  9269.                             {
  9270.                                     var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
  9271.                                     return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0;
  9272.                             }
  9273.                             return false;
  9274.                     }
  9275.        
  9276.     }
  9277.  
  9278.     function AlignmentPatternFinder( image,  startX,  startY,  width,  height,  moduleSize,  resultPointCallback)
  9279.     {
  9280.             this.image = image;
  9281.             this.possibleCenters = new Array();
  9282.             this.startX = startX;
  9283.             this.startY = startY;
  9284.             this.width = width;
  9285.             this.height = height;
  9286.             this.moduleSize = moduleSize;
  9287.             this.crossCheckStateCount = new Array(0,0,0);
  9288.             this.resultPointCallback = resultPointCallback;
  9289.        
  9290.             this.centerFromEnd=function(stateCount,  end)
  9291.                     {
  9292.                             return  (end - stateCount[2]) - stateCount[1] / 2.0;
  9293.                     }
  9294.             this.foundPatternCross = function(stateCount)
  9295.                     {
  9296.                             var moduleSize = this.moduleSize;
  9297.                             var maxVariance = moduleSize / 2.0;
  9298.                             for (var i = 0; i < 3; i++)
  9299.                             {
  9300.                                     if (Math.abs(moduleSize - stateCount[i]) >= maxVariance)
  9301.                                     {
  9302.                                             return false;
  9303.                                     }
  9304.                             }
  9305.                             return true;
  9306.                     }
  9307.  
  9308.             this.crossCheckVertical=function( startI,  centerJ,  maxCount,  originalStateCountTotal)
  9309.                     {
  9310.                             var image = this.image;
  9311.                        
  9312.                             var maxI = qrcode.height;
  9313.                             var stateCount = this.crossCheckStateCount;
  9314.                             stateCount[0] = 0;
  9315.                             stateCount[1] = 0;
  9316.                             stateCount[2] = 0;
  9317.                        
  9318.                             // Start counting up from center
  9319.                             var i = startI;
  9320.                             while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
  9321.                             {
  9322.                                     stateCount[1]++;
  9323.                                     i--;
  9324.                             }
  9325.                             // If already too many modules in this state or ran off the edge:
  9326.                             if (i < 0 || stateCount[1] > maxCount)
  9327.                             {
  9328.                                     return NaN;
  9329.                             }
  9330.                             while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount)
  9331.                             {
  9332.                                     stateCount[0]++;
  9333.                                     i--;
  9334.                             }
  9335.                             if (stateCount[0] > maxCount)
  9336.                             {
  9337.                                     return NaN;
  9338.                             }
  9339.                        
  9340.                             // Now also count down from center
  9341.                             i = startI + 1;
  9342.                             while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
  9343.                             {
  9344.                                     stateCount[1]++;
  9345.                                     i++;
  9346.                             }
  9347.                             if (i == maxI || stateCount[1] > maxCount)
  9348.                             {
  9349.                                     return NaN;
  9350.                             }
  9351.                             while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount)
  9352.                             {
  9353.                                     stateCount[2]++;
  9354.                                     i++;
  9355.                             }
  9356.                             if (stateCount[2] > maxCount)
  9357.                             {
  9358.                                     return NaN;
  9359.                             }
  9360.                        
  9361.                             var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  9362.                             if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal)
  9363.                             {
  9364.                                     return NaN;
  9365.                             }
  9366.                        
  9367.                             return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN;
  9368.                     }
  9369.                
  9370.             this.handlePossibleCenter=function( stateCount,  i,  j)
  9371.                     {
  9372.                             var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  9373.                             var centerJ = this.centerFromEnd(stateCount, j);
  9374.                             var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal);
  9375.                             if (!isNaN(centerI))
  9376.                             {
  9377.                                     var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0;
  9378.                                     var max = this.possibleCenters.length;
  9379.                                     for (var index = 0; index < max; index++)
  9380.                                     {
  9381.                                             var center =  this.possibleCenters[index];
  9382.                                             // Look for about the same center and module size:
  9383.                                             if (center.aboutEquals(estimatedModuleSize, centerI, centerJ))
  9384.                                             {
  9385.                                                     return new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
  9386.                                             }
  9387.                                     }
  9388.                                     // Hadn't found this before; save it
  9389.                                     var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
  9390.                                     this.possibleCenters.push(point);
  9391.                                     if (this.resultPointCallback != null)
  9392.                                     {
  9393.                                             this.resultPointCallback.foundPossibleResultPoint(point);
  9394.                                     }
  9395.                             }
  9396.                             return null;
  9397.                     }
  9398.                
  9399.             this.find = function()
  9400.             {
  9401.                             var startX = this.startX;
  9402.                             var height = this.height;
  9403.                             var maxJ = startX + width;
  9404.                             var middleI = startY + (height >> 1);
  9405.                             // We are looking for black/white/black modules in 1:1:1 ratio;
  9406.                             // this tracks the number of black/white/black modules seen so far
  9407.                             var stateCount = new Array(0,0,0);
  9408.                             for (var iGen = 0; iGen < height; iGen++)
  9409.                             {
  9410.                                     // Search from middle outwards
  9411.                                     var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1));
  9412.                                     stateCount[0] = 0;
  9413.                                     stateCount[1] = 0;
  9414.                                     stateCount[2] = 0;
  9415.                                     var j = startX;
  9416.                                     // Burn off leading white pixels before anything else; if we start in the middle of
  9417.                                     // a white run, it doesn't make sense to count its length, since we don't know if the
  9418.                                     // white run continued to the left of the start point
  9419.                                     while (j < maxJ && !image[j + qrcode.width* i])
  9420.                                     {
  9421.                                             j++;
  9422.                                     }
  9423.                                     var currentState = 0;
  9424.                                     while (j < maxJ)
  9425.                                     {
  9426.                                             if (image[j + i*qrcode.width])
  9427.                                             {
  9428.                                                     // Black pixel
  9429.                                                     if (currentState == 1)
  9430.                                                     {
  9431.                                                             // Counting black pixels
  9432.                                                             stateCount[currentState]++;
  9433.                                                     }
  9434.                                                     else
  9435.                                                     {
  9436.                                                             // Counting white pixels
  9437.                                                             if (currentState == 2)
  9438.                                                             {
  9439.                                                                     // A winner?
  9440.                                                                     if (this.foundPatternCross(stateCount))
  9441.                                                                     {
  9442.                                                                             // Yes
  9443.                                                                             var confirmed = this.handlePossibleCenter(stateCount, i, j);
  9444.                                                                             if (confirmed != null)
  9445.                                                                             {
  9446.                                                                                     return confirmed;
  9447.                                                                             }
  9448.                                                                     }
  9449.                                                                     stateCount[0] = stateCount[2];
  9450.                                                                     stateCount[1] = 1;
  9451.                                                                     stateCount[2] = 0;
  9452.                                                                     currentState = 1;
  9453.                                                             }
  9454.                                                             else
  9455.                                                             {
  9456.                                                                     stateCount[++currentState]++;
  9457.                                                             }
  9458.                                                     }
  9459.                                             }
  9460.                                             else
  9461.                                             {
  9462.                                                     // White pixel
  9463.                                                     if (currentState == 1)
  9464.                                                     {
  9465.                                                             // Counting black pixels
  9466.                                                             currentState++;
  9467.                                                     }
  9468.                                                     stateCount[currentState]++;
  9469.                                             }
  9470.                                             j++;
  9471.                                     }
  9472.                                     if (this.foundPatternCross(stateCount))
  9473.                                     {
  9474.                                             var confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
  9475.                                             if (confirmed != null)
  9476.                                             {
  9477.                                                     return confirmed;
  9478.                                             }
  9479.                                     }
  9480.                             }
  9481.                        
  9482.                             // Hmm, nothing we saw was observed and confirmed twice. If we had
  9483.                             // any guess at all, return it.
  9484.                             if (!(this.possibleCenters.length == 0))
  9485.                             {
  9486.                                     return  this.possibleCenters[0];
  9487.                             }
  9488.                        
  9489.                             throw "Couldn't find enough alignment patterns";
  9490.                     }
  9491.        
  9492.     }
  9493.  
  9494.     function QRCodeDataBlockReader(blocks,  version,  numErrorCorrectionCode)
  9495.     {
  9496.             this.blockPointer = 0;
  9497.             this.bitPointer = 7;
  9498.             this.dataLength = 0;
  9499.             this.blocks = blocks;
  9500.             this.numErrorCorrectionCode = numErrorCorrectionCode;
  9501.             if (version <= 9)
  9502.                     this.dataLengthMode = 0;
  9503.             else if (version >= 10 && version <= 26)
  9504.                     this.dataLengthMode = 1;
  9505.             else if (version >= 27 && version <= 40)
  9506.                     this.dataLengthMode = 2;
  9507.                
  9508.             this.getNextBits = function( numBits)
  9509.                     {                        
  9510.                             var bits = 0;
  9511.                             if (numBits < this.bitPointer + 1)
  9512.                             {
  9513.                                     // next word fits into current data block
  9514.                                     var mask = 0;
  9515.                                     for (var i = 0; i < numBits; i++)
  9516.                                     {
  9517.                                             mask += (1 << i);
  9518.                                     }
  9519.                                     mask <<= (this.bitPointer - numBits + 1);
  9520.                                
  9521.                                     bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1);
  9522.                                     this.bitPointer -= numBits;
  9523.                                     return bits;
  9524.                             }
  9525.                             else if (numBits < this.bitPointer + 1 + 8)
  9526.                             {
  9527.                                     // next word crosses 2 data blocks
  9528.                                     var mask1 = 0;
  9529.                                     for (var i = 0; i < this.bitPointer + 1; i++)
  9530.                                     {
  9531.                                             mask1 += (1 << i);
  9532.                                     }
  9533.                                     bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1));
  9534.                     this.blockPointer++;
  9535.                                     bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1))));
  9536.                                
  9537.                                     this.bitPointer = this.bitPointer - numBits % 8;
  9538.                                     if (this.bitPointer < 0)
  9539.                                     {
  9540.                                             this.bitPointer = 8 + this.bitPointer;
  9541.                                     }
  9542.                                     return bits;
  9543.                             }
  9544.                             else if (numBits < this.bitPointer + 1 + 16)
  9545.                             {
  9546.                                     // next word crosses 3 data blocks
  9547.                                     var mask1 = 0; // mask of first block
  9548.                                     var mask3 = 0; // mask of 3rd block
  9549.                                     //bitPointer + 1 : number of bits of the 1st block
  9550.                                     //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks)
  9551.                                     //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block
  9552.                                     for (var i = 0; i < this.bitPointer + 1; i++)
  9553.                                     {
  9554.                                             mask1 += (1 << i);
  9555.                                     }
  9556.                                     var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1));
  9557.                                     this.blockPointer++;
  9558.                                
  9559.                                     var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8));
  9560.                                     this.blockPointer++;
  9561.                                
  9562.                                     for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++)
  9563.                                     {
  9564.                                             mask3 += (1 << i);
  9565.                                     }
  9566.                                     mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8));
  9567.                                     var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8)));
  9568.                                
  9569.                                     bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock;
  9570.                                     this.bitPointer = this.bitPointer - (numBits - 8) % 8;
  9571.                                     if (this.bitPointer < 0)
  9572.                                     {
  9573.                                             this.bitPointer = 8 + this.bitPointer;
  9574.                                     }
  9575.                                     return bits;
  9576.                             }
  9577.                             else
  9578.                             {
  9579.                                     return 0;
  9580.                             }
  9581.                     }
  9582.             this.NextMode=function()
  9583.             {
  9584.                     if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2))
  9585.                             return 0;
  9586.                     else
  9587.                             return this.getNextBits(4);
  9588.             }
  9589.             this.getDataLength=function( modeIndicator)
  9590.                     {
  9591.                             var index = 0;
  9592.                             while (true)
  9593.                             {
  9594.                                     if ((modeIndicator >> index) == 1)
  9595.                                             break;
  9596.                                     index++;
  9597.                             }
  9598.                        
  9599.                             return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]);
  9600.                     }
  9601.             this.getRomanAndFigureString=function( dataLength)
  9602.                     {
  9603.                             var length = dataLength;
  9604.                             var intData = 0;
  9605.                             var strData = "";
  9606.                             var tableRomanAndFigure = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':');
  9607.                             do
  9608.                             {
  9609.                                     if (length > 1)
  9610.                                     {
  9611.                                             intData = this.getNextBits(11);
  9612.                                             var firstLetter = Math.floor(intData / 45);
  9613.                                             var secondLetter = intData % 45;
  9614.                                             strData += tableRomanAndFigure[firstLetter];
  9615.                                             strData += tableRomanAndFigure[secondLetter];
  9616.                                             length -= 2;
  9617.                                     }
  9618.                                     else if (length == 1)
  9619.                                     {
  9620.                                             intData = this.getNextBits(6);
  9621.                                             strData += tableRomanAndFigure[intData];
  9622.                                             length -= 1;
  9623.                                     }
  9624.                             }
  9625.                             while (length > 0);
  9626.                        
  9627.                             return strData;
  9628.                     }
  9629.             this.getFigureString=function( dataLength)
  9630.                     {
  9631.                             var length = dataLength;
  9632.                             var intData = 0;
  9633.                             var strData = "";
  9634.                             do
  9635.                             {
  9636.                                     if (length >= 3)
  9637.                                     {
  9638.                                             intData = this.getNextBits(10);
  9639.                                             if (intData < 100)
  9640.                                                     strData += "0";
  9641.                                             if (intData < 10)
  9642.                                                     strData += "0";
  9643.                                             length -= 3;
  9644.                                     }
  9645.                                     else if (length == 2)
  9646.                                     {
  9647.                                             intData = this.getNextBits(7);
  9648.                                             if (intData < 10)
  9649.                                                     strData += "0";
  9650.                                             length -= 2;
  9651.                                     }
  9652.                                     else if (length == 1)
  9653.                                     {
  9654.                                             intData = this.getNextBits(4);
  9655.                                             length -= 1;
  9656.                                     }
  9657.                                     strData += intData;
  9658.                             }
  9659.                             while (length > 0);
  9660.                        
  9661.                             return strData;
  9662.                     }
  9663.             this.get8bitByteArray=function( dataLength)
  9664.                     {
  9665.                             var length = dataLength;
  9666.                             var intData = 0;
  9667.                             var output = new Array();
  9668.                        
  9669.                             do
  9670.                             {
  9671.                                     intData = this.getNextBits(8);
  9672.                                     output.push( intData);
  9673.                                     length--;
  9674.                             }
  9675.                             while (length > 0);
  9676.                             return output;
  9677.                     }
  9678.         this.getKanjiString=function( dataLength)
  9679.                     {
  9680.                             var length = dataLength;
  9681.                             var intData = 0;
  9682.                             var unicodeString = "";
  9683.                             do
  9684.                             {
  9685.                                     intData = getNextBits(13);
  9686.                                     var lowerByte = intData % 0xC0;
  9687.                                     var higherByte = intData / 0xC0;
  9688.                                
  9689.                                     var tempWord = (higherByte << 8) + lowerByte;
  9690.                                     var shiftjisWord = 0;
  9691.                                     if (tempWord + 0x8140 <= 0x9FFC)
  9692.                                     {
  9693.                                             // between 8140 - 9FFC on Shift_JIS character set
  9694.                                             shiftjisWord = tempWord + 0x8140;
  9695.                                     }
  9696.                                     else
  9697.                                     {
  9698.                                             // between E040 - EBBF on Shift_JIS character set
  9699.                                             shiftjisWord = tempWord + 0xC140;
  9700.                                     }
  9701.                                
  9702.                                     //var tempByte = new Array(0,0);
  9703.                                     //tempByte[0] = (sbyte) (shiftjisWord >> 8);
  9704.                                     //tempByte[1] = (sbyte) (shiftjisWord & 0xFF);
  9705.                                     //unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte)));
  9706.                     unicodeString += String.fromCharCode(shiftjisWord);
  9707.                                     length--;
  9708.                             }
  9709.                             while (length > 0);
  9710.                        
  9711.                        
  9712.                             return unicodeString;
  9713.                     }
  9714.  
  9715.             this.__defineGetter__("DataByte", function()
  9716.             {
  9717.                     var output = new Array();
  9718.                     var MODE_NUMBER = 1;
  9719.                 var MODE_ROMAN_AND_NUMBER = 2;
  9720.                 var MODE_8BIT_BYTE = 4;
  9721.                 var MODE_KANJI = 8;
  9722.                     do
  9723.                                             {
  9724.                                                     var mode = this.NextMode();
  9725.                                                     //canvas.println("mode: " + mode);
  9726.                                                     if (mode == 0)
  9727.                                                     {
  9728.                                                             if (output.length > 0)
  9729.                                                                     break;
  9730.                                                             else
  9731.                                                                     throw "Empty data block";
  9732.                                                     }
  9733.                                                     //if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
  9734.                                                     //        break;
  9735.                                                     //}
  9736.                                                     if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
  9737.                                                     {
  9738.                                                             /*                                        canvas.println("Invalid mode: " + mode);
  9739.                                                             mode = guessMode(mode);
  9740.                                                             canvas.println("Guessed mode: " + mode); */
  9741.                                                             throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")";
  9742.                                                     }
  9743.                                                     dataLength = this.getDataLength(mode);
  9744.                                                     if (dataLength < 1)
  9745.                                                             throw "Invalid data length: " + dataLength;
  9746.                                                     //canvas.println("length: " + dataLength);
  9747.                                                     switch (mode)
  9748.                                                     {
  9749.                                                        
  9750.                                                             case MODE_NUMBER:
  9751.                                                                     //canvas.println("Mode: Figure");
  9752.                                                                     var temp_str = this.getFigureString(dataLength);
  9753.                                                                     var ta = new Array(temp_str.length);
  9754.                                                                     for(var j=0;j<temp_str.length;j++)
  9755.                                                                             ta[j]=temp_str.charCodeAt(j);
  9756.                                                                     output.push(ta);
  9757.                                                                     break;
  9758.                                                        
  9759.                                                             case MODE_ROMAN_AND_NUMBER:
  9760.                                                                     //canvas.println("Mode: Roman&Figure");
  9761.                                                                     var temp_str = this.getRomanAndFigureString(dataLength);
  9762.                                                                     var ta = new Array(temp_str.length);
  9763.                                                                     for(var j=0;j<temp_str.length;j++)
  9764.                                                                             ta[j]=temp_str.charCodeAt(j);
  9765.                                                                     output.push(ta );
  9766.                                                                     //output.Write(SystemUtils.ToByteArray(temp_sbyteArray2), 0, temp_sbyteArray2.Length);
  9767.                                                                     break;
  9768.                                                        
  9769.                                                             case MODE_8BIT_BYTE:
  9770.                                                                     //canvas.println("Mode: 8bit Byte");
  9771.                                                                     //sbyte[] temp_sbyteArray3;
  9772.                                                                     var temp_sbyteArray3 = this.get8bitByteArray(dataLength);
  9773.                                                                     output.push(temp_sbyteArray3);
  9774.                                                                     //output.Write(SystemUtils.ToByteArray(temp_sbyteArray3), 0, temp_sbyteArray3.Length);
  9775.                                                                     break;
  9776.                                                        
  9777.                                                             case MODE_KANJI:
  9778.                                                                     //canvas.println("Mode: Kanji");
  9779.                                                                     //sbyte[] temp_sbyteArray4;
  9780.                                                                     //temp_sbyteArray4 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getKanjiString(dataLength)));
  9781.                                                                     //output.Write(SystemUtils.ToByteArray(temp_sbyteArray4), 0, temp_sbyteArray4.Length);
  9782.                                     var temp_str = this.getKanjiString(dataLength);
  9783.                                                                     output.push(temp_str);
  9784.                                                                     break;
  9785.                                                             }
  9786.                                                     //                        
  9787.                                                     //canvas.println("DataLength: " + dataLength);
  9788.                                                     //Console.out.println(dataString);
  9789.                                             }
  9790.                                             while (true);
  9791.                     return output;
  9792.             });
  9793.     }
  9794.         </script>
  9795.  
  9796.         <script type="text/javascript">
  9797.     function QRCodeScanner(width, height, container, success, error) {
  9798.         navigator.getUserMedia = navigator.getUserMedia ||
  9799.             navigator.webkitGetUserMedia ||
  9800.             navigator.mozGetUserMedia ||
  9801.             navigator.msGetUserMedia;
  9802.         window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
  9803.  
  9804.         var _width = width;
  9805.         var _height = height;
  9806.         var _id_container = container;
  9807.         var _id_video = container + '_video';
  9808.         var _success = success;
  9809.         var _error = error;
  9810.  
  9811.         var _container = document.getElementById(container);
  9812.         var _video = null;
  9813.         var _stream = null;
  9814.         var _canvas = null;
  9815.         var _ctx = null;
  9816.         var _interval = null;
  9817.  
  9818.         function isCanvasSupported() {
  9819.             var elem = document.createElement('canvas');
  9820.             return !!(elem.getContext && elem.getContext('2d'));
  9821.         }
  9822.  
  9823.         function canvasInit() {
  9824.             _canvas = document.createElement('canvas');
  9825.             _canvas.width = _width;
  9826.             _canvas.height = _height;
  9827.             _ctx = _canvas.getContext('2d');
  9828.         }
  9829.  
  9830.         function captureToCanvas() {
  9831.             _ctx.drawImage(_video, 0, 0, _video.videoWidth, _video.videoHeight, 0, 0, _canvas.width, _canvas.height);
  9832.             qrcode.decode(_canvas.toDataURL());
  9833.         }
  9834.  
  9835.         this.isSupported = function() {
  9836.             if (!isCanvasSupported()) return false;
  9837.             if (!navigator.getUserMedia) return false;
  9838.             return true;
  9839.         }
  9840.  
  9841.         this.start = function() {
  9842.             if (_video) return;
  9843.             if (navigator.getUserMedia) {
  9844.                 //Append the video element
  9845.                 _container.innerHTML = '<video style="width:' + _width + 'px;height:' + _height + 'px" autoplay id="' + _id_video + '"></video>';
  9846.                 _video = document.getElementById(_id_video);
  9847.  
  9848.                 navigator.getUserMedia(
  9849.                     {video: true},
  9850.                     function(stream) {
  9851.                         _stream = stream;
  9852.                         _video.src = window.URL.createObjectURL(stream) || stream;
  9853.  
  9854.                         setTimeout(function() {
  9855.                             canvasInit();
  9856.                             _interval = setInterval(captureToCanvas, 500);
  9857.                         }, 250); // Needed to get videoWidth/videoHeight
  9858.                     },
  9859.                     function(error) {
  9860.                         _container.innerHTML = '';
  9861.                         _video = null;
  9862.                         if (error && error.message)
  9863.                             _error(error.message);
  9864.                         else if (error && error.name)
  9865.                             _error(error.name);
  9866.                         else
  9867.                             _error(error);
  9868.                     });
  9869.  
  9870.  
  9871.                 qrcode.callback = function(data) {
  9872.                     if (data && data.indexOf('error') != 0) {
  9873.                         stop();
  9874.                         if (data.indexOf('bitcoin:') == 0)
  9875.                             data = data.substring(8);
  9876.                         _success(data);
  9877.                     }
  9878.                 };
  9879.             }else{
  9880.                 _error('Sorry your browser is not supported. Please try Firefox, Chrome or safari.');
  9881.             }
  9882.         }
  9883.  
  9884.         function stop() {
  9885.             if (_interval) {
  9886.                 clearInterval(_interval);
  9887.                 _interval = null;
  9888.             }
  9889.  
  9890.             _container.innerHTML = '';
  9891.             _video = null;
  9892.  
  9893.             try {
  9894.                 if (_stream) {
  9895.                     _stream.stop();
  9896.                     _stream = null;
  9897.                 }
  9898.             } catch (e) {
  9899.                 console.log(e);
  9900.                 _error(e);
  9901.             }
  9902.         }
  9903.         this.stop = stop;
  9904.     }
  9905.     </script>
  9906.     <!-- END OF https://github.com/LazarSoft/jsqrcode -->
  9907.  
  9908. <!--    ****************************************************
  9909.         ***************** BEGIN STYLES *********************
  9910.         **************************************************** -->
  9911.  
  9912.  
  9913.     <style type="text/css">
  9914.            
  9915.         /*  import ubuntu mono bold as our font for display public & private keys.
  9916.             NOTE: This font has been stripped down such that it only includes characters A-Z, a-Z, and 0-9 */
  9917.         @font-face {
  9918.             font-family: 'ubuntu_mono_bold';
  9919.             src: url('images/ubuntumono-b-webfont.eot');
  9920.             src: url('images/ubuntumono-b-webfont.eot?#iefix') format('embedded-opentype'),
  9921.                  url('images/ubuntumono-b-webfont.woff') format('woff'),
  9922.                  url('images/ubuntumono-b-webfont.ttf') format('truetype'),
  9923.                  url('images/ubuntumono-b-webfont.svg#ubuntu_monobold') format('svg');
  9924.             font-weight: bold;
  9925.             font-style: normal;
  9926.         }
  9927.        
  9928.         .right { text-align: right; }
  9929.         .walletarea { display: none; }
  9930.         .keyarea { font-family: Courier New; height: 130px; text-align: left; position: relative; padding: 25px; }
  9931.         .keyarea .public { float: left; }
  9932.         .keyarea .pubaddress { display: inline-block; height: 40px; padding: 0 0 0 10px; float: left; }
  9933.         .keyarea .privwif { margin: 0; float: right; text-align: right; padding: 0 10px 0 0; position: relative; }
  9934.         .keyarea .label { text-decoration: underline; }
  9935.         .keyarea .output { display: block; }
  9936.         .keyarea .qrcode_public { display: inline-block; float: left; }
  9937.         .keyarea .qrcode_private { display: inline-block; float: right; }
  9938.         .pubkeyhex { word-wrap: break-word; }
  9939.         .faqs ol { padding: 0 0 0 25px; }
  9940.         .faqs li { padding: 3px 0; }
  9941.         body { margin-top: 0; font-family: Arial; background-image:url(images/webpage-background.png); background-repeat: repeat-y; background-position: center; background-color: #ffffff; font-size: 14px;}
  9942.        
  9943.         h1 { font-size: 24px; font-weight: 100; color: #3398cc; margin:0 0 10px 0; padding:0; }
  9944.        
  9945.         a, a:visited { text-decoration: none; color: #000000; }
  9946.         a:hover {color: #000000; text-decoration: underline;}
  9947.  
  9948.  
  9949.         #generatelabelmovemouse { background-color:#3398cc; position: absolute; z-index: 20; top: -10px; left: 0; margin: 0;  padding: 25px 55px; width: 901px; text-align: left;
  9950.         -webkit-box-shadow: #3398cc 1px 0px 1px; -moz-box-shadow: #3398cc 1px 0px 1px; box-shadow: #3398cc 1px 0px 1px; }
  9951.  
  9952.         #generate { height: 350px; text-align: left; position: relative; padding: 5px; border: none; line-height: 24px;}
  9953.        
  9954.         #generate input { font-size: 10px; }
  9955.        
  9956.         #generatelabelbitcoinaddress { font-size: 90%;}
  9957.                
  9958.         #seedpoolarea { display: none; }
  9959.         #seedpooldisplay {  font-family: monospace; font-size: 12px; width: 680px; padding: 0 0 0 0; word-wrap: break-word; color: #3398cc; line-height: 16px;}
  9960.  
  9961.         #seedSkipper { font-size: 11px; text-align: center; line-height: 14px;}
  9962.         .seedpoint { width: 12px; height: 12px; display: block; border-radius: 6px; background-color: #3398cc; border: 1px solid #000000; position: absolute; z-index: 10; }
  9963.         #generate #mousemovelimit { font-size: 16px; color: #3398cc; }
  9964.  
  9965.         #rightArea { float: right; width: 170px; }
  9966.  
  9967.         #progress-bar { width: 170px; background:#3398cc; position: relative; margin-bottom: 20px; }
  9968.         .fullyRounded { -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }
  9969.         #progress-bar-percentage { background:#ffffff; padding: 3px 0px; text-align: center; height: 18px; }
  9970.         #progress-bar-percentage span { display: inline-block; position: absolute; width: 100%; left: 0; }
  9971.                
  9972.         #main { position: relative; margin: 0px auto; width: 1010px; color: #3398cc; } /* removed text-align: center; */
  9973.         #logoback {  background-image:url(images/logo.png); background-position: top left; background-repeat: no-repeat; }
  9974.         #menu { visibility: hidden; font-size: 90%; padding: 0 12px;}
  9975.        
  9976.         #culturemenu { text-align: right; padding: 10px 20px; font-size: 12px; }
  9977.  
  9978.         #culturemenu { text-align: right; padding: 10px 20px; font-size: 12px;}
  9979.         #culturemenu span { padding: 3px; }
  9980.         #culturemenu .selected { text-decoration: none; color: #000000; }
  9981.  
  9982.         #calibratearea .calibratesvg { width: 1010px; height: 331px; border: 0; margin: 0; padding: 0; left: 0; }
  9983.         #calibratearea #calibrationinfo { clear: both; text-align: center; color: #3398cc; padding: 10px 0;}
  9984.         #backarea .backsvg { width: 1010px; height: 331px; border: 0; margin: 0; padding: 0; left: 0; }
  9985.  
  9986.         #printeradjust { color: #3398cc; font-size: 12px; }
  9987.         #printeradjust span { background-color: #3398cc; padding: 2px 3px; border: 1px solid #000000; font-family: "Courier New", Courier, monospace; font-weight: bold; font-size: 12px;}
  9988.         #printeradjust a:hover span { background-color: #CCFFCC; }
  9989.         #printeradjust a, #printeradjust a:hover {text-decoration: none;}
  9990.         #printeradjust input { text-align: center; margin: 0 2px;}
  9991.        
  9992.        
  9993.         #paperarea { min-height: 120px; display: none; }
  9994.         #paperarea .keyarea { border: 2px solid #000000; border-top: 0; }
  9995.        
  9996.         /* alphanum for public-private keys*/
  9997.         #paperarea .keyarea.art { display: block; height: auto; border: 0; font-family: ubuntu_mono_bold, Arial, Helvetica, sans-serif; padding: 0; margin: 0; font-size: 13px;}
  9998.        
  9999.         #paperarea .artwallet .papersvg { width: 1010px; height: 331px; border: 0; margin: 0; padding: 0; left: 0; }
  10000.         #paperarea .artwallet .qrcode_public { top: 120px; left: 41px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
  10001.                                                padding: 5px 5px 2px 5px; }
  10002.         #paperarea .artwallet .qrcode_private { top: 105px; left: 827px; z-index: 100; margin: 0; float: none; display: block; position: absolute; background-color: #FFFFFF;
  10003.                                                 padding: 5px 5px 2px 5px; }
  10004.         .btcaddress
  10005.         {
  10006.             clear: both;
  10007.         }
  10008.         .btcprivwif
  10009.         {
  10010.             clear: both;
  10011.             float: right;
  10012.         }
  10013.  
  10014.         #paperarea .artwallet .btcaddress  
  10015.         {
  10016.             position: absolute; top: 275px; left: 40px; z-index: 100; background-color: transparent;
  10017.             color: #3398cc; margin: 0;
  10018.                 -webkit-transform-origin:top left;
  10019.                 /* -webkit-transform:rotate(-90deg); */
  10020.                 -moz-transform-origin:top left;    
  10021.                 /*-moz-transform:rotate(-90deg); */
  10022.                 -ms-transform-origin:top left;    
  10023.                 /*-ms-transform:rotate(-90deg);*/
  10024.                 -o-transform-origin:top left;      
  10025.                 /*-o-transform:rotate(-90deg);*/
  10026.                 transform-origin:top left;        
  10027.                 /*transform:rotate(-90deg);*/
  10028.         }
  10029.  
  10030.         #paperarea .artwallet .dupbtcaddress  
  10031.         {
  10032.             position: absolute; top: 45px; left: 40px; z-index: 100; background-color: transparent;
  10033.             color: #3398cc; margin: 0;
  10034.                 /* -webkit-transform-origin:top left; */
  10035.                 -webkit-transform:rotate(-180deg);
  10036.                 /* -moz-transform-origin:top left; */  
  10037.                 -moz-transform:rotate(-180deg);
  10038.                 /* -ms-transform-origin:top left; */    
  10039.                 -ms-transform:rotate(-180deg);
  10040.                 /* -o-transform-origin:top left; */    
  10041.                 -o-transform:rotate(-180deg);
  10042.                 /* transform-origin:top left; */        
  10043.                 transform:rotate(-180deg);
  10044.         }
  10045.  
  10046.         #paperarea .artwallet .btcprivwif, #paperarea .artwallet .btcencryptedkey  
  10047.         {
  10048.             position: absolute; top: 245px; left: 610px; z-index: 100; background-color: transparent;
  10049.             color: #000000; margin: 0;  
  10050.                 -webkit-transform-origin:top left;
  10051.                 /*-webkit-transform:rotate(-90deg);*/
  10052.                 -moz-transform-origin:top left;    
  10053.                 /*-moz-transform:rotate(-90deg);*/
  10054.                 -ms-transform-origin:top left;    
  10055.                 /*-ms-transform:rotate(-90deg);*/
  10056.                 -o-transform-origin:top left;      
  10057.                 /*-o-transform:rotate(-90deg);*/
  10058.                 transform-origin:top left;        
  10059.                 /*transform:rotate(-90deg);*/
  10060.         }
  10061.  
  10062.         #paperarea .artwallet .dupbtcprivwif, #paperarea .artwallet .dupbtcencryptedkey
  10063.         {
  10064.             position: absolute; top: 75px; left: 610px; z-index: 100; background-color: transparent;
  10065.             color: #000000; margin: 0;  
  10066.                 /* -webkit-transform-origin:top left; */
  10067.                 -webkit-transform:rotate(-180deg);
  10068.                 /* -moz-transform-origin:top left; */  
  10069.                 -moz-transform:rotate(-180deg);
  10070.                 /* -ms-transform-origin:top left; */    
  10071.                 -ms-transform:rotate(-180deg);
  10072.                 /* -o-transform-origin:top left; */      
  10073.                 -o-transform:rotate(-180deg);
  10074.                 /* transform-origin:top left; */    
  10075.                 transform:rotate(-180deg);
  10076.         }
  10077.        
  10078.         #paperarea .artwallet .btcencryptedkey, #paperarea .artwallet .dupbtcencryptedkey
  10079.         {
  10080.             font-size: 12px;
  10081.         }
  10082.  
  10083.         #paperarea .artwallet .wallettype
  10084.         {
  10085.             position: absolute; top: 160px; left: 732px; z-index: 100; background-color: transparent;
  10086.             color: #000000; margin: 0; font-size: 11px;
  10087.                 /* -webkit-transform-origin:top left; */
  10088.                 -webkit-transform:rotate(90deg);
  10089.                 /* -moz-transform-origin:top left; */  
  10090.                 -moz-transform:rotate(90deg);
  10091.                 /* -ms-transform-origin:top left; */    
  10092.                 -ms-transform:rotate(90deg);
  10093.                 /* -o-transform-origin:top left; */      
  10094.                 -o-transform:rotate(90deg);
  10095.                 /* transform-origin:top left; */    
  10096.                 transform:rotate(90deg);
  10097.         }
  10098.  
  10099.         .nicerButton { /* thanks http://www.cssbuttongenerator.com */
  10100.             -moz-box-shadow:inset 0px 1px 0px 0px #000000;
  10101.             -webkit-box-shadow:inset 0px 1px 0px 0px #000000;
  10102.             box-shadow:inset 0px 1px 0px 0px #000000;
  10103.             background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #3398cc), color-stop(1, #3398cc) );
  10104.             background:-moz-linear-gradient( center top, #3398cc 5%, #3398cc 100% );
  10105.             filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#3398cc', endColorstr='#3398cc');
  10106.             background-color:#3398cc;
  10107.             -webkit-border-top-left-radius:12px;
  10108.             -moz-border-radius-topleft:12px;
  10109.             border-top-left-radius:12px;
  10110.             -webkit-border-top-right-radius:12px;
  10111.             -moz-border-radius-topright:12px;
  10112.             border-top-right-radius:12px;
  10113.             -webkit-border-bottom-right-radius:12px;
  10114.             -moz-border-radius-bottomright:12px;
  10115.             border-bottom-right-radius:12px;
  10116.             -webkit-border-bottom-left-radius:12px;
  10117.             -moz-border-radius-bottomleft:12px;
  10118.             border-bottom-left-radius:12px;
  10119.             text-indent:0;
  10120.             border:1px solid #000000;
  10121.             display:inline-block;
  10122.             color:#ffffff !important;
  10123.             font-family:Arial;
  10124.             font-size:14px;
  10125.             font-weight:bold;
  10126.             font-style:normal;
  10127.             height:35px;
  10128.             line-height:35px;
  10129.             width:189px;
  10130.             text-decoration:none;
  10131.             text-align:center;
  10132.             text-shadow:1px 1px 0px #000000;
  10133.         }
  10134.         .nicerButton:hover {
  10135.           background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #3398cc), color-stop(1, #3398cc) );
  10136.           background:-moz-linear-gradient( center top, #3398cc 5%, #3398cc 100% );
  10137.           filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#3398cc', endColorstr='#3398cc');
  10138.           background-color:#3398cc;
  10139.           text-decoration: none;
  10140.         }.nicerButton:active {
  10141.             position:relative;
  10142.             top:1px;
  10143.         }
  10144.  
  10145.         .instructionsarea { padding: 0 25px; }
  10146.         .instructionsarea { font-size: 12px; line-height: 18px; }
  10147.         .instructionsarea li { padding-bottom: 8px; list-style: none; }
  10148.        
  10149.         .highlighted { font-size: 14px; padding: 8px; background-color: #3398cc;}
  10150.        
  10151.         #browserinfo { text-align: center; }
  10152.         .englishjson { text-align: center; padding: 40px 0 20px 0; }
  10153.         .unittests { text-align: center; }
  10154.         .unittests div { width: 894px; font-family: monospace; text-align: left; margin: auto; padding: 5px; border: 1px solid black; }
  10155.        
  10156.         .background { background: #3398cc no-repeat center; opacity: 0.4; position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
  10157.         /*#busyblock, #busyblock_decrypt, #paperbip38settings, #paperqrscanner { position: absolute; display: none; width: 100%; height: 100%; top: 0; left: 0; z-index: 5000; vertical-aligh: middle; }*/
  10158.         #paperbip38settings, #paperqrscanner { position: absolute; display: none; width: 100%; height: 100%; top: 0; left: 0; z-index: 5000; vertical-aligh: middle; }
  10159.         #busyblock, #busyblock_decrypt { display: none; text-align: center;}
  10160.         #busyblock.busy, #busyblock_decrypt.busy, #paperbip38settings.show, #paperqrscanner.show { display: block; }
  10161.         .dialog {
  10162.             z-index: 6000;
  10163.             position: relative;
  10164.             background: white;
  10165.             border: 2px solid #3398cc;
  10166.             width: 600px;
  10167.             margin: 150px auto;
  10168.             padding: 1em;
  10169.         }
  10170.         .dialog-narrow {
  10171.             width: 300px;
  10172.         }
  10173.         .hide { display: none; }
  10174.         .show { display: block; }
  10175.        
  10176.         input { font-size: 12px; }
  10177.  
  10178.         /* IE8 */
  10179.         .qrcodetable { border-width: 0px; border-style: none; border-color: #3398cc; border-collapse: collapse; }
  10180.         .qrcodetddark { border-width: 0px; border-style: none; border-color: #3398cc; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #000000; }
  10181.         .qrcodetdlight { border-width: 0px; border-style: none; border-color: #3398cc; border-collapse: collapse; padding: 0; margin: 0; width: 2px; height: 2px; background-color: #ffffff; }
  10182.  
  10183.  
  10184.         @-webkit-keyframes blink { /* Like it's the 1990's again! Thanks https://github.com/madrobby/blink */
  10185.           0%     { opacity: .4 } 50% { opacity: .7 }
  10186.           50.01% { opacity: 1 } 100% { opacity: 1 }
  10187.         }
  10188.         blink {
  10189.           -webkit-animation: blink 0.6s infinite linear alternate;
  10190.           -webkit-font-smoothing: antialiased;
  10191.         }
  10192.  
  10193.         #detailarea span.qrinput {
  10194.             position: relative;
  10195.             padding: 0;
  10196.         }
  10197.         #detailarea span.qrinput span {
  10198.             position: absolute;
  10199.             display: block;
  10200.             top: 0px;
  10201.             right: 5px;
  10202.             width: 16px;
  10203.             height: 16px;
  10204.             background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAZdJREFUOE89kVmKAmEMhHMJcUBfVFAR3PcFbdt93xE8jHhpxb3nc4oxD0UlqUryd9vpdNrtdvv9frPZbLfb+XzueR78cDi8Xq/lcimu1vF4tPV6/Xw+6aEjSN/v93g8hlMkhZzP57+mx1xjwPV6haGjxBgIO5nNoNVq9Xg8SBeLBelkMrHBYIAOEUFJJxH0wOl0qhQbiNiwwlCD3CAFqeqycYKQtTYcDmezWb/fh9DGgE1vIFjY6/UwM5vWaDSy73NF7vc7SAMFlW+X0FXWarWYAXNdF53jOHpVt9sFO52OWpzAC1liJGq0221xRkinWSAcNQLQ9FwYeLlcQKJcLstMl52lUomF8EajYZVKpVarNZvNer0OJpNJeSh+sVgsiiD+GGA86Ha7ScG2dDoNZzD1bDYLJ3K5HGiJRIJPUSgUVGUYq6vVajwex8ZtpBDZ8BgKDDB9wUwmg4LDqOTz+VQqJR0GNn8MoVCIEmq9OxqNgkQsFsMJCYfDkUgEVN34u36//+c/4FQhjAgGgz6fDxIIBKhQd133F0QNzDPqO/1fAAAAAElFTkSuQmCC); /* this is the QR code icon on the 'verify' tab */
  10205.             cursor: pointer;
  10206.             padding: 0;
  10207.         }
  10208.         #detailarea span.qrinput input {
  10209.             padding: 5px 20px 5px 5px;
  10210.             width: 420px;
  10211.         }
  10212.         #detailkeyarea { padding: 10px; }
  10213.         #detailarea { margin: 0; text-align: left; }
  10214.         #detailarea .notes { text-align: left; padding: 0 0 20px 0; }
  10215.         #detailarea .pubqr .item .label { text-decoration: none; }
  10216.         #detailarea .pubqr .item { float: left; margin: 10px 0; position: relative; }
  10217.         #detailarea .pubqr .item.right { float: right; position: relative; top: 0; }
  10218.         #detailarea .privqr .item .label { text-decoration: none; }
  10219.         #detailarea .privqr .item { float: left; margin: 0; position: relative; }
  10220.         #detailarea .privqr .item.right { float: right; position: relative; }
  10221.         #detailarea .item { margin: 10px 0; position: relative; font-size: 90%; padding: 1px 0; }
  10222.         #detailarea .item.clear { clear: both; padding-top: 10px; }
  10223.         #detailarea .label { display: block; font-weight: bold; }
  10224.         #detailarea .output { display: block; font-family: monospace; font-size: 1.25em; }
  10225.         #detailarea #detailqrcodepublic { position: relative; float: left; margin: 0 10px 0 0; padding: 13px 11px 11px 11px; }
  10226.         #detailarea #detailqrcodepubliccomp { position: relative; float: right; margin: 0 0 0 10px; padding: 13px 11px 11px 11px; }
  10227.         #detailarea #detailqrcodeprivate { position: relative; float: left; margin: 0 10px 0 0; padding: 13px 11px 11px 11px; }
  10228.         #detailarea #detailqrcodeprivatecomp { position: relative; float: right; margin: 0 0 0 10px; padding: 13px 11px 11px 11px; }
  10229.         #detailpubkey { width: 590px; }
  10230.         #detailbip38commands { display: none; padding-top: 5px; }  
  10231.         .answer { padding: 0 15px 10px 25px; text-align: left; display: none; font-size: 80%; }
  10232.        
  10233.         #paperencryptstatus { margin-top: 5px; font-size: 12px; line-height: 20px; }
  10234.            
  10235.         #paperencryptpassphrase {
  10236.             background-color: #3398cc;
  10237.             color: #3398cc;
  10238.             font-weight: bold;
  10239.             padding: 5px 0;
  10240.             font-size: 12px;
  10241.             margin: 4px;
  10242.         }
  10243.  
  10244.         #suppliedPrivateKey {
  10245.             width: 420px;
  10246.             font-size: 11px;
  10247.         }
  10248.  
  10249.         @media screen  
  10250.         {
  10251.             #tagline { font-style: italic; font-size: 18px; color: #3398cc; }
  10252.             #tagline span {padding-left: 10px; font-size: 11px; color: #3398cc;}
  10253.             #tagsite { margin: 5px 0 20px 252px; font-size: 14px; color: #3398cc; }
  10254.            
  10255.  
  10256.             #tagwarning { position: absolute; left: 250px; top: 25px; font-size: 12px; color: red; }
  10257.             .menu { text-align: left; }
  10258.             .menu .tab { border-top-left-radius: 5px; border-top-right-radius: 5px; display: inline-block; background-color: #ffffff;
  10259.                          color: #3398cc; font-size: 12px;
  10260.                          border-top: 2px solid #3398cc;
  10261.                          border-left: 2px solid #3398cc;
  10262.                          border-right: 2px solid #3398cc;
  10263.                          border-bottom: 2px solid #3398cc;
  10264.                          padding: 4px 8px; margin: 0 2px 0 0; position: relative; top: 2px; z-index: 110; cursor: pointer; }
  10265.             .menu .tab:hover { color: #3398cc; }
  10266.             .menu .tab.selected { background-color: #FFFFFF; border-bottom: 4px solid #FFF; cursor: default; font-weight: bold; }
  10267.             .menu .tab.selected:hover { color: #3398cc; }
  10268.            
  10269.             .menu #printeradjust { float: right; text-align: right; margin-top: 5px; } /* zoom & shift */
  10270.            
  10271.             .pagebreak { height: 50px; }
  10272.             .commands { padding: 10px 0 20px 10px; margin-bottom: 0;}
  10273.             .commands span { padding: 0 10px; }
  10274.             .commands span.print { float: right; padding-top: 10px;}
  10275.             .commands span.right { float: right; }
  10276.             .expandable { padding: 10px 15px; text-align: left; cursor: pointer; }
  10277.            
  10278.             .commands p.instructions { width: 700px; float: left; font-size: 13px; }
  10279.            
  10280.             #detailcommands { padding: 10px 0; }
  10281.             #detailcommands span { padding: 0 10px; }
  10282.             #detailprivkey { width: 250px; }
  10283.             #detailprivkeypassphrase { width: 250px; }
  10284.             #detailkeyareakey { display: block; margin-top: 10px; color: #3398cc;}
  10285.  
  10286.  
  10287.             #bulkstartindex, #paperlimit, #paperlimitperpage { width: 35px; }
  10288.             #bulklimit { width: 45px; }
  10289.            
  10290.             .footer { font-family: Arial; font-size: 90%; clear: both; padding: 10px 0 10px 0; margin: 50px 20px; color: #999; }
  10291.             .footer div span.item { padding: 5px; }
  10292.             .footer .authorbtc { margin: auto; width: 600px; border-top: 1px dotted #999;}
  10293.             .footer .authorbtc span.item { text-align: left; display: block; padding-right: 20px; }
  10294.             .footer .authorbtc div { position: relative; z-index: 100; }
  10295.             .footer .authorpgp { position: relative; }
  10296.             .footer .authorpgp span.item { text-align: right; display: block; padding-bottom: 5px; }
  10297.             .footer .copyright { font-size: 90%; clear: both; padding: 5px 0; }
  10298.             .footer .copyright span { padding: 10px 0; }
  10299.  
  10300.             #siginfo, #selfinfo { margin: 10px 100px; border: 1px solid #FF9705; padding: 15px; background-color: #FFFFF6; color: #333; z-index: 10000; font-size: 12px;}
  10301.            
  10302.             #supplyKeys { float: left; background-color: #3398cc; border: 1px solid #CCCCCC; padding: 8px; }
  10303.             #wallets { margin: auto; width: 600px;}
  10304.         }      
  10305.  
  10306.         @media print
  10307.         {
  10308.             #wallets .walletarea { border-top: none; }
  10309.             body { width: 1000px; padding: 30px; background-image: none; background-color: #FFFFFF;}
  10310.             #main { width: auto; position: absolute; left: 25px;}
  10311.             #culturemenu { display: none; }
  10312.             .pagebreak { height: 1px; }
  10313.             #logoback { display: none; }
  10314.             .menu { display: none; }
  10315.             .footer { display: none; }
  10316.             .commands { display: none; }
  10317.             #tagline { display: none; }
  10318.             #faqs { display: none; }
  10319.             #seedpoolarea { display: none; }
  10320.             #detailprivwif { width: 285px; word-wrap: break-word; }
  10321.             #detailprivwifcomp { width: 310px; word-wrap: break-word; text-align: right; }
  10322.             #detailarea .privqr .item.right { width: 310px; }
  10323.             #detailarea .privqr .item { width: 285px; }
  10324.             #detailarea .notes { display: none; }
  10325.             .faq { display: none; }
  10326.         }
  10327.     </style>
  10328.    
  10329. <style type="text/css"></style></head>
  10330. <body onclick="SecureRandom.seedTime();" onmousemove="ninja.seeder.seed(event);" ontouchmove="ninja.seeder.seed(event);" onload="setDesign(ninja.getQueryString()['design'], true); /*guessPrinterSettings();*/ ">
  10331.    
  10332.             <div id="tagline"><center><img src="https://www.darkcoin.io/wp-content/uploads/2014/09/darkcoin_logo_l.png" height="110"><br><br><br>Open Source JavaScript Darkcoin Brain Wallet Generator</center><span></span><center><font size="1"><font color="000000">Download this .html file, disconnect from internet, generate wallet.</font><br>
  10333. For more info, visit <a href="https://darkcoin.io">darkcoin.io</a></font>
  10334.  
  10335.                      
  10336.                
  10337.                
  10338.            
  10339.                
  10340.             </center></div>
  10341.        
  10342.  
  10343.         <div id="wallets">
  10344.        
  10345.             <div id="landarea" class="walletarea" style="display: block;"> 
  10346.                
  10347.                 <div class="instructionsarea">
  10348.                
  10349.                        
  10350.  
  10351.                     <div id="keyButtons" style="display: none; float: left;">
  10352.  
  10353.                     <center><input type="button" id="papergenerate" value="BRAIN WALLET - Supply my own passphrase" onclick="ninja.wallets.paperwallet.toggleVanityField(true);">
  10354.                     </center></div>
  10355.  
  10356.  
  10357.  
  10358.  
  10359.  
  10360.  
  10361.  
  10362.                 <div id="selfinfo" style="display: none; position: absolute; top: 15px;">
  10363.  
  10364.                    <b>You can make a so-called "brain wallet" by supplying a VERY secure passphrase like '1852 Adobe Cloud SMASH fuzzy steamzonk'. <em>Be extremely careful doing this because a wallet generated using an insecure passphrase is virtually guaranteed to have its balance stolen within minutes of receiving funds!</em>.
  10365.                    <br>
  10366.                    <br>The resulting paper wallet will still have an ordinary crypto-looking private key and public address, but you will <em>also</em> be able to retrieve your wallet contents by entering your passphrase into the 'verify' tab of this service or a similar service such as <a href="https://brainwallet.org" target="_blank">brainwallet.org</a>.<br><br>
  10367.                     <strong>Note:</strong> supplying a brain wallet passphrase is different from BIP38-encrypting your wallet with a passphrase.
  10368.                    <br>
  10369.                    <br>
  10370.                    <a href="#" class="nicerButton" onclick="document.getElementById('selfinfo').style.display='none'; return(false);">OK</a>
  10371.                 </b></div><b>
  10372.                    
  10373.                     <div id="supplyKeys">
  10374.                     <p style="padding: 0; margin: 0;"><input placeholder="Enter secret passphrase - do NOT forget it!" autocomplete="off" id="suppliedPrivateKey" name="suppliedPrivateKey" spellcheck="false" style="font-family: ubuntu_mono_bold, 'Courier New', Courier, monospace;">&nbsp;<input type="button" id="papergenerate" value="Generate Keys »" onclick="testAndApplyVanityKey();">
  10375.                     </p>
  10376.                     <p style="margin: 10px 0 0 0; padding:0; font-size: 12px">
  10377.                     <a href="#" onclick="ninja.wallets.paperwallet.toggleVanityField(false);">« Back</a>
  10378.                     |
  10379.                     <a href="#" onclick="document.getElementById('selfinfo').style.display='block'; return(false);"><strong>HELP!</strong> (Explain how to use this feature.)</a>
  10380.                     </p>
  10381.                     </div>
  10382.  
  10383.                     <div id="paperadvancedcommands" class="row extra" style="float: left">
  10384.                         <span><label id="paperlabelencrypt" for="paperencrypt">BIP38 Encrypt?</label> <input type="checkbox" id="paperencrypt" onchange="ninja.wallets.paperwallet.toggleEncryptSettings(this.checked);"></span><br>
  10385.                         <div id="paperencryptstatus" class="hide">
  10386.                             <span><span id="paperencryptpassphrase"></span></span><br>
  10387.                             <div style="text-align: center;"><a onclick="ninja.wallets.paperwallet.toggleEncryptSettings(true);">Change passphrase</a></div>
  10388.                         </div>
  10389.                     </div>
  10390.                    
  10391.                     <div id="paperbip38settings">
  10392.                         <div class="background"></div>
  10393.                         <div class="dialog instructionsarea">
  10394.                             <p style="float: right;"><a href="https://bitcoinpaperwallet.com/wallet-tutorial-add-withdraw-funds/" target="_blank">Help / Instructions »</a></p>
  10395.                             <h2>About "BIP38" Encryption</h2>
  10396.                             <p>
  10397.                                 The advantage to encrypting your paper wallet is that if your paper wallet is stolen or otherwise exposed, the balance on the wallet is safe unless the passphrase used to encrypt the wallet is guessed. However, if you encrypt your private key with BIP38 and you lose your passphrase, it will be impossible for you to recover the funds you have sent to this wallet.</p>
  10398.                             <p>Also, note that not many <script type="text/javascript">document.write(window.currencyName);</script>Darkcoin wallet applications or web services are able to import BIP38 private keys. In this case, you will have to use the "Validate" feature on this webpage to extract the unencrypted Wallet Import Format (WIF) key as an intermediate step before sweeping the balance.</p>
  10399.                            
  10400.                             <p style="color: red;">WARNING: Before sending any funds to a BIP38-encrypted wallet, first do a test make sure you are able to decrypt the printed private key back to ordinary WIF format.</p>
  10401.                             <p>In short, if you do not have a strong understanding of the BIP38 encryption and decryption workflow, <strong>click cancel</strong>, print your paper wallet out without encryption, and keep it safe the same way you would jewels or cash.
  10402.                             </p>
  10403.                             <p>
  10404.                                 <button id="paperbip38activate" disabled="" onclick="ninja.wallets.paperwallet.toggleEncryptSettings(false);">TURN ON BIP38 ENCRYPTION</button>
  10405.                                 <label id="paperlabelBIPpassphrase" for="paperpassphrase"><strong>using passphrase:</strong></label>
  10406.                                 <input type="text" id="paperpassphrase" autocomplete="off" onkeyup="document.getElementById('paperbip38activate').disabled = this.value.length < 3">
  10407.                             </p>
  10408.                             <p><button onclick="ninja.wallets.paperwallet.toggleEncryptSettings(false, true);">CANCEL</button></p>
  10409.                         </div>
  10410.                     </div>
  10411.                    
  10412.                     <br clear="all">
  10413.                 </b></div><b>
  10414.                 <div id="busyblock">Working.....</div>
  10415.                 <div id="paperkeyarea"></div>
  10416.             </b></div><!-- end paperarea --><b>
  10417.            
  10418.  
  10419.  
  10420.  
  10421.  
  10422.             <div id="backarea" class="walletarea">
  10423.                 <div class="commands">
  10424.                     <div id="backcommands">
  10425.                         <p id="backinstructions" class="instructions highlighted"><strong>Reload the front page into your printer first.</strong> Note: The back design is intentionally larger than the front side. (Use the front side as your guide when cutting to trim off the excess.)</p>
  10426.                         <span class="print">
  10427.                         <a href="#" class="nicerButton" onclick="doPrint();">Print Wallet Back</a>
  10428.                         </span>
  10429.                     </div>
  10430.                     <br clear="all">
  10431.                 </div>
  10432.                
  10433.                 <img id="backsvg1" class="backsvg" src="./images/back-300dpi.jpg">
  10434.                
  10435.             </div><!-- end backarea -->
  10436.  
  10437.  
  10438.  
  10439.             <div id="foldarea" class="walletarea"> 
  10440.                 <div id="foldcommands" class="commands">
  10441.                     &nbsp;
  10442.                 </div>
  10443.                 <div class="instructionsarea">
  10444.                       <h1><span id="instructions21">How to cut &amp; fold your 2-sided wallet:</span></h1>
  10445.                     <div class="notes">
  10446.  
  10447.                         <div style="float: right; margin: 0 0 20px 30px; padding-left: 30px; border-left: 4px solid #3398cc;">
  10448.                          <!-- <img src="images/finished-folds.png" width="355" height="144" alt="Folding Diagram"><br><br>
  10449.                         <img src="images/finished-sample.jpg" width="400" height="203" alt="Sample Wallet"><br><br>
  10450.                         <img src="images/finished-sample-sealed.jpg" width="400" height="203" alt="Sealed Wallet"> -->
  10451.                         </div>
  10452.  
  10453.                         <span id="instructions22">Cut out your wallet <em>using the dotted lines on the front as a guide, not the back!</em>
  10454.                        
  10455.                         Note that the design on the back side is intentionally larger than the front side so that back design will "bleed" to the edges even if your front and back sides are misaligned up to 1cm.
  10456.                         <br><br>
  10457.                         Now fold the more narrow private key area in half, and then over again as indicated by the dotted lines in this diagram. The unusual "butterfly" shape can be a bit of a pain to cut out, but it's essential to keep your private key safe.</span>
  10458.                         <br>
  10459.                         <br>
  10460.                         <span id="instructions23">The final wallet will be a rectangle shape with the more narrow private key area folded over it.</span>
  10461.                         <br>
  10462.                                                
  10463.                         <br>
  10464.                         <span id="instructions13">Seal your wallet by placing two strips of sturdy <strong>light-blocking</strong> tape over the top and bottom edges of the private (folded) area. A zip-seal bag will keep it safe from moisture (especially important for inkjet prints.)</span>
  10465.                         <br><br>   
  10466.                         <a href="#" onclick="window.open(window.suppliesURL, '_blank'); return false;" class="nicerButton" style="width: 400px;">Purchase hologram stickers and/or zip-sealing bags »</a> 
  10467.  
  10468.                         <br><br>   
  10469.  
  10470.                         <h1><span id="instructions16">How to add funds to your wallet:</span></h1>
  10471.  
  10472.                         <span id="instructions17">Send <script type="text/javascript">document.write(window.currencyName);</script>Darkcoins to the address (or QR code) where your wallet says "PUBLIC ADDRESS".</span>
  10473.                         <br><br>   
  10474.                        
  10475.                         <h1><span id="instructions18">How to withdraw funds from your wallet:</span></h1>
  10476.  
  10477.                         <span id="instructions19">You should expect to withdraw the entire balance of the wallet by importing it (or "sweeping" it) to a live wallet, e.g. a Bitcoin wallet application or online service like blockchain.info or coinbase.com.
  10478.                         <br>
  10479.                         <br>
  10480.                         <strong>If you elected to BIP38-encrypt your wallet</strong>, you may need to recover your unencrypted WIF "Wallet Import Format" private key by using the "validate" tab on this web page.
  10481.                         <br>
  10482.                         <br><a href="https://bitcoinpaperwallet.com/wallet-tutorial-add-withdraw-funds/" target="_blank">Visit BitcoinPaperWallet.com for detailed information on adding to and spending from a paper wallet »</a></span>
  10483.                        
  10484.                     </div>
  10485.                 </div>
  10486.             </div><!-- end landarea -->
  10487.  
  10488.             <div id="detailarea" class="walletarea">
  10489.  
  10490.                 <div id="detailcommands" class="commands">
  10491.                 &nbsp;
  10492.                 </div>
  10493.             <div class="instructionsarea"> 
  10494.                     <h1>Validate or decrypt private key</h1>
  10495.                     <div style="width: 45%; float: left; padding: 0 15px; border-right: 3px solid #ccc;">
  10496.                         <p>Enter or <a onclick="ninja.wallets.detailwallet.qrscanner.start()">scan</a> any private key into this form to display all available details in various formats. If your private key decodes properly, then you have verified that you should be able to retrieve any funds sent to that wallet. This should work for private keys generated by BitcoinPaperWallet.com as well as any other Bitcoin service.</p>
  10497.                         <p>For example, if you have a wallet encrypted with a BIP38 passphrase, you can use this form to decrypt your private key and retrieve the standard Wallet Import Format (WIF) key suitable for wallet software and services that don't directly support BIP38 importing.</p>
  10498.                         <p>You may also enter a passphrase (or "brain wallet") to see the corresponding SHA256 hashed keys.</p>
  10499.                     </div>
  10500.                     <div style="width: 45%; float: left; padding: 0 15px;">
  10501.                         <span class="qrinput">
  10502.                             <input type="text" id="detailprivkey" value="" placeholder="Enter a private key, or click the QR icon to scan" autocomplete="off" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();">
  10503.                             <span onclick="ninja.wallets.detailwallet.qrscanner.start()"></span>
  10504.                         </span>
  10505.                         <div id="paperqrscanner">
  10506.                             <div class="background"></div>
  10507.                             <div id="mainbody" class="dialog instructionsarea">
  10508.                                 <p style="float: right;"><a href="https://bitcoinpaperwallet.com/how-to-scan-qr-codes-with-camera/" target="_blank" style="font-family: 'Lucida Console', Monaco, monospace;">Help / Instructions »</a></p>
  10509.                                 <h2>Scan QR code using your camera</h2>
  10510.                                 <div id="paperqrnotsupported" style="color: red" class="hide">Sorry, but your web browser does not support the HTML5 camera controls. Try using a recent version of Firefox (recommended), Chrome or Opera.</div>
  10511.                                 <div id="paperqrpermissiondenied" style="color: red" class="hide">
  10512.                                     <p>Permission denied. Your browser should display a message requesting access to your camera. Please click the "Allow" button to enable the camera.</p>
  10513.                                     <p>If you are using Chrome and you launched this generator by opening the HTML file from your own computer "locally", you may need to launch Chrome from the command line and specify the <a href="https://bitcoinpaperwallet.com/how-to-scan-qr-codes-with-camera/" target="_blank" style="font-family: 'Lucida Console', Monaco, monospace;">--allow-file-access-from-files</a> flag. Or you can set up a local web server (Apache) and run this generator via http://127.0.0.1... or, give up and just use Firefox.</p>
  10514.                                    
  10515.                                 </div>
  10516.                                 <div id="paperqrerror" style="color: red"></div>
  10517.                                 <div id="paperqroutput"></div>
  10518.                                 <button onclick="ninja.wallets.detailwallet.qrscanner.stop()">Cancel</button>
  10519.                             </div>
  10520.                         </div>
  10521.                         <br>
  10522.                         <span><input type="button" id="detailview" value="Validate / Decrypt" onclick="ninja.wallets.detailwallet.viewDetails();"></span>
  10523.                         <div class="row extra">
  10524.                             <span><label id="detailkeyformats">Supported formats: WIF, WIFC, HEX, B64, B6, MINI, BIP38, "Brain Wallet"</label></span>
  10525.                         </div>
  10526.                         <div id="detailbip38commands">
  10527.                             This "6P..." private key is BIP38-encrypted.<br>
  10528.                             <label id="detaillabelpassphrase">Please type in passphrase below:</label><br>
  10529.                             <span><input type="text" id="detailprivkeypassphrase" value="" onfocus="this.select();" onkeypress="if (event.keyCode == 13) ninja.wallets.detailwallet.viewDetails();"></span>
  10530.                             <span><input type="button" id="detaildecrypt" value="Decrypt BIP38" onclick="ninja.wallets.detailwallet.viewDetails();"></span>
  10531.                         </div>
  10532.                     </div>
  10533.                     <div style="clear: both;"></div>
  10534.  
  10535.                 <div id="detailkeyarea" class="hide">
  10536.                     <div class="notes">
  10537.                         <h1>Public and private details for:<br><span id="detailkeyareakey"></span></h1>
  10538.                         <p><button onclick="ninja.wallets.detailwallet.loadInPaperWallet()">Use these details to print a paper wallet</button></p>
  10539.                         <span id="detaillabelnote1">Use the <strong>Public Address</strong> to receive funds or check your balance online. The <strong>Private Key WIF</strong> is a code that needs to be keep secret since it can be used to spend any funds that have been sent to the corresponding public key. Keys can be encoded in a number of different formats. The most popular encoding formats (WIF, WIFC, HEX, B64) are shown below.</span>
  10540.                         <br>
  10541.                     </div>
  10542.                     <div class="pubqr">
  10543.                         <div class="item">
  10544.                             <span class="label" id="detaillabelbitcoinaddress"><strong style="font-size: 150%;">Public <script type="text/javascript">document.write(window.currencyName);</script>Darkcoin Address</strong></span>
  10545.                             <div id="detailqrcodepublic" class="qrcode_public"></div>
  10546.                             <span class="output" id="detailaddress"></span>
  10547.                         </div>                 
  10548.                         <div class="item right">
  10549.                             <span class="label" id="detaillabelbitcoinaddresscomp"><script type="text/javascript">document.write(window.currencyName);</script>Darkcoin Address Compressed Format</span>
  10550.                             <div id="detailqrcodepubliccomp" class="qrcode_public"></div>
  10551.                             <span class="output" id="detailaddresscomp"></span>
  10552.                         </div>
  10553.                     </div>
  10554.                     <br><br>
  10555.                     <div class="item clear">
  10556.                         <span class="label" id="detaillabelpublickey">Public Key (130 characters [0-9A-F]):</span>
  10557.                         <span class="output pubkeyhex" id="detailpubkey"></span>
  10558.                     </div>
  10559.                     <div class="item">
  10560.                         <span class="label" id="detaillabelpublickeycomp">Public Key (compressed, 66 characters [0-9A-F]):</span>
  10561.                         <span class="output" id="detailpubkeycomp"></span>
  10562.                     </div>
  10563.                     <hr>
  10564.                     <div class="privqr">
  10565.                         <div class="item">
  10566.                             <span class="label"><span id="detaillabelprivwif"><strong style="font-size: 150%;">Private Key WIF</strong><br>51 characters base58, starts with a</span> '<script type="text/javascript">document.write(window.window.WIFPrefix);</script>7'</span>
  10567.                             <div id="detailqrcodeprivate" class="qrcode_private"></div>
  10568.                             <span class="output" id="detailprivwif"></span>
  10569.                         </div>
  10570.                         <div class="item right">
  10571.                             <span class="label"><span id="detaillabelprivwifcomp">Private Key WIF Compressed<br>52 characters base58, starts with a</span> '<script type="text/javascript">document.write(window.compressedWIFPrefix);</script>X'</span>
  10572.                             <div id="detailqrcodeprivatecomp" class="qrcode_private"></div>
  10573.                             <span class="output" id="detailprivwifcomp"></span>
  10574.                         </div>
  10575.                     </div>
  10576.                     <br><br>
  10577.                     <div class="item clear">
  10578.                         <span class="label" id="detaillabelprivhex">Private Key Hexadecimal Format (64 characters [0-9A-F]):</span>
  10579.                         <span class="output" id="detailprivhex"></span>
  10580.                     </div>
  10581.                     <div class="item">
  10582.                         <span class="label" id="detaillabelprivb64">Private Key Base64 (44 characters):</span>
  10583.                         <span class="output" id="detailprivb64"></span>
  10584.                     </div>
  10585.                     <div class="item" style="display: none;" id="detailmini">
  10586.                         <span class="label" id="detaillabelprivmini">Private Key Mini Format (22, 26 or 30 characters, starts with an 'S'):</span>
  10587.                         <span class="output" id="detailprivmini"></span>
  10588.                     </div>
  10589.                     <div class="item" style="display: none;" id="detailb6">
  10590.                         <span class="label" id="detaillabelprivb6">Private Key Base6 Format (99 characters [0-5]):</span>
  10591.                         <span class="output" id="detailprivb6"></span>
  10592.                     </div>
  10593.                     <div class="item" style="display: none;" id="detailbip38">
  10594.                         <span class="label" id="detaillabelprivbip38">Private Key BIP38 Format (58 characters base58, starts with '6P'):</span>
  10595.                         <span class="output" id="detailprivbip38"></span>
  10596.                     </div>
  10597.                 </div>
  10598.                
  10599.             </div><!-- end instructionsarea -->
  10600.             </div><!-- end detailarea -->
  10601.            
  10602.            
  10603.         </b></div><!-- *** end wallets *** --><b>
  10604.  
  10605.         <div id="footer" class="footer">
  10606.             <div class="authorbtc">
  10607.                 <div>
  10608.                     <span class="item" id="footerlabeldonations"><b>
  10609.             </b></span></div><b>
  10610.             <div class="copyright">
  10611.                 <span id="footerlabelnowarranty"><strong><center><font size="1">This software and service is provided with no warranty. Use at your own risk.</font></center></strong></span>
  10612.  
  10613.             </div>
  10614.         </b></div><b>
  10615.     </b></div><b>
  10616.  
  10617. <script type="text/javascript">
  10618.  
  10619. // bitaddress.org code -- though significantly modified for this implementation.
  10620. // For the original modified version of this code see
  10621. // https://github.com/pointbiz/bitaddress.org
  10622.  
  10623. var ninja = { wallets: {} };
  10624.  
  10625. ninja.privateKey = {
  10626.     isPrivateKey: function (key) {
  10627.         return (
  10628.             Bitcoin.ECKey.isWalletImportFormat(key) ||
  10629.             Bitcoin.ECKey.isCompressedWalletImportFormat(key) ||
  10630.             Bitcoin.ECKey.isHexFormat(key) ||
  10631.             Bitcoin.ECKey.isBase64Format(key) ||
  10632.             Bitcoin.ECKey.isMiniFormat(key)
  10633.         );
  10634.     },
  10635.     getECKeyFromAdding: function (privKey1, privKey2) {
  10636.         var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
  10637.         var ecKey1 = new Bitcoin.ECKey(privKey1);
  10638.         var ecKey2 = new Bitcoin.ECKey(privKey2);
  10639.         // if both keys are the same return null
  10640.         if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
  10641.         if (ecKey1 == null || ecKey2 == null) return null;
  10642.         var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.add(ecKey2.priv).mod(n));
  10643.         // compressed when both keys are compressed
  10644.         if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
  10645.         return combinedPrivateKey;
  10646.     },
  10647.     getECKeyFromMultiplying: function (privKey1, privKey2) {
  10648.         var n = EllipticCurve.getSECCurveByName("secp256k1").getN();
  10649.         var ecKey1 = new Bitcoin.ECKey(privKey1);
  10650.         var ecKey2 = new Bitcoin.ECKey(privKey2);
  10651.         // if both keys are the same return null
  10652.         if (ecKey1.getBitcoinHexFormat() == ecKey2.getBitcoinHexFormat()) return null;
  10653.         if (ecKey1 == null || ecKey2 == null) return null;
  10654.         var combinedPrivateKey = new Bitcoin.ECKey(ecKey1.priv.multiply(ecKey2.priv).mod(n));
  10655.         // compressed when both keys are compressed
  10656.         if (ecKey1.compressed && ecKey2.compressed) combinedPrivateKey.setCompressed(true);
  10657.         return combinedPrivateKey;
  10658.     },
  10659.     // 58 base58 characters starting with 6P
  10660.     isBIP38Format: function (key) {
  10661.         key = key.toString();
  10662.         return (/^6P[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{56}$/.test(key));
  10663.     },
  10664.     BIP38EncryptedKeyToByteArrayAsync: function (base58Encrypted, passphrase, callback) {
  10665.         var hex;
  10666.         try {
  10667.             hex = Bitcoin.Base58.decode(base58Encrypted);
  10668.         } catch (e) {
  10669.             callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10670.             return;
  10671.         }
  10672.  
  10673.         // 43 bytes: 2 bytes prefix, 37 bytes payload, 4 bytes checksum
  10674.         if (hex.length != 43) {
  10675.             callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10676.             return;
  10677.         }
  10678.         // first byte is always 0x01
  10679.         else if (hex[0] != 0x01) {
  10680.             callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10681.             return;
  10682.         }
  10683.  
  10684.         var expChecksum = hex.slice(-4);
  10685.         hex = hex.slice(0, -4);
  10686.         var checksum = Bitcoin.Util.dsha256(hex);
  10687.         if (checksum[0] != expChecksum[0] || checksum[1] != expChecksum[1] || checksum[2] != expChecksum[2] || checksum[3] != expChecksum[3]) {
  10688.             callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10689.             return;
  10690.         }
  10691.  
  10692.         var isCompPoint = false;
  10693.         var isECMult = false;
  10694.         var hasLotSeq = false;
  10695.         // second byte for non-EC-multiplied key
  10696.         if (hex[1] == 0x42) {
  10697.             // key should use compression
  10698.             if (hex[2] == 0xe0) {
  10699.                 isCompPoint = true;
  10700.             }
  10701.             // key should NOT use compression
  10702.             else if (hex[2] != 0xc0) {
  10703.                 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10704.                 return;
  10705.             }
  10706.         }
  10707.         // second byte for EC-multiplied key
  10708.         else if (hex[1] == 0x43) {
  10709.             isECMult = true;
  10710.             isCompPoint = (hex[2] & 0x20) != 0;
  10711.             hasLotSeq = (hex[2] & 0x04) != 0;
  10712.             if ((hex[2] & 0x24) != hex[2]) {
  10713.                 callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10714.                 return;
  10715.             }
  10716.         }
  10717.         else {
  10718.             callback(new Error(ninja.translator.get("detailalertnotvalidprivatekey")));
  10719.             return;
  10720.         }
  10721.  
  10722.         var decrypted;
  10723.         var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
  10724.  
  10725.         var verifyHashAndReturn = function () {
  10726.             var tmpkey = new Bitcoin.ECKey(decrypted); // decrypted using closure
  10727.             var base58AddrText = tmpkey.setCompressed(isCompPoint).getBitcoinAddress(); // isCompPoint using closure
  10728.             checksum = Bitcoin.Util.dsha256(base58AddrText); // checksum using closure
  10729.  
  10730.             if (checksum[0] != hex[3] || checksum[1] != hex[4] || checksum[2] != hex[5] || checksum[3] != hex[6]) {
  10731.                 callback(new Error(ninja.translator.get("bip38alertincorrectpassphrase"))); // callback using closure
  10732.                 return;
  10733.             }
  10734.             callback(tmpkey.getBitcoinPrivateKeyByteArray()); // callback using closure
  10735.         };
  10736.  
  10737.         if (!isECMult) {
  10738.             var addresshash = hex.slice(3, 7);
  10739.             Crypto_scrypt(passphrase, addresshash, 16384, 8, 8, 64, function (derivedBytes) {
  10740.                 var k = derivedBytes.slice(32, 32 + 32);
  10741.                 decrypted = Crypto.AES.decrypt(hex.slice(7, 7 + 32), k, AES_opts);
  10742.                 for (var x = 0; x < 32; x++) decrypted[x] ^= derivedBytes[x];
  10743.                 verifyHashAndReturn(); //TODO: pass in 'decrypted' as a param
  10744.             });
  10745.         }
  10746.         else {
  10747.             var ownerentropy = hex.slice(7, 7 + 8);
  10748.             var ownersalt = !hasLotSeq ? ownerentropy : ownerentropy.slice(0, 4);
  10749.             Crypto_scrypt(passphrase, ownersalt, 16384, 8, 8, 32, function (prefactorA) {
  10750.                 var passfactor;
  10751.                 if (!hasLotSeq) { // hasLotSeq using closure
  10752.                     passfactor = prefactorA;
  10753.                 } else {
  10754.                     var prefactorB = prefactorA.concat(ownerentropy); // ownerentropy using closure
  10755.                     passfactor = Bitcoin.Util.dsha256(prefactorB);
  10756.                 }
  10757.                 var kp = new Bitcoin.ECKey(passfactor);
  10758.                 var passpoint = kp.setCompressed(true).getPub();
  10759.  
  10760.                 var encryptedpart2 = hex.slice(23, 23 + 16);
  10761.  
  10762.                 var addresshashplusownerentropy = hex.slice(3, 3 + 12);
  10763.                 Crypto_scrypt(passpoint, addresshashplusownerentropy, 1024, 1, 1, 64, function (derived) {
  10764.                     var k = derived.slice(32);
  10765.  
  10766.                     var unencryptedpart2 = Crypto.AES.decrypt(encryptedpart2, k, AES_opts);
  10767.                     for (var i = 0; i < 16; i++) { unencryptedpart2[i] ^= derived[i + 16]; }
  10768.  
  10769.                     var encryptedpart1 = hex.slice(15, 15 + 8).concat(unencryptedpart2.slice(0, 0 + 8));
  10770.                     var unencryptedpart1 = Crypto.AES.decrypt(encryptedpart1, k, AES_opts);
  10771.                     for (var i = 0; i < 16; i++) { unencryptedpart1[i] ^= derived[i]; }
  10772.  
  10773.                     var seedb = unencryptedpart1.slice(0, 0 + 16).concat(unencryptedpart2.slice(8, 8 + 8));
  10774.  
  10775.                     var factorb = Bitcoin.Util.dsha256(seedb);
  10776.  
  10777.                     var ps = EllipticCurve.getSECCurveByName("secp256k1");
  10778.                     var privateKey = BigInteger.fromByteArrayUnsigned(passfactor).multiply(BigInteger.fromByteArrayUnsigned(factorb)).remainder(ps.getN());
  10779.  
  10780.                     decrypted = privateKey.toByteArrayUnsigned();
  10781.                     verifyHashAndReturn();
  10782.                 });
  10783.             });
  10784.         }
  10785.     },
  10786.     BIP38PrivateKeyToEncryptedKeyAsync: function (base58Key, passphrase, compressed, callback) {
  10787.         var privKey = new Bitcoin.ECKey(base58Key);
  10788.         var privKeyBytes = privKey.getBitcoinPrivateKeyByteArray();
  10789.         var address = privKey.setCompressed(compressed).getBitcoinAddress();
  10790.  
  10791.         // compute sha256(sha256(address)) and take first 4 bytes
  10792.         var salt = Bitcoin.Util.dsha256(address).slice(0, 4);
  10793.  
  10794.         // derive key using scrypt
  10795.         var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
  10796.  
  10797.         Crypto_scrypt(passphrase, salt, 16384, 8, 8, 64, function (derivedBytes) {
  10798.             for (var i = 0; i < 32; ++i) {
  10799.                 privKeyBytes[i] ^= derivedBytes[i];
  10800.             }
  10801.  
  10802.             // 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2
  10803.             var flagByte = compressed ? 0xe0 : 0xc0;
  10804.             var encryptedKey = [0x01, 0x42, flagByte].concat(salt);
  10805.             encryptedKey = encryptedKey.concat(Crypto.AES.encrypt(privKeyBytes, derivedBytes.slice(32), AES_opts));
  10806.             encryptedKey = encryptedKey.concat(Bitcoin.Util.dsha256(encryptedKey).slice(0, 4));
  10807.             callback(Bitcoin.Base58.encode(encryptedKey));
  10808.         });
  10809.     },
  10810.     BIP38GenerateIntermediatePointAsync: function (passphrase, lotNum, sequenceNum, callback) {
  10811.         var noNumbers = lotNum === null || sequenceNum === null;
  10812.         var rng = new SecureRandom();
  10813.         var ownerEntropy, ownerSalt;
  10814.  
  10815.         if (noNumbers) {
  10816.             ownerSalt = ownerEntropy = new Array(8);
  10817.             rng.nextBytes(ownerEntropy);
  10818.         }
  10819.         else {
  10820.             // 1) generate 4 random bytes
  10821.             ownerSalt = new Array(4);
  10822.  
  10823.             rng.nextBytes(ownerSalt);
  10824.  
  10825.             // 2)  Encode the lot and sequence numbers as a 4 byte quantity (big-endian):
  10826.             // lotnumber * 4096 + sequencenumber. Call these four bytes lotsequence.
  10827.             var lotSequence = BigInteger(4096 * lotNum + sequenceNum).toByteArrayUnsigned();
  10828.  
  10829.             // 3) Concatenate ownersalt + lotsequence and call this ownerentropy.
  10830.             var ownerEntropy = ownerSalt.concat(lotSequence);
  10831.         }
  10832.  
  10833.  
  10834.         // 4) Derive a key from the passphrase using scrypt
  10835.         Crypto_scrypt(passphrase, ownerSalt, 16384, 8, 8, 32, function (prefactor) {
  10836.             // Take SHA256(SHA256(prefactor + ownerentropy)) and call this passfactor
  10837.             var passfactorBytes = noNumbers ? prefactor : Bitcoin.Util.dsha256(prefactor.concat(ownerEntropy));
  10838.             var passfactor = BigInteger.fromByteArrayUnsigned(passfactorBytes);
  10839.  
  10840.             // 5) Compute the elliptic curve point G * passfactor, and convert the result to compressed notation (33 bytes)
  10841.             var ellipticCurve = EllipticCurve.getSECCurveByName("secp256k1");
  10842.             var passpoint = ellipticCurve.getG().multiply(passfactor).getEncoded(1);
  10843.  
  10844.             // 6) Convey ownersalt and passpoint to the party generating the keys, along with a checksum to ensure integrity.
  10845.             // magic bytes "2C E9 B3 E1 FF 39 E2 51" followed by ownerentropy, and then passpoint
  10846.             var magicBytes = [0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2, 0x51];
  10847.             if (noNumbers) magicBytes[7] = 0x53;
  10848.  
  10849.             var intermediate = magicBytes.concat(ownerEntropy).concat(passpoint);
  10850.  
  10851.             // base58check encode
  10852.             intermediate = intermediate.concat(Bitcoin.Util.dsha256(intermediate).slice(0, 4));
  10853.             callback(Bitcoin.Base58.encode(intermediate));
  10854.         });
  10855.     },
  10856.     BIP38GenerateECAddressAsync: function (intermediate, compressed, callback) {
  10857.         // decode IPS
  10858.         var x = Bitcoin.Base58.decode(intermediate);
  10859.         //if(x.slice(49, 4) !== Bitcoin.Util.dsha256(x.slice(0,49)).slice(0,4)) {
  10860.         //  callback({error: 'Invalid intermediate passphrase string'});
  10861.         //}
  10862.         var noNumbers = (x[7] === 0x53);
  10863.         var ownerEntropy = x.slice(8, 8 + 8);
  10864.         var passpoint = x.slice(16, 16 + 33);
  10865.  
  10866.         // 1) Set flagbyte.
  10867.         // set bit 0x20 for compressed key
  10868.         // set bit 0x04 if ownerentropy contains a value for lotsequence
  10869.         var flagByte = (compressed ? 0x20 : 0x00) | (noNumbers ? 0x00 : 0x04);
  10870.  
  10871.  
  10872.         // 2) Generate 24 random bytes, call this seedb.
  10873.         var seedB = new Array(24);
  10874.         var rng = new SecureRandom();
  10875.         rng.nextBytes(seedB);
  10876.  
  10877.         // Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb.
  10878.         var factorB = Bitcoin.Util.dsha256(seedB);
  10879.  
  10880.         // 3) ECMultiply passpoint by factorb. Use the resulting EC point as a public key and hash it into a Bitcoin
  10881.         // address using either compressed or uncompressed public key methodology (specify which methodology is used
  10882.         // inside flagbyte). This is the generated Bitcoin address, call it generatedaddress.
  10883.         var ec = EllipticCurve.getSECCurveByName("secp256k1").getCurve();
  10884.         var generatedPoint = ec.decodePointHex(ninja.publicKey.getHexFromByteArray(passpoint));
  10885.         var generatedBytes = generatedPoint.multiply(BigInteger.fromByteArrayUnsigned(factorB)).getEncoded(compressed);
  10886.         var generatedAddress = (new Bitcoin.Address(Bitcoin.Util.sha256ripe160(generatedBytes))).toString();
  10887.  
  10888.         // 4) Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash.
  10889.         var addressHash = Bitcoin.Util.dsha256(generatedAddress).slice(0, 4);
  10890.  
  10891.         // 5) Now we will encrypt seedb. Derive a second key from passpoint using scrypt
  10892.         Crypto_scrypt(passpoint, addressHash.concat(ownerEntropy), 1024, 1, 1, 64, function (derivedBytes) {
  10893.             // 6) Do AES256Encrypt(seedb[0...15]] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1
  10894.             for (var i = 0; i < 16; ++i) {
  10895.                 seedB[i] ^= derivedBytes[i];
  10896.             }
  10897.             var AES_opts = { mode: new Crypto.mode.ECB(Crypto.pad.NoPadding), asBytes: true };
  10898.             var encryptedPart1 = Crypto.AES.encrypt(seedB.slice(0, 16), derivedBytes.slice(32), AES_opts);
  10899.  
  10900.             // 7) Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedseedb.
  10901.             var message2 = encryptedPart1.slice(8, 8 + 8).concat(seedB.slice(16, 16 + 8));
  10902.             for (var i = 0; i < 16; ++i) {
  10903.                 message2[i] ^= derivedBytes[i + 16];
  10904.             }
  10905.             var encryptedSeedB = Crypto.AES.encrypt(message2, derivedBytes.slice(32), AES_opts);
  10906.  
  10907.             // 0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2
  10908.             var encryptedKey = [0x01, 0x43, flagByte].concat(addressHash).concat(ownerEntropy).concat(encryptedPart1.slice(0, 8)).concat(encryptedSeedB);
  10909.  
  10910.             // base58check encode
  10911.             encryptedKey = encryptedKey.concat(Bitcoin.Util.dsha256(encryptedKey).slice(0, 4));
  10912.             callback(generatedAddress, Bitcoin.Base58.encode(encryptedKey));
  10913.         });
  10914.     }
  10915. };
  10916.  
  10917. ninja.publicKey = {
  10918.     isPublicKeyHexFormat: function (key) {
  10919.         key = key.toString();
  10920.         return ninja.publicKey.isUncompressedPublicKeyHexFormat(key) || ninja.publicKey.isCompressedPublicKeyHexFormat(key);
  10921.     },
  10922.     // 130 characters [0-9A-F] starts with 04
  10923.     isUncompressedPublicKeyHexFormat: function (key) {
  10924.         key = key.toString();
  10925.         return /^04[A-Fa-f0-9]{128}$/.test(key);
  10926.     },
  10927.     // 66 characters [0-9A-F] starts with 02 or 03
  10928.     isCompressedPublicKeyHexFormat: function (key) {
  10929.         key = key.toString();
  10930.         return /^0[2-3][A-Fa-f0-9]{64}$/.test(key);
  10931.     },
  10932.     getBitcoinAddressFromByteArray: function (pubKeyByteArray) {
  10933.         var pubKeyHash = Bitcoin.Util.sha256ripe160(pubKeyByteArray);
  10934.         var addr = new Bitcoin.Address(pubKeyHash);
  10935.         return addr.toString();
  10936.     },
  10937.     getHexFromByteArray: function (pubKeyByteArray) {
  10938.         return Crypto.util.bytesToHex(pubKeyByteArray).toString().toUpperCase();
  10939.     },
  10940.     getByteArrayFromAdding: function (pubKeyHex1, pubKeyHex2) {
  10941.         var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  10942.         var curve = ecparams.getCurve();
  10943.         var ecPoint1 = curve.decodePointHex(pubKeyHex1);
  10944.         var ecPoint2 = curve.decodePointHex(pubKeyHex2);
  10945.         // if both points are the same return null
  10946.         if (ecPoint1.equals(ecPoint2)) return null;
  10947.         var compressed = (ecPoint1.compressed && ecPoint2.compressed);
  10948.         var pubKey = ecPoint1.add(ecPoint2).getEncoded(compressed);
  10949.         return pubKey;
  10950.     },
  10951.     getByteArrayFromMultiplying: function (pubKeyHex, ecKey) {
  10952.         var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  10953.         var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHex);
  10954.         var compressed = (ecPoint.compressed && ecKey.compressed);
  10955.         // if both points are the same return null
  10956.         ecKey.setCompressed(false);
  10957.         if(ecPoint.equals(ecKey.getPubPoint())) {
  10958.             return null;
  10959.         }
  10960.         var bigInt = ecKey.priv;
  10961.         var pubKey = ecPoint.multiply(bigInt).getEncoded(compressed);
  10962.         return pubKey;
  10963.     },
  10964.     // used by unit test
  10965.     getDecompressedPubKeyHex: function (pubKeyHexComp) {
  10966.         var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  10967.         var ecPoint = ecparams.getCurve().decodePointHex(pubKeyHexComp);
  10968.         var pubByteArray = ecPoint.getEncoded(0);
  10969.         var pubHexUncompressed = ninja.publicKey.getHexFromByteArray(pubByteArray);
  10970.         return pubHexUncompressed;
  10971.     }
  10972. };
  10973. </script>
  10974.  
  10975. <script type="text/javascript">
  10976.     ninja.seeder = {
  10977.         init: (function () {
  10978.             // document.getElementById("generatekeyinput").value = "";
  10979.         })(),
  10980.  
  10981.         // number of mouse movements to wait for
  10982.         seedLimit: (function () {
  10983.             var num = Crypto.util.randomBytes(12)[11];
  10984.             return 200 + Math.floor(num);
  10985.         })(),
  10986.  
  10987.         seedCount: 0, // counter
  10988.         lastInputTime: new Date().getTime(),
  10989.         seedPoints: [],
  10990.  
  10991.         // seed function exists to wait for mouse movement to add more entropy before generating an address
  10992.         seed: function (evt) {
  10993.             if (!evt) var evt = window.event;
  10994.             var timeStamp = new Date().getTime();
  10995.  
  10996.             if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
  10997.                 ninja.seeder.seedCount++;
  10998.                 ninja.wallets.landwallet.open();
  10999.                 // document.getElementById("generate").style.display = "none";
  11000.                 // document.getElementById("menu").style.visibility = "visible";
  11001.                 ninja.seeder.removePoints();
  11002.             }
  11003.             // seed mouse position X and Y when mouse movements are greater than 40ms apart.
  11004.             else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt && (timeStamp - ninja.seeder.lastInputTime) > 40) {
  11005.                 SecureRandom.seedTime();
  11006.                 SecureRandom.seedInt16((evt.clientX * evt.clientY));
  11007.                 // ninja.seeder.showPoint(evt.clientX, evt.clientY);
  11008.                 ninja.seeder.seedCount++;
  11009.                 ninja.seeder.lastInputTime = new Date().getTime();
  11010.                 // ninja.seeder.showPool();
  11011.             }
  11012.         },
  11013.  
  11014.         // seed function exists to wait for mouse movement to add more entropy before generating an address
  11015.         seedKeyPress: function (evt) {
  11016.             if (!evt) var evt = window.event;
  11017.             // seeding is over now we generate and display the address
  11018.             if (ninja.seeder.seedCount == ninja.seeder.seedLimit) {
  11019.                 ninja.seeder.seedCount++;
  11020.                 ninja.wallets.landwallet.open();
  11021.                 document.getElementById("generate").style.display = "none";
  11022.                 document.getElementById("menu").style.visibility = "visible";
  11023.                 ninja.seeder.removePoints();
  11024.             }
  11025.             // seed key press character
  11026.             else if ((ninja.seeder.seedCount < ninja.seeder.seedLimit) && evt.which) {
  11027.                 var timeStamp = new Date().getTime();
  11028.                 // seed a bunch (minimum seedLimit) of times
  11029.                 SecureRandom.seedTime();
  11030.                 SecureRandom.seedInt8(evt.which);
  11031.                 var keyPressTimeDiff = timeStamp - ninja.seeder.lastInputTime;
  11032.                 SecureRandom.seedInt8(keyPressTimeDiff);
  11033.                 ninja.seeder.seedCount++;
  11034.                 ninja.seeder.lastInputTime = new Date().getTime();
  11035.                 ninja.seeder.showPool();
  11036.             }
  11037.         },
  11038.  
  11039.         showPool: function () {
  11040.             var poolHex;
  11041.             if (SecureRandom.poolCopyOnInit != null) {
  11042.                 poolHex = Crypto.util.bytesToHex(SecureRandom.poolCopyOnInit);
  11043.                 document.getElementById("seedpool").innerHTML = poolHex;
  11044.                 document.getElementById("seedpooldisplay").innerHTML = poolHex;
  11045.             }
  11046.             else {
  11047.                 poolHex = Crypto.util.bytesToHex(SecureRandom.pool);
  11048.                 document.getElementById("seedpool").innerHTML = poolHex;
  11049.                 document.getElementById("seedpooldisplay").innerHTML = poolHex;
  11050.             }
  11051.             document.getElementById("mousemovelimit").innerHTML = (ninja.seeder.seedLimit - ninja.seeder.seedCount);
  11052.         },
  11053.  
  11054.         showPoint: function (x, y) {
  11055.             var div = document.createElement("div");
  11056.             div.setAttribute("class", "seedpoint");
  11057.             div.style.top = y + "px";
  11058.             div.style.left = x + "px";
  11059.            
  11060.             // let's make the entropy 'points' grow and change color!
  11061.             percentageComplete = ninja.seeder.seedCount / ninja.seeder.seedLimit;
  11062.             pointSize = 2 + Math.ceil(9*percentageComplete) + 'px'
  11063.             pointColor = 255 - Math.ceil(140 * percentageComplete);
  11064.             div.style.backgroundColor = '#' + pointColor.toString(16) + 'FF' + pointColor.toString(16);
  11065.             div.style.width = pointSize;
  11066.             div.style.height = pointSize;
  11067.            
  11068.             document.getElementById("progress-bar-percentage").style.width=Math.ceil(percentageComplete*100)+"%";
  11069.             // for some reason, appending these divs to an IOS device breaks clicking altogether (?)
  11070.             if (navigator.platform != 'iPad' && navigator.platform != 'iPhone' && navigator.platform != 'iPod') {
  11071.                 document.body.appendChild(div);
  11072.             }
  11073.             ninja.seeder.seedPoints.push(div);
  11074.         },
  11075.         removePoints: function () {
  11076.             for (var i = 0; i < ninja.seeder.seedPoints.length; i++) {
  11077.                 document.body.removeChild(ninja.seeder.seedPoints[i]);
  11078.             }
  11079.             ninja.seeder.seedPoints = [];
  11080.         }
  11081.     };
  11082.     ninja.qrCode = {
  11083.         // determine which type number is big enough for the input text length
  11084.         getTypeNumber: function (text) {
  11085.             var lengthCalculation = text.length * 8 + 12; // length as calculated by the QRCode
  11086.             if (lengthCalculation < 72) { return 1; }
  11087.             else if (lengthCalculation < 128) { return 2; }
  11088.             else if (lengthCalculation < 208) { return 3; }
  11089.             else if (lengthCalculation < 288) { return 4; }
  11090.             else if (lengthCalculation < 368) { return 5; }
  11091.             else if (lengthCalculation < 480) { return 6; }
  11092.             else if (lengthCalculation < 528) { return 7; }
  11093.             else if (lengthCalculation < 688) { return 8; }
  11094.             else if (lengthCalculation < 800) { return 9; }
  11095.             else if (lengthCalculation < 976) { return 10; }
  11096.             return null;
  11097.         },
  11098.         createCanvas: function (text, sizeMultiplier) {
  11099.             sizeMultiplier = (sizeMultiplier == undefined) ? 2 : sizeMultiplier; // default 2
  11100.             // create the qrcode itself
  11101.             var typeNumber = ninja.qrCode.getTypeNumber(text);
  11102.             var qrcode = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
  11103.             qrcode.addData(text);
  11104.             qrcode.make();
  11105.             var width = qrcode.getModuleCount() * sizeMultiplier;
  11106.             var height = qrcode.getModuleCount() * sizeMultiplier;
  11107.             // create canvas element
  11108.             var canvas = document.createElement('canvas');
  11109.             var scale = 10.0;
  11110.             canvas.width = width * scale;
  11111.             canvas.height = height * scale;
  11112.             canvas.style.width = width + 'px';
  11113.             canvas.style.height = height + 'px';
  11114.             var ctx = canvas.getContext('2d');
  11115.             ctx.scale(scale, scale);
  11116.             // compute tileW/tileH based on width/height
  11117.             var tileW = width / qrcode.getModuleCount();
  11118.             var tileH = height / qrcode.getModuleCount();
  11119.             // draw in the canvas
  11120.             for (var row = 0; row < qrcode.getModuleCount(); row++) {
  11121.                 for (var col = 0; col < qrcode.getModuleCount(); col++) {
  11122.                     ctx.fillStyle = qrcode.isDark(row, col) ? "#000000" : "#ffffff";
  11123.                     ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
  11124.                 }
  11125.             }
  11126.             // return just built canvas
  11127.             return canvas;
  11128.         },
  11129.         // generate a QRCode and return it's representation as an Html table
  11130.         createTableHtml: function (text) {
  11131.             var typeNumber = ninja.qrCode.getTypeNumber(text);
  11132.             var qr = new QRCode(typeNumber, QRCode.ErrorCorrectLevel.H);
  11133.             qr.addData(text);
  11134.             qr.make();
  11135.             var tableHtml = "<table class='qrcodetable'>";
  11136.             for (var r = 0; r < qr.getModuleCount(); r++) {
  11137.                 tableHtml += "<tr>";
  11138.                 for (var c = 0; c < qr.getModuleCount(); c++) {
  11139.                     if (qr.isDark(r, c)) {
  11140.                         tableHtml += "<td class='qrcodetddark'/>";
  11141.                     } else {
  11142.                         tableHtml += "<td class='qrcodetdlight'/>";
  11143.                     }
  11144.                 }
  11145.                 tableHtml += "</tr>";
  11146.             }
  11147.             tableHtml += "</table>";
  11148.             return tableHtml;
  11149.         },
  11150.  
  11151.         // show QRCodes with canvas OR table (IE8)
  11152.         // parameter: keyValuePair
  11153.         // example: { "id1": "string1", "id2": "string2"}
  11154.         //      "id1" is the id of a div element where you want a QRCode inserted.
  11155.         //      "string1" is the string you want encoded into the QRCode.
  11156.         showQrCode: function (keyValuePair, sizeMultiplier) {
  11157.             for (var key in keyValuePair) {
  11158.                 var value = keyValuePair[key];
  11159.                 try {
  11160.                     if (document.getElementById(key)) {
  11161.                         document.getElementById(key).innerHTML = "";
  11162.                         document.getElementById(key).appendChild(ninja.qrCode.createCanvas(value, sizeMultiplier));
  11163.                     }
  11164.                 }
  11165.                 catch (e) {
  11166.                     // for browsers that do not support canvas (IE8)
  11167.                     document.getElementById(key).innerHTML = ninja.qrCode.createTableHtml(value);
  11168.                 }
  11169.             }
  11170.         }
  11171.     };
  11172.  
  11173.     ninja.tabSwitch = function (walletTab) {
  11174.         if (walletTab.className.indexOf("selected") == -1) {
  11175.             // unselect all tabs
  11176.             for (var wType in ninja.wallets) {
  11177.                 document.getElementById(wType).className = "tab";
  11178.                 ninja.wallets[wType].close();
  11179.             }
  11180.             walletTab.className += " selected";
  11181.             ninja.wallets[walletTab.getAttribute("id")].open();
  11182.         }
  11183.     };
  11184.  
  11185.     ninja.getQueryString = function () {
  11186.         var result = {}, queryString = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;
  11187.         while (m = re.exec(queryString)) {
  11188.             result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  11189.         }
  11190.         return result;
  11191.     };
  11192.    
  11193.     // use when passing an Array of Functions
  11194.     ninja.runSerialized = function (functions, onComplete) {
  11195.         onComplete = onComplete || function () { };
  11196.    
  11197.         if (functions.length === 0) onComplete();
  11198.         else {
  11199.             // run the first function, and make it call this
  11200.             // function when finished with the rest of the list
  11201.             var f = functions.shift();
  11202.             f(function () { ninja.runSerialized(functions, onComplete); });
  11203.         }
  11204.     };
  11205.    
  11206.     ninja.forSerialized = function (initial, max, whatToDo, onComplete) {
  11207.         onComplete = onComplete || function () { };
  11208.    
  11209.         if (initial === max) { onComplete(); }
  11210.         else {
  11211.             // same idea as runSerialized
  11212.             whatToDo(initial, function () { ninja.forSerialized(++initial, max, whatToDo, onComplete); });
  11213.         }
  11214.     };
  11215.    
  11216.     // use when passing an Object (dictionary) of Functions
  11217.     ninja.foreachSerialized = function (collection, whatToDo, onComplete) {
  11218.         var keys = [];
  11219.         for (var name in collection) {
  11220.             keys.push(name);
  11221.         }
  11222.         ninja.forSerialized(0, keys.length, function (i, callback) {
  11223.             whatToDo(keys[i], callback);
  11224.         }, onComplete);
  11225.     };
  11226. </script>
  11227.  
  11228. <script type="text/javascript">
  11229.     ninja.translator = {
  11230.         currentCulture: "en",
  11231.  
  11232.         translate: function (culture) {
  11233.             var dict = ninja.translator.translations[culture];
  11234.             if (dict) {
  11235.                 // set current culture
  11236.                 ninja.translator.currentCulture = culture;
  11237.                 // update menu UI
  11238.                 for (var cult in ninja.translator.translations) {
  11239.                     document.getElementById("culture" + cult).setAttribute("class", "");
  11240.                 }
  11241.                 document.getElementById("culture" + culture).setAttribute("class", "selected");
  11242.                 // apply translations
  11243.                 for (var id in dict) {
  11244.                     if (document.getElementById(id) && document.getElementById(id).value) {
  11245.                         document.getElementById(id).value = dict[id];
  11246.                     }
  11247.                     else if (document.getElementById(id)) {
  11248.                         document.getElementById(id).innerHTML = dict[id];
  11249.                     }
  11250.                 }
  11251.             }
  11252.         },
  11253.  
  11254.         get: function (id) {
  11255.             var translation = ninja.translator.translations[ninja.translator.currentCulture][id];
  11256.             return translation;
  11257.         },
  11258.  
  11259.         translations: {
  11260.             "en": {
  11261.                 // javascript alerts or messages
  11262.                 "paperlabelbitcoinaddress": "Bitcoin Address:",
  11263.                 "paperlabelprivatekey": "Private Key (Wallet Import Format):",
  11264.                 "paperlabelencryptedkey": "Encrypted Private Key (Password required)",
  11265.                 "bip38alertpassphraserequired": "Passphrase required for BIP38 key",
  11266.                 "detailalertnotvalidprivatekey": "The text you entered is not a valid private key or passphrase.",
  11267.                 "detailconfirmsha256": "The text you entered does not appear to be a private " + window.currencyName + " key.\n\nWould you like to use this text as a passphrase and create a private key using its SHA256 hash?\n\nWarning: Choosing an extremely strong passphrase (also known as a \"brain wallet\") is important as all common phrases, words, lyrics etc. are regularly scanned by hackers for bitcoin balances worth stealing.",
  11268.                 "bip38alertincorrectpassphrase": "Incorrect passphrase for this encrypted private key.",
  11269.             },
  11270.  
  11271.             "es": {
  11272.                 // javascript alerts or messages
  11273.                 "paperlabelbitcoinaddress": "Dirección Bitcoin:",
  11274.                 "paperlabelprivatekey": "Clave privada (formato para importar):",
  11275.  
  11276.                 // header and menu html
  11277.                 "tagline": "Generador de carteras Bitcoin de código abierto en lado de cliente con Javascript",
  11278.                 "generatelabelbitcoinaddress": "Generando dirección Bitcoin...",
  11279.                 "generatelabelmovemouse": "<blink>Mueve un poco el ratón para crear entropía...</blink>",
  11280.                 "calibratewallet": "Calibrate Printer (es)",
  11281.                 "paperwallet": "Cartera en papel",
  11282.                 "landwallet": "Welcome (Es)",
  11283.  
  11284.                 // footer html
  11285.                 "footerlabeldonations": "Donaciones:",
  11286.                 "footerlabeltranslatedby": "Traducción: <b>12345</b>Vypv2QSmuRXcciT5oEB27mPbWGeva",
  11287.                 "footerlabelpgp": "Clave pública PGP",
  11288.                 "footerlabelversion": "Histórico de versiones",
  11289.                 "footerlabelgithub": "Repositorio GitHub",
  11290.                 "footerlabelcopyright1": "&copy; Copyright 2014 Canton Becker and bitaddress.org.",
  11291.                 "footerlabelcopyright2": "Copyright del código JavaScript: en el fuente.",
  11292.                 "footerlabelnowarranty": "Sin garantía.",
  11293.  
  11294.                 // paper wallet html
  11295.                 "paperlabeladdressesperpage": "Direcciones por página:",
  11296.                 "paperlabeladdressestogenerate": "Direcciones en total:",
  11297.                 "papergenerate": "Generar",
  11298.                 "paperprint": "Imprimir"
  11299.             },
  11300.                
  11301.             "fr": {
  11302.                 // javascript alerts or messages
  11303.                 "paperlabelbitcoinaddress": "Adresse Bitcoin:",
  11304.                 "paperlabelprivatekey": "Clé Privée (Format d'importation de porte-monnaie):",
  11305.  
  11306.                 // header and menu html
  11307.                 "tagline": "Générateur De Porte-Monnaie Bitcoin Javascript Hors-Ligne",
  11308.                 "generatelabelbitcoinaddress": "Création de l'adresse Bitcoin...",
  11309.                 "generatelabelmovemouse": "<blink>BOUGEZ votre souris pour ajouter de l'entropie...</blink>",
  11310.                 "calibratewallet": "Calibrate Printer (fr)",
  11311.                 "paperwallet": "Porte-Monnaie Papier",
  11312.                 "landwallet": "Welcome (Fr)",
  11313.  
  11314.                 // footer html
  11315.                 "footerlabeldonations": "Dons:",
  11316.                 "footerlabeltranslatedby": "Traduction: 1Gy7NYSJNUYqUdXTBow5d7bCUEJkUFDFSq",
  11317.                 "footerlabelpgp": "Clé Publique PGP",
  11318.                 "footerlabelversion": "Historique De Version Signé",
  11319.                 "footerlabelgithub": "Dépôt GitHub",
  11320.                 "footerlabelcopyright1": "&copy; Copyright 2014 Canton Becker and bitaddress.org.",
  11321.                 "footerlabelcopyright2": "Les droits d'auteurs JavaScript sont inclus dans le code source.",
  11322.                 "footerlabelnowarranty": "Aucune garantie.",
  11323.                 "newaddress": "Générer Une Nouvelle Adresse",
  11324.  
  11325.                 // paper wallet html
  11326.                 "paperlabeladdressesperpage": "Adresses par page:",
  11327.                 "paperlabeladdressestogenerate": "Nombre d'adresses à créer:",
  11328.                 "papergenerate": "Générer",
  11329.                 "paperprint": "Imprimer"
  11330.             }
  11331.         }
  11332.     };
  11333.  
  11334.     ninja.translator.showEnglishJson = function () {
  11335.         var english = ninja.translator.translations["en"];
  11336.         var spanish = ninja.translator.translations["es"];
  11337.         var spanishClone = {};
  11338.         for (var key in spanish) {
  11339.             spanishClone[key] = spanish[key];
  11340.         }
  11341.         var newLang = {};
  11342.         for (var key in english) {
  11343.             newLang[key] = english[key];
  11344.             delete spanishClone[key];
  11345.         }
  11346.         for (var key in spanishClone) {
  11347.             if (document.getElementById(key)) {
  11348.                 if (document.getElementById(key).value) {
  11349.                     newLang[key] = document.getElementById(key).value;
  11350.                 }
  11351.                 else {
  11352.                     newLang[key] = document.getElementById(key).innerHTML;
  11353.                 }
  11354.             }
  11355.         }
  11356.         var div = document.createElement("div");
  11357.         div.setAttribute("class", "englishjson");
  11358.         div.innerHTML = "<h3>English Json</h3>";
  11359.         var elem = document.createElement("textarea");
  11360.         elem.setAttribute("rows", "35");
  11361.         elem.setAttribute("cols", "110");
  11362.         elem.setAttribute("wrap", "off");
  11363.         var langJson = "{\n";
  11364.         for (var key in newLang) {
  11365.             langJson += "\t\"" + key + "\"" + ": " + "\"" + newLang[key].replace(/\"/g, "\\\"").replace(/\n/g, "\\n") + "\",\n";
  11366.         }
  11367.         langJson = langJson.substr(0, langJson.length - 2);
  11368.         langJson += "\n}\n";
  11369.         elem.innerHTML = langJson;
  11370.         div.appendChild(elem);
  11371.         document.body.appendChild(div);
  11372.     };
  11373. </script>
  11374.  
  11375.  
  11376. <!-- UX controls for switching tabs -->
  11377.  
  11378. <script type="text/javascript">
  11379.     ninja.wallets.landwallet = {
  11380.         open: function () {
  11381.             document.getElementById("landarea").style.display = "block";
  11382.         },
  11383.  
  11384.         close: function () {
  11385.             document.getElementById("landarea").style.display = "none";
  11386.         }
  11387.     };
  11388. </script>
  11389.  
  11390. <script type="text/javascript">
  11391.     ninja.wallets.calibratewallet = {
  11392.         open: function () {
  11393.             document.getElementById("calibratearea").style.display = "block";
  11394.         },
  11395.  
  11396.         close: function () {
  11397.             document.getElementById("calibratearea").style.display = "none";
  11398.         }
  11399.     };
  11400. </script>
  11401.  
  11402. <script type="text/javascript">
  11403.     ninja.wallets.backwallet = {
  11404.         open: function () {
  11405.             document.getElementById("backarea").style.display = "block";
  11406.         },
  11407.  
  11408.         close: function () {
  11409.             document.getElementById("backarea").style.display = "none";
  11410.         }
  11411.     };
  11412. </script>
  11413.  
  11414.  
  11415.  
  11416. <script type="text/javascript">
  11417.     ninja.wallets.foldwallet = {
  11418.         open: function () {
  11419.             document.getElementById("foldarea").style.display = "block";
  11420.         },
  11421.  
  11422.         close: function () {
  11423.             document.getElementById("foldarea").style.display = "none";
  11424.         }
  11425.     };
  11426. </script>
  11427.  
  11428.  
  11429. <script type="text/javascript">
  11430.     ninja.wallets.paperwallet = {
  11431.         open: function () {
  11432.             document.getElementById("main").setAttribute("class", "paper"); // add 'paper' class to main div
  11433.             var paperArea = document.getElementById("paperarea");
  11434.             paperArea.style.display = "block";
  11435.             var perPageLimitElement = document.getElementById("paperlimitperpage");
  11436.             var limitElement = document.getElementById("paperlimit");
  11437.             var pageBreakAt = (ninja.wallets.paperwallet.useArtisticWallet) ? ninja.wallets.paperwallet.pageBreakAtArtisticDefault : ninja.wallets.paperwallet.pageBreakAtDefault;
  11438.             if (perPageLimitElement && perPageLimitElement.value < 1) {
  11439.                 perPageLimitElement.value = pageBreakAt;
  11440.             }
  11441.             if (limitElement && limitElement.value < 1) {
  11442.                 limitElement.value = pageBreakAt;
  11443.             }
  11444.             if (document.getElementById("paperkeyarea").innerHTML == "") {
  11445.                 document.getElementById("paperencrypt").checked = false;
  11446.                 ninja.wallets.paperwallet.encrypt = false;
  11447.                 ninja.wallets.paperwallet.build(pageBreakAt, pageBreakAt, !document.getElementById('paperart').checked, document.getElementById('paperpassphrase').value);
  11448.             }
  11449.         },
  11450.  
  11451.         close: function () {
  11452.             document.getElementById("paperarea").style.display = "none";
  11453.             document.getElementById("main").setAttribute("class", ""); // remove 'paper' class from main div
  11454.         },
  11455.  
  11456.         toggleVanityField: function(show) {
  11457.             document.getElementById('keyButtons').style.display= show ? 'none' : 'block';
  11458.             document.getElementById('supplyKeys').style.display = show ? 'block' : 'none';
  11459.         },
  11460.  
  11461.         remaining: null, // use to keep track of how many addresses are left to process when building the paper wallet
  11462.         count: 0,
  11463.         pageBreakAtDefault: 7,
  11464.         pageBreakAtArtisticDefault: 1,
  11465.         useArtisticWallet: false,
  11466.         pageBreakAt: null,
  11467.         passphrase: null,
  11468.         lastwallet: null,
  11469.         minPassphraseLength: 15,
  11470.  
  11471.         build: function (numWallets, pageBreakAt, useArtisticWallet, passphrase) {
  11472.             if (numWallets < 1) numWallets = 1;
  11473.             ninja.wallets.paperwallet.remaining = numWallets;
  11474.             ninja.wallets.paperwallet.count = 0;
  11475.             ninja.wallets.paperwallet.useArtisticWallet = useArtisticWallet;
  11476.             ninja.wallets.paperwallet.pageBreakAt = pageBreakAt;
  11477.             document.getElementById("paperkeyarea").innerHTML = "";
  11478.             if (ninja.wallets.paperwallet.encrypt && passphrase == "") {
  11479.                 alert(ninja.translator.get("bip38alertpassphraserequired"));
  11480.                 return;
  11481.             }
  11482.             ninja.wallets.paperwallet.passphrase = passphrase;
  11483.             setTimeout(ninja.wallets.paperwallet.batch, 0);
  11484.         },
  11485.        
  11486.         buildManual: function(wallet, passphrase) {
  11487.             ninja.wallets.paperwallet.remaining = 1;
  11488.             ninja.wallets.paperwallet.count = 0;
  11489.             ninja.wallets.paperwallet.pageBreakAt = 1;
  11490.             document.getElementById("paperkeyarea").innerHTML = "";
  11491.             if (ninja.wallets.paperwallet.encrypt && passphrase == "") {
  11492.                 alert(ninja.translator.get("bip38alertpassphraserequired"));
  11493.                 return;
  11494.             }
  11495.             ninja.wallets.paperwallet.passphrase = passphrase;
  11496.             setTimeout(function() {
  11497.                 ninja.wallets.paperwallet.batch(wallet);
  11498.             }, 0);
  11499.         },
  11500.        
  11501.         batch: function (addressSeed) {
  11502.             if (ninja.wallets.paperwallet.remaining > 0) {
  11503.                 var paperArea = document.getElementById("paperkeyarea");
  11504.                 ninja.wallets.paperwallet.count++;
  11505.                 var i = ninja.wallets.paperwallet.count;
  11506.                 var pageBreakAt = ninja.wallets.paperwallet.pageBreakAt;
  11507.                 var div = document.createElement("div");
  11508.                 div.setAttribute("id", "keyarea" + i);
  11509.                 div.innerHTML = ninja.wallets.paperwallet.templateArtisticHtml(i);
  11510.                 div.setAttribute("class", "keyarea art");
  11511.                 if (paperArea.innerHTML != "") {
  11512.                     // page break
  11513.                    if ((i-1) % pageBreakAt == 0 && i >= pageBreakAt) {
  11514.                         var pBreak = document.createElement("div");
  11515.                         pBreak.setAttribute("class", "pagebreak");
  11516.                         document.getElementById("paperkeyarea").appendChild(pBreak);
  11517.                         div.style.pageBreakBefore = "always";
  11518.                         if (!ninja.wallets.paperwallet.useArtisticWallet) {
  11519.                             div.style.borderTop = "2px solid green";
  11520.                         }
  11521.                     }
  11522.                 }
  11523.                 document.getElementById("paperkeyarea").appendChild(div);
  11524.                 ninja.wallets.paperwallet.generateNewWallet(addressSeed, function(wallet) {
  11525.                     var walletKey = ninja.wallets.paperwallet.encrypt ? wallet.encryptedKey : wallet.wifKey;
  11526.                     ninja.wallets.paperwallet.showArtisticWallet(i, wallet.address, walletKey);
  11527.                 });
  11528.                 ninja.wallets.paperwallet.remaining--;
  11529.                 setTimeout(ninja.wallets.paperwallet.batch, 0);
  11530.             }
  11531.         },
  11532.  
  11533.         generateNewWallet: function(addressSeed, callback) {
  11534.             if (addressSeed == null) {
  11535.                 var key = new Bitcoin.ECKey(false);
  11536.                 addressSeed = { address: key.getBitcoinAddress(), wifKey: key.getBitcoinWalletImportFormat() };
  11537.             }
  11538.             ninja.wallets.paperwallet.lastwallet = addressSeed;
  11539.             if (ninja.wallets.paperwallet.encrypt) {
  11540.                 document.getElementById("busyblock").className = "busy";
  11541.                 setTimeout(function() {
  11542.                     ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(addressSeed.wifKey, ninja.wallets.paperwallet.passphrase, false, function(encodedKey) {
  11543.                         document.getElementById("busyblock").className = "";
  11544.                         addressSeed.passphrase = ninja.wallets.paperwallet.passphrase;
  11545.                         addressSeed.encryptedKey = encodedKey;
  11546.                         ninja.wallets.paperwallet.lastwallet.addressSeed = addressSeed;
  11547.                         callback(addressSeed);
  11548.                     });
  11549.                 }, 10);
  11550.             } else {
  11551.                 callback(addressSeed);
  11552.             }
  11553.         },
  11554.  
  11555.         templateArtisticHtml: function (i) {
  11556.             var keyelement = 'btcprivwif';
  11557.             if (ninja.wallets.paperwallet.encrypt) {
  11558.                 keyelement = 'btcencryptedkey'
  11559.             }
  11560.  
  11561.             var walletHtml =
  11562.                         "<div class='artwallet' id='artwallet" + i + "'>" +
  11563.             //"<iframe src='bitcoin-wallet-01.svg' id='papersvg" + i + "' class='papersvg' ></iframe>" +
  11564.                             // "<img id='papersvg" + i + "' class='papersvg' src='" + window.frontJPG + "' />" +
  11565.                             "<div class='btcaddress' id='btcaddress" + i + "'></div>" +
  11566.                             "<div id='qrcode_public" + i + "' class='qrcode_public'></div>" +
  11567.                             "<div id='qrcode_private" + i + "' class='qrcode_private'></div>" +
  11568.                             // "<div class='dupbtcaddress' id='dupbtcaddress" + i + "'></div>" +
  11569.                             "<div class='" + keyelement + "' id='" + keyelement + i + "'></div>" +
  11570.                             // "<div class='dup" + keyelement + "' id='dup" + keyelement + i + "'></div>" +
  11571.                             "<div class='wallettype' id='wallettype" + i + "'></div>" +
  11572.                         "</div>";
  11573.             return walletHtml;
  11574.         },
  11575.  
  11576.         showArtisticWallet: function (idPostFix, bitcoinAddress, privateKey) {
  11577.             var keyValuePair = {};
  11578.             keyValuePair["qrcode_public" + idPostFix] = bitcoinAddress;
  11579.             keyValuePair["qrcode_private" + idPostFix] = privateKey;
  11580.             ninja.qrCode.showQrCode(keyValuePair, 2.75);
  11581.             document.getElementById("btcaddress" + idPostFix).innerHTML = bitcoinAddress;
  11582.             // document.getElementById("dupbtcaddress" + idPostFix).innerHTML = bitcoinAddress;
  11583.  
  11584.             if (ninja.wallets.paperwallet.encrypt) {
  11585.                 var half = privateKey.length / 2;
  11586.                 document.getElementById("btcencryptedkey" + idPostFix).innerHTML = privateKey;
  11587.                 // document.getElementById("dupbtcencryptedkey" + idPostFix).innerHTML = privateKey;
  11588.                 document.getElementById("wallettype" + idPostFix).innerHTML = 'BIP38 Encrypted';
  11589.             }
  11590.             else {
  11591.                 document.getElementById("btcprivwif" + idPostFix).innerHTML = privateKey;
  11592.                 // document.getElementById("dupbtcprivwif" + idPostFix).innerHTML = privateKey;
  11593.                 document.getElementById("wallettype" + idPostFix).innerHTML = '';
  11594.             }
  11595.  
  11596.             // CODE to modify SVG DOM elements
  11597.             //var paperSvg = document.getElementById("papersvg" + idPostFix);
  11598.             //if (paperSvg) {
  11599.             //  svgDoc = paperSvg.contentDocument;
  11600.             //  if (svgDoc) {
  11601.             //      var bitcoinAddressElement = svgDoc.getElementById("bitcoinaddress");
  11602.             //      var privateKeyElement = svgDoc.getElementById("privatekey");
  11603.             //      if (bitcoinAddressElement && privateKeyElement) {
  11604.             //          bitcoinAddressElement.textContent = bitcoinAddress;
  11605.             //          privateKeyElement.textContent = privateKeyWif;
  11606.             //      }
  11607.             //  }
  11608.             //}
  11609.         },
  11610.  
  11611.         toggleArt: function (element) {
  11612.             if (!element.checked) {
  11613.                 // show Art
  11614.                 document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
  11615.                 document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
  11616.             }
  11617.             else {
  11618.                 // hide Art
  11619.                 document.getElementById("paperlimitperpage").value = ninja.wallets.paperwallet.pageBreakAtDefault;
  11620.                 document.getElementById("paperlimit").value = ninja.wallets.paperwallet.pageBreakAtDefault;
  11621.             }
  11622.         },
  11623.  
  11624.         toggleEncryptSettings: function(show, cancelSave) {
  11625.             if (show == null)
  11626.                 show = document.getElementById('paperbip38settings').className != 'show';
  11627.             var encryptBox = document.getElementById('paperencrypt');
  11628.             if (cancelSave == true) {
  11629.                 encryptBox.checked = ninja.wallets.paperwallet.encrypt;
  11630.             }
  11631.                
  11632.             document.getElementById('paperbip38settings').className = show ? 'show' : '';
  11633.             document.getElementById('paperencryptpassphrase').innerText =
  11634.                 document.getElementById('paperencryptpassphrase').textContent = document.getElementById('paperpassphrase').value;
  11635.            
  11636.             if (!show && !cancelSave) {
  11637.                 ninja.wallets.paperwallet.encrypt = encryptBox.checked;
  11638.                 ninja.wallets.paperwallet.buildManual(ninja.wallets.paperwallet.lastwallet, document.getElementById('paperpassphrase').value);
  11639.                 ninja.wallets.paperwallet.resetLimits();
  11640.             }
  11641.            
  11642.             document.getElementById('paperencryptstatus').className = ninja.wallets.paperwallet.encrypt ? '' : 'hide';
  11643.         },
  11644.  
  11645.         resetLimits: function () {
  11646.             // var hideArt = document.getElementById("paperart");
  11647.             var hideArt = {checked: false}
  11648.             var paperEncrypt = document.getElementById("paperencrypt");
  11649.             var limit;
  11650.             var limitperpage;
  11651.  
  11652.             document.getElementById("paperkeyarea").style.fontSize = "100%";
  11653.             if (!hideArt.checked) {
  11654.                 limit = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
  11655.                 limitperpage = ninja.wallets.paperwallet.pageBreakAtArtisticDefault;
  11656.             }
  11657.             else if (hideArt.checked && paperEncrypt.checked) {
  11658.                 limit = ninja.wallets.paperwallet.pageBreakAtDefault;
  11659.                 limitperpage = ninja.wallets.paperwallet.pageBreakAtDefault;
  11660.                 // reduce font size
  11661.                 document.getElementById("paperkeyarea").style.fontSize = "95%";
  11662.             }
  11663.             else if (hideArt.checked && !paperEncrypt.checked) {
  11664.                 limit = ninja.wallets.paperwallet.pageBreakAtDefault;
  11665.                 limitperpage = ninja.wallets.paperwallet.pageBreakAtDefault;
  11666.             }
  11667.             // document.getElementById("paperlimitperpage").value = limitperpage;
  11668.             // document.getElementById("paperlimit").value = limit;
  11669.         }
  11670.     };
  11671. </script>
  11672.  
  11673. <script type="text/javascript">
  11674.     ninja.wallets.detailwallet = {
  11675.         qrscanner: {
  11676.             scanner: null,
  11677.  
  11678.             start: function() {
  11679.                 document.getElementById('paperqrscanner').className = 'show';
  11680.                 ninja.wallets.detailwallet.qrscanner.showError(null);
  11681.                 var supported = ninja.wallets.detailwallet.qrscanner.scanner.isSupported();
  11682.                 if (!supported) {
  11683.                     document.getElementById('paperqrnotsupported').className = '';
  11684.                 } else {
  11685.                     ninja.wallets.detailwallet.qrscanner.scanner.start();
  11686.                 }
  11687.             },
  11688.  
  11689.             stop: function() {
  11690.                 ninja.wallets.detailwallet.qrscanner.scanner.stop();
  11691.                 document.getElementById('paperqrscanner').className = '';
  11692.             },
  11693.  
  11694.             showError: function(error) {
  11695.                 if (error) {
  11696.                     if (error == 'PERMISSION_DENIED' || error == 'PermissionDeniedError') {
  11697.                         document.getElementById('paperqrerror').innerHTML = '';
  11698.                         document.getElementById('paperqrpermissiondenied').className = '';
  11699.                     } else {
  11700.                         document.getElementById('paperqrerror').innerHTML = error;
  11701.                         document.getElementById('paperqrpermissiondenied').className = 'hide';
  11702.                     }
  11703.                 } else {
  11704.                     document.getElementById('paperqrerror').innerHTML = '';
  11705.                     document.getElementById('paperqrpermissiondenied').className = 'hide';
  11706.                 }
  11707.             }
  11708.         },
  11709.  
  11710.         open: function () {
  11711.             document.getElementById("detailarea").style.display = "block";
  11712.             document.getElementById("detailprivkey").focus();
  11713.             if (!ninja.wallets.detailwallet.qrscanner.scanner) {
  11714.                 ninja.wallets.detailwallet.qrscanner.scanner = new QRCodeScanner(320, 240, 'paperqroutput',
  11715.                     function(data) {
  11716.                         document.getElementById('detailprivkey').value = data;
  11717.                         document.getElementById('paperqrscanner').className = '';
  11718.                     },
  11719.                     function(error) {
  11720.                         ninja.wallets.detailwallet.qrscanner.showError(error);
  11721.                     });
  11722.             }
  11723.         },
  11724.  
  11725.         close: function () {
  11726.             document.getElementById("detailarea").style.display = "none";
  11727.         },
  11728.  
  11729.         openCloseFaq: function (faqNum) {
  11730.             // do close
  11731.             if (document.getElementById("detaila" + faqNum).style.display == "block") {
  11732.                 document.getElementById("detaila" + faqNum).style.display = "none";
  11733.                 document.getElementById("detaile" + faqNum).setAttribute("class", "more");
  11734.             }
  11735.             // do open
  11736.             else {
  11737.                 document.getElementById("detaila" + faqNum).style.display = "block";
  11738.                 document.getElementById("detaile" + faqNum).setAttribute("class", "less");
  11739.             }
  11740.         },
  11741.  
  11742.         viewDetails: function () {
  11743.             var bip38 = false;
  11744.             var key = document.getElementById("detailprivkey").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
  11745.             document.getElementById("detailprivkey").value = key;
  11746.             var bip38CommandDisplay = document.getElementById("detailbip38commands").style.display;
  11747.             ninja.wallets.detailwallet.clear();
  11748.             if (key == "") {
  11749.                 return;
  11750.             }
  11751.             if (ninja.privateKey.isBIP38Format(key)) {
  11752.                 document.getElementById("detailbip38commands").style.display = bip38CommandDisplay;
  11753.                 if (bip38CommandDisplay != "block") {
  11754.                     document.getElementById("detailbip38commands").style.display = "block";
  11755.                     document.getElementById("detailprivkeypassphrase").focus();
  11756.                     return;
  11757.                 }
  11758.                 var passphrase = document.getElementById("detailprivkeypassphrase").value.toString().replace(/^\s+|\s+$/g, ""); // trim white space
  11759.                 if (passphrase == "") {
  11760.                     alert(ninja.translator.get("bip38alertpassphraserequired"));
  11761.                     return;
  11762.                 }
  11763.                 document.getElementById("busyblock_decrypt").className = "busy";
  11764.                 // show Private Key BIP38 Format
  11765.                 document.getElementById("detailprivbip38").innerHTML = key;
  11766.                 document.getElementById("detailbip38").style.display = "block";
  11767.                 ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(key, passphrase, function (btcKeyOrError) {
  11768.                     document.getElementById("busyblock_decrypt").className = "";
  11769.                     if (btcKeyOrError.message) {
  11770.                         alert(btcKeyOrError.message);
  11771.                         ninja.wallets.detailwallet.clear();
  11772.                     } else {
  11773.                         ninja.wallets.detailwallet.populateKeyDetails(new Bitcoin.ECKey(btcKeyOrError));
  11774.                     }
  11775.                 });
  11776.             }
  11777.             else {
  11778.                 if (Bitcoin.ECKey.isMiniFormat(key)) {
  11779.                     // show Private Key Mini Format
  11780.                     document.getElementById("detailprivmini").innerHTML = key;
  11781.                     document.getElementById("detailmini").style.display = "block";
  11782.                 }
  11783.                 else if (Bitcoin.ECKey.isBase6Format(key)) {
  11784.                     // show Private Key Base6 Format
  11785.                     document.getElementById("detailprivb6").innerHTML = key;
  11786.                     document.getElementById("detailb6").style.display = "block";
  11787.                 }
  11788.                 var btcKey = new Bitcoin.ECKey(key);
  11789.                 if (btcKey.priv == null) {
  11790.                     // enforce a minimum passphrase length
  11791.                     if (key.length >= ninja.wallets.paperwallet.minPassphraseLength) {
  11792.                         // Deterministic Wallet confirm box to ask if user wants to SHA256 the input to get a private key
  11793.                         var usePassphrase = confirm(ninja.translator.get("detailconfirmsha256"));
  11794.                         if (usePassphrase) {
  11795.                             var bytes = Crypto.SHA256(key, { asBytes: true });
  11796.                             var btcKey = new Bitcoin.ECKey(bytes);
  11797.                         }
  11798.                         else {
  11799.                             ninja.wallets.detailwallet.clear();
  11800.                         }
  11801.                     }
  11802.                     else {
  11803.                         alert(ninja.translator.get("detailalertnotvalidprivatekey"));
  11804.                         ninja.wallets.detailwallet.clear();
  11805.                     }
  11806.                 }
  11807.                 ninja.wallets.detailwallet.populateKeyDetails(btcKey);
  11808.             }
  11809.         },
  11810.  
  11811.         populateKeyDetails: function (btcKey) {
  11812.             if (btcKey.priv != null) {
  11813.                 btcKey.setCompressed(false);
  11814.                 document.getElementById('detailkeyarea').className = '';
  11815.                 document.getElementById('detailkeyareakey').innerHTML = document.getElementById('detailprivkey').value;
  11816.                 document.getElementById("detailprivhex").innerHTML = btcKey.toString().toUpperCase();
  11817.                 document.getElementById("detailprivb64").innerHTML = btcKey.toString("base64");
  11818.                 var bitcoinAddress = btcKey.getBitcoinAddress();
  11819.                 var wif = btcKey.getBitcoinWalletImportFormat();
  11820.                 ninja.wallets.detailwallet.lastwallet = { address: bitcoinAddress, wifKey: wif };
  11821.                 document.getElementById("detailpubkey").innerHTML = btcKey.getPubKeyHex();
  11822.                 document.getElementById("detailaddress").innerHTML = bitcoinAddress;
  11823.                 document.getElementById("detailprivwif").innerHTML = wif;
  11824.                 btcKey.setCompressed(true);
  11825.                 var bitcoinAddressComp = btcKey.getBitcoinAddress();
  11826.                 var wifComp = btcKey.getBitcoinWalletImportFormat();
  11827.                 document.getElementById("detailpubkeycomp").innerHTML = btcKey.getPubKeyHex();
  11828.                 document.getElementById("detailaddresscomp").innerHTML = bitcoinAddressComp;
  11829.                 document.getElementById("detailprivwifcomp").innerHTML = wifComp;
  11830.  
  11831.                 ninja.qrCode.showQrCode({
  11832.                     "detailqrcodepublic": bitcoinAddress,
  11833.                     "detailqrcodepubliccomp": bitcoinAddressComp,
  11834.                     "detailqrcodeprivate": wif,
  11835.                     "detailqrcodeprivatecomp": wifComp
  11836.                 }, 4);
  11837.             }
  11838.         },
  11839.  
  11840.         clear: function () {
  11841.             document.getElementById('detailkeyarea').className = 'hide';
  11842.             document.getElementById("detailpubkey").innerHTML = "";
  11843.             document.getElementById("detailpubkeycomp").innerHTML = "";
  11844.             document.getElementById("detailaddress").innerHTML = "";
  11845.             document.getElementById("detailaddresscomp").innerHTML = "";
  11846.             document.getElementById("detailprivwif").innerHTML = "";
  11847.             document.getElementById("detailprivwifcomp").innerHTML = "";
  11848.             document.getElementById("detailprivhex").innerHTML = "";
  11849.             document.getElementById("detailprivb64").innerHTML = "";
  11850.             document.getElementById("detailprivb6").innerHTML = "";
  11851.             document.getElementById("detailprivmini").innerHTML = "";
  11852.             document.getElementById("detailprivbip38").innerHTML = "";
  11853.             document.getElementById("detailqrcodepublic").innerHTML = "";
  11854.             document.getElementById("detailqrcodepubliccomp").innerHTML = "";
  11855.             document.getElementById("detailqrcodeprivate").innerHTML = "";
  11856.             document.getElementById("detailqrcodeprivatecomp").innerHTML = "";
  11857.             document.getElementById("detailb6").style.display = "none";
  11858.             document.getElementById("detailmini").style.display = "none";
  11859.             document.getElementById("detailbip38commands").style.display = "none";
  11860.             document.getElementById("detailbip38").style.display = "none";
  11861.         },
  11862.  
  11863.         loadInPaperWallet: function() {
  11864.             document.getElementById("paperkeyarea").innerHTML = 'Loading...';
  11865.             ninja.tabSwitch(document.getElementById('paperwallet'));
  11866.             ninja.wallets.paperwallet.toggleVanityField(true);
  11867.             document.getElementById('suppliedPrivateKey').value = ninja.wallets.detailwallet.lastwallet.wifKey;
  11868.             if (ninja.wallets.paperwallet.encrypt && !confirm('Do you want to encrypt this wallet using the previously supplied private key?')) {
  11869.                 document.getElementById('paperencrypt').checked = false;
  11870.                 ninja.wallets.paperwallet.toggleEncryptSettings(false);
  11871.             }
  11872.             ninja.wallets.paperwallet.buildManual(ninja.wallets.detailwallet.lastwallet, ninja.wallets.paperwallet.passphrase);
  11873.         }
  11874.     };
  11875. </script>
  11876.  
  11877.  
  11878. <script type="text/javascript">
  11879. (function (ninja) {
  11880.     var ut = ninja.unitTests = {
  11881.         runSynchronousTests: function () {
  11882.             document.getElementById("busyblock").className = "busy";
  11883.             var div = document.createElement("div");
  11884.             div.setAttribute("class", "unittests");
  11885.             div.setAttribute("id", "unittests");
  11886.             var testResults = "";
  11887.             var passCount = 0;
  11888.             var testCount = 0;
  11889.             for (var test in ut.synchronousTests) {
  11890.                 var exceptionMsg = "";
  11891.                 var resultBool = false;
  11892.                 try {
  11893.                     resultBool = ut.synchronousTests[test]();
  11894.                 } catch (ex) {
  11895.                     exceptionMsg = ex.toString();
  11896.                     resultBool = false;
  11897.                 }
  11898.                 if (resultBool == true) {
  11899.                     var passFailStr = "pass";
  11900.                     passCount++;
  11901.                 }
  11902.                 else {
  11903.                     var passFailStr = "<b>FAIL " + exceptionMsg + "</b>";
  11904.                 }
  11905.                 testCount++;
  11906.                 testResults += test + ": " + passFailStr + "<br/>";
  11907.             }
  11908.             testResults += passCount + " of " + testCount + " synchronous tests passed";
  11909.             if (passCount < testCount) {
  11910.                 testResults += "<b>" + (testCount - passCount) + " unit test(s) failed</b>";
  11911.             }
  11912.             div.innerHTML = "<a name=\"tests\"></a><h3>Unit Tests</h3><div id=\"unittestresults\">" + testResults + "<br/><br/></div>";
  11913.             document.body.appendChild(div);
  11914.             document.getElementById("busyblock").className = "";
  11915.  
  11916.     },
  11917.  
  11918.         runAsynchronousTests: function () {
  11919.             var div = document.createElement("div");
  11920.             div.setAttribute("class", "unittests");
  11921.             div.setAttribute("id", "asyncunittests");
  11922.             div.innerHTML = "<a name=\"tests\"></a><h3>Async Unit Tests</h3><div id=\"asyncunittestresults\"></div><br/><br/><br/><br/>";
  11923.             document.body.appendChild(div);
  11924.  
  11925.             // run the asynchronous tests one after another so we don't crash the browser
  11926.             ninja.foreachSerialized(ninja.unitTests.asynchronousTests, function (name, cb) {
  11927.                 document.getElementById("busyblock").className = "busy";
  11928.                 ninja.unitTests.asynchronousTests[name](cb);
  11929.             }, function () {
  11930.                 document.getElementById("asyncunittestresults").innerHTML += "running of asynchronous unit tests complete!<br/>";
  11931.                 document.getElementById("busyblock").className = "";
  11932.             });
  11933.         },
  11934.  
  11935.         synchronousTests: {
  11936.             //ninja.publicKey tests
  11937.             testIsPublicKeyHexFormat: function () {
  11938.                 var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  11939.                 var bool = ninja.publicKey.isPublicKeyHexFormat(key);
  11940.                 if (bool != true) {
  11941.                     return false;
  11942.                 }
  11943.                 return true;
  11944.             },
  11945.             testGetHexFromByteArray: function () {
  11946.                 var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
  11947.                 var key = ninja.publicKey.getHexFromByteArray(bytes);
  11948.                 if (key != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44") {
  11949.                     return false;
  11950.                 }
  11951.                 return true;
  11952.             },
  11953.             testHexToBytes: function () {
  11954.                 var key = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  11955.                 var bytes = Crypto.util.hexToBytes(key);
  11956.                 if (bytes.toString() != "4,120,152,47,64,250,12,11,122,85,113,117,131,175,201,154,78,223,211,1,162,114,157,197,155,11,142,185,225,134,146,188,181,33,240,84,250,217,130,175,76,193,147,58,253,31,27,86,62,167,121,166,170,108,206,54,163,11,148,125,214,83,230,62,68") {
  11957.                     return false;
  11958.                 }
  11959.                 return true;
  11960.             },
  11961.             testGetBitcoinAddressFromByteArray: function () {
  11962.                 var bytes = [4, 120, 152, 47, 64, 250, 12, 11, 122, 85, 113, 117, 131, 175, 201, 154, 78, 223, 211, 1, 162, 114, 157, 197, 155, 11, 142, 185, 225, 134, 146, 188, 181, 33, 240, 84, 250, 217, 130, 175, 76, 193, 147, 58, 253, 31, 27, 86, 62, 167, 121, 166, 170, 108, 206, 54, 163, 11, 148, 125, 214, 83, 230, 62, 68];
  11963.                 var address = ninja.publicKey.getBitcoinAddressFromByteArray(bytes);
  11964.                 if (address != "1Cnz9ULjzBPYhDw1J8bpczDWCEXnC9HuU1") {
  11965.                     return false;
  11966.                 }
  11967.                 return true;
  11968.             },
  11969.             testGetByteArrayFromAdding: function () {
  11970.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  11971.                 var key2 = "0419153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C0159DC0099AD54F733812892EB9A11A8C816A201B3BAF0D97117EBA2033C9AB2";
  11972.                 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
  11973.                 if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
  11974.                     return false;
  11975.                 }
  11976.                 return true;
  11977.             },
  11978.             testGetByteArrayFromAddingCompressed: function () {
  11979.                 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
  11980.                 var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
  11981.                 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
  11982.                 var hex = ninja.publicKey.getHexFromByteArray(bytes);
  11983.                 if (hex != "029713E3983625B8FF045373D866BD4C52AA3904C4FD02294A06E221A7C7FA4AEB") {
  11984.                     return false;
  11985.                 }
  11986.                 return true;
  11987.             },
  11988.             testGetByteArrayFromAddingUncompressedAndCompressed: function () {
  11989.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  11990.                 var key2 = "0219153E53FECAD7FF07FEC26F7DDEB1EDD66957711AA4554B8475F10AFBBCD81C";
  11991.                 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
  11992.                 if (bytes.toString() != "4,151,19,227,152,54,37,184,255,4,83,115,216,102,189,76,82,170,57,4,196,253,2,41,74,6,226,33,167,199,250,74,235,223,128,233,99,150,147,92,57,39,208,84,196,71,68,248,166,106,138,95,172,253,224,70,187,65,62,92,81,38,253,79,0") {
  11993.                     return false;
  11994.                 }
  11995.                 return true;
  11996.             },
  11997.             testGetByteArrayFromAddingShouldReturnNullWhenSameKey1: function () {
  11998.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  11999.                 var key2 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  12000.                 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
  12001.                 if (bytes != null) {
  12002.                     return false;
  12003.                 }
  12004.                 return true;
  12005.             },
  12006.             testGetByteArrayFromAddingShouldReturnNullWhenSameKey2: function () {
  12007.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  12008.                 var key2 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
  12009.                 var bytes = ninja.publicKey.getByteArrayFromAdding(key1, key2);
  12010.                 if (bytes != null) {
  12011.                     return false;
  12012.                 }
  12013.                 return true;
  12014.             },
  12015.             testGetByteArrayFromMultiplying: function () {
  12016.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  12017.                 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
  12018.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
  12019.                 if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
  12020.                     return false;
  12021.                 }
  12022.                 return true;
  12023.             },
  12024.             testGetByteArrayFromMultiplyingCompressedOutputsUncompressed: function () {
  12025.                 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
  12026.                 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
  12027.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
  12028.                 if (bytes.toString() != "4,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57,115,35,54,105,7,180,5,106,217,57,229,127,174,145,215,79,121,163,191,211,143,215,50,48,156,211,178,72,226,68,150,52") {
  12029.                     return false;
  12030.                 }
  12031.                 return true;
  12032.             },
  12033.             testGetByteArrayFromMultiplyingCompressedOutputsCompressed: function () {
  12034.                 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
  12035.                 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
  12036.                 var ecKey = new Bitcoin.ECKey(key2);
  12037.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, ecKey);
  12038.                 if (bytes.toString() != "2,102,230,163,180,107,9,21,17,48,35,245,227,110,199,119,144,57,41,112,64,245,182,40,224,41,230,41,5,26,206,138,57") {
  12039.                     return false;
  12040.                 }
  12041.                 return true;
  12042.             },
  12043.             testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey1: function () {
  12044.                 var key1 = "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44";
  12045.                 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12046.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
  12047.                 if (bytes != null) {
  12048.                     return false;
  12049.                 }
  12050.                 return true;
  12051.             },
  12052.             testGetByteArrayFromMultiplyingShouldReturnNullWhenSameKey2: function () {
  12053.                 var key1 = "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5";
  12054.                 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12055.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(key1, new Bitcoin.ECKey(key2));
  12056.                 if (bytes != null) {
  12057.                     return false;
  12058.                 }
  12059.                 return true;
  12060.             },
  12061.             // confirms multiplication is working and BigInteger was created correctly (Pub Key B vs Priv Key A)
  12062.             testGetPubHexFromMultiplyingPrivAPubB: function () {
  12063.                 var keyPub = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
  12064.                 var keyPriv = "B1202A137E917536B3B4C5010C3FF5DDD4784917B3EEF21D3A3BF21B2E03310C";
  12065.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
  12066.                 var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
  12067.                 if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
  12068.                     return false;
  12069.                 }
  12070.                 return true;
  12071.             },
  12072.             // confirms multiplication is working and BigInteger was created correctly (Pub Key A vs Priv Key B)
  12073.             testGetPubHexFromMultiplyingPrivBPubA: function () {
  12074.                 var keyPub = "0429BF26C0AF7D31D608474CEBD49DA6E7C541B8FAD95404B897643476CE621CFD05E24F7AE8DE8033AADE5857DB837E0B704A31FDDFE574F6ECA879643A0D3709";
  12075.                 var keyPriv = "7DE52819F1553C2BFEDE6A2628B6FDDF03C2A07EB21CF77ACA6C2C3D252E1FD9";
  12076.                 var bytes = ninja.publicKey.getByteArrayFromMultiplying(keyPub, new Bitcoin.ECKey(keyPriv));
  12077.                 var pubHex = ninja.publicKey.getHexFromByteArray(bytes);
  12078.                 if (pubHex != "04C6732006AF4AE571C7758DF7A7FB9E3689DFCF8B53D8724D3A15517D8AB1B4DBBE0CB8BB1C4525F8A3001771FC7E801D3C5986A555E2E9441F1AD6D181356076") {
  12079.                     return false;
  12080.                 }
  12081.                 return true;
  12082.             },
  12083.  
  12084.             // Private Key tests
  12085.             testBadKeyIsNotWif: function () {
  12086.                 return !(Bitcoin.ECKey.isWalletImportFormat("bad key"));
  12087.             },
  12088.             testBadKeyIsNotWifCompressed: function () {
  12089.                 return !(Bitcoin.ECKey.isCompressedWalletImportFormat("bad key"));
  12090.             },
  12091.             testBadKeyIsNotHex: function () {
  12092.                 return !(Bitcoin.ECKey.isHexFormat("bad key"));
  12093.             },
  12094.             testBadKeyIsNotBase64: function () {
  12095.                 return !(Bitcoin.ECKey.isBase64Format("bad key"));
  12096.             },
  12097.             testBadKeyIsNotMini: function () {
  12098.                 return !(Bitcoin.ECKey.isMiniFormat("bad key"));
  12099.             },
  12100.             testBadKeyReturnsNullPrivFromECKey: function () {
  12101.                 var key = "bad key";
  12102.                 var ecKey = new Bitcoin.ECKey(key);
  12103.                 if (ecKey.priv != null) {
  12104.                     return false;
  12105.                 }
  12106.                 return true;
  12107.             },
  12108.             testGetBitcoinPrivateKeyByteArray: function () {
  12109.                 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12110.                 var bytes = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
  12111.                 var btcKey = new Bitcoin.ECKey(key);
  12112.                 if (btcKey.getBitcoinPrivateKeyByteArray().toString() != bytes.toString()) {
  12113.                     return false;
  12114.                 }
  12115.                 return true;
  12116.             },
  12117.             testECKeyDecodeWalletImportFormat: function () {
  12118.                 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12119.                 var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
  12120.                 var bytes2 = Bitcoin.ECKey.decodeWalletImportFormat(key);
  12121.                 if (bytes1.toString() != bytes2.toString()) {
  12122.                     return false;
  12123.                 }
  12124.                 return true;
  12125.             },
  12126.             testECKeyDecodeCompressedWalletImportFormat: function () {
  12127.                 var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12128.                 var bytes1 = [41, 38, 101, 195, 135, 36, 24, 173, 241, 218, 127, 250, 58, 100, 111, 47, 6, 2, 36, 109, 166, 9, 138, 145, 210, 41, 195, 33, 80, 242, 113, 139];
  12129.                 var bytes2 = Bitcoin.ECKey.decodeCompressedWalletImportFormat(key);
  12130.                 if (bytes1.toString() != bytes2.toString()) {
  12131.                     return false;
  12132.                 }
  12133.                 return true;
  12134.             },
  12135.             testWifToPubKeyHex: function () {
  12136.                 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12137.                 var btcKey = new Bitcoin.ECKey(key);
  12138.                 if (btcKey.getPubKeyHex() != "0478982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB521F054FAD982AF4CC1933AFD1F1B563EA779A6AA6CCE36A30B947DD653E63E44"
  12139.                     || btcKey.getPubPoint().compressed != false) {
  12140.                 return false;
  12141.             }
  12142.             return true;
  12143.         },
  12144.         testWifToPubKeyHexCompressed: function () {
  12145.             var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12146.             var btcKey = new Bitcoin.ECKey(key);
  12147.             btcKey.setCompressed(true);
  12148.             if (btcKey.getPubKeyHex() != "0278982F40FA0C0B7A55717583AFC99A4EDFD301A2729DC59B0B8EB9E18692BCB5"
  12149.                     || btcKey.getPubPoint().compressed != true) {
  12150.                 return false;
  12151.             }
  12152.             return true;
  12153.         },
  12154.         testBase64ToECKey: function () {
  12155.             var key = "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=";
  12156.             var btcKey = new Bitcoin.ECKey(key);
  12157.             if (btcKey.getBitcoinBase64Format() != "KSZlw4ckGK3x2n/6OmRvLwYCJG2mCYqR0inDIVDycYs=") {
  12158.                 return false;
  12159.             }
  12160.             return true;
  12161.         },
  12162.         testHexToECKey: function () {
  12163.             var key = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
  12164.             var btcKey = new Bitcoin.ECKey(key);
  12165.             if (btcKey.getBitcoinHexFormat() != "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B") {
  12166.                 return false;
  12167.             }
  12168.             return true;
  12169.         },
  12170.         testCompressedWifToECKey: function () {
  12171.             var key = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12172.             var btcKey = new Bitcoin.ECKey(key);
  12173.             if (btcKey.getBitcoinWalletImportFormat() != "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S"
  12174.                     || btcKey.getPubPoint().compressed != true) {
  12175.                     return false;
  12176.                 }
  12177.                 return true;
  12178.             },
  12179.             testWifToECKey: function () {
  12180.                 var key = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12181.                 var btcKey = new Bitcoin.ECKey(key);
  12182.                 if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
  12183.                     return false;
  12184.                 }
  12185.                 return true;
  12186.             },
  12187.             testBrainToECKey: function () {
  12188.                 var key = "bitaddress.org unit test";
  12189.                 var bytes = Crypto.SHA256(key, { asBytes: true });
  12190.                 var btcKey = new Bitcoin.ECKey(bytes);
  12191.                 if (btcKey.getBitcoinWalletImportFormat() != "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb") {
  12192.                     return false;
  12193.                 }
  12194.                 return true;
  12195.             },
  12196.             testMini30CharsToECKey: function () {
  12197.                 var key = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
  12198.                 var btcKey = new Bitcoin.ECKey(key);
  12199.                 if (btcKey.getBitcoinWalletImportFormat() != "5JrBLQseeZdYw4jWEAHmNxGMr5fxh9NJU3fUwnv4khfKcg2rJVh") {
  12200.                     return false;
  12201.                 }
  12202.                 return true;
  12203.             },
  12204.             testGetECKeyFromAdding: function () {
  12205.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12206.                 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
  12207.                 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
  12208.                 if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
  12209.                     return false;
  12210.                 }
  12211.                 return true;
  12212.             },
  12213.             testGetECKeyFromAddingCompressed: function () {
  12214.                 var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12215.                 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
  12216.                 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
  12217.                 if (ecKey.getBitcoinWalletImportFormat() != "L3A43j2pc2J8F2SjBNbYprPrcDpDCh8Aju8dUH65BEM2r7RFSLv4") {
  12218.                     return false;
  12219.                 }
  12220.                 return true;
  12221.             },
  12222.             testGetECKeyFromAddingUncompressedAndCompressed: function () {
  12223.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12224.                 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
  12225.                 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
  12226.                 if (ecKey.getBitcoinWalletImportFormat() != "5KAJTSqSjpsZ11KyEE3qu5PrJVjR4ZCbNxK3Nb1F637oe41m1c2") {
  12227.                     return false;
  12228.                 }
  12229.                 return true;
  12230.             },
  12231.             testGetECKeyFromAddingShouldReturnNullWhenSameKey1: function () {
  12232.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12233.                 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12234.                 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
  12235.                 if (ecKey != null) {
  12236.                     return false;
  12237.                 }
  12238.                 return true;
  12239.             },
  12240.             testGetECKeyFromAddingShouldReturnNullWhenSameKey2: function () {
  12241.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12242.                 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12243.                 var ecKey = ninja.privateKey.getECKeyFromAdding(key1, key2);
  12244.                 if (ecKey != null) {
  12245.                     return false;
  12246.                 }
  12247.                 return true;
  12248.             },
  12249.             testGetECKeyFromMultiplying: function () {
  12250.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12251.                 var key2 = "SQE6yipP5oW8RBaStWoB47xsRQ8pat";
  12252.                 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
  12253.                 if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
  12254.                     return false;
  12255.                 }
  12256.                 return true;
  12257.             },
  12258.             testGetECKeyFromMultiplyingCompressed: function () {
  12259.                 var key1 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12260.                 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
  12261.                 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
  12262.                 if (ecKey.getBitcoinWalletImportFormat() != "L5LFitc24jme2PfVChJS3bKuQAPBp54euuqLWciQdF2CxnaU3M8t") {
  12263.                     return false;
  12264.                 }
  12265.                 return true;
  12266.             },
  12267.             testGetECKeyFromMultiplyingUncompressedAndCompressed: function () {
  12268.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12269.                 var key2 = "L1n4cgNZAo2KwdUc15zzstvo1dcxpBw26NkrLqfDZtU9AEbPkLWu";
  12270.                 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
  12271.                 if (ecKey.getBitcoinWalletImportFormat() != "5KetpZ5mCGagCeJnMmvo18n4iVrtPSqrpnW5RP92Gv2BQy7GPCk") {
  12272.                     return false;
  12273.                 }
  12274.                 return true;
  12275.             },
  12276.             testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey1: function () {
  12277.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12278.                 var key2 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12279.                 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
  12280.                 if (ecKey != null) {
  12281.                     return false;
  12282.                 }
  12283.                 return true;
  12284.             },
  12285.             testGetECKeyFromMultiplyingShouldReturnNullWhenSameKey2: function () {
  12286.                 var key1 = "5J8QhiQtAiozKwyk3GCycAscg1tNaYhNdiiLey8vaDK8Bzm4znb";
  12287.                 var key2 = "KxbhchnQquYQ2dfSxz7rrEaQTCukF4uCV57TkamyTbLzjFWcdi3S";
  12288.                 var ecKey = ninja.privateKey.getECKeyFromMultiplying(key1, key2);
  12289.                 if (ecKey != null) {
  12290.                     return false;
  12291.                 }
  12292.                 return true;
  12293.             },
  12294.             testGetECKeyFromBase6Key: function () {
  12295.                 var baseKey = "100531114202410255230521444145414341221420541210522412225005202300434134213212540304311321323051431";
  12296.                 var hexKey = "292665C3872418ADF1DA7FFA3A646F2F0602246DA6098A91D229C32150F2718B";
  12297.                 var ecKey = new Bitcoin.ECKey(baseKey);
  12298.                 if (ecKey.getBitcoinHexFormat() != hexKey) {
  12299.                     return false;
  12300.                 }
  12301.                 return true;
  12302.             },
  12303.  
  12304.             // EllipticCurve tests
  12305.             testDecodePointEqualsDecodeFrom: function () {
  12306.                 var key = "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF";
  12307.                 var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  12308.                 var ecPoint1 = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), Crypto.util.hexToBytes(key));
  12309.                 var ecPoint2 = ecparams.getCurve().decodePointHex(key);
  12310.                 if (!ecPoint1.equals(ecPoint2)) {
  12311.                     return false;
  12312.                 }
  12313.                 return true;
  12314.             },
  12315.             testDecodePointHexForCompressedPublicKey: function () {
  12316.                 var key = "03F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F989380";
  12317.                 var pubHexUncompressed = ninja.publicKey.getDecompressedPubKeyHex(key);
  12318.                 if (pubHexUncompressed != "04F04BF260DCCC46061B5868F60FE962C77B5379698658C98A93C3129F5F98938020F36EBBDE6F1BEAF98E5BD0E425747E68B0F2FB7A2A59EDE93F43C0D78156FF") {
  12319.                     return false;
  12320.                 }
  12321.                 return true;
  12322.             },
  12323.             // old bugs
  12324.             testBugWithLeadingZeroBytePublicKey: function () {
  12325.                 var key = "5Je7CkWTzgdo1RpwjYhwnVKxQXt8EPRq17WZFtWcq5umQdsDtTP";
  12326.                 var btcKey = new Bitcoin.ECKey(key);
  12327.                 if (btcKey.getBitcoinAddress() != "1M6dsMZUjFxjdwsyVk8nJytWcfr9tfUa9E") {
  12328.                     return false;
  12329.                 }
  12330.                 return true;
  12331.             },
  12332.             testBugWithLeadingZeroBytePrivateKey: function () {
  12333.                 var key = "0004d30da67214fa65a41a6493576944c7ea86713b14db437446c7a8df8e13da";
  12334.                 var btcKey = new Bitcoin.ECKey(key);
  12335.                 if (btcKey.getBitcoinAddress() != "1NAjZjF81YGfiJ3rTKc7jf1nmZ26KN7Gkn") {
  12336.                     return false;
  12337.                 }
  12338.                 return true;
  12339.             }
  12340.         },
  12341.  
  12342.         asynchronousTests: {
  12343.             //https://en.bitcoin.it/wiki/BIP_0038
  12344.             testBip38: function (done) {
  12345.                 var tests = [
  12346.                 //No compression, no EC multiply
  12347.                     ["6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg", "TestingOneTwoThree", "5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR"],
  12348.                     ["6PRNFFkZc2NZ6dJqFfhRoFNMR9Lnyj7dYGrzdgXXVMXcxoKTePPX1dWByq", "Satoshi", "5HtasZ6ofTHP6HCwTqTkLDuLQisYPah7aUnSKfC7h4hMUVw2gi5"],
  12349.                 //Compression, no EC multiply
  12350.                     ["6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo", "TestingOneTwoThree", "L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP"],
  12351.                     ["6PYLtMnXvfG3oJde97zRyLYFZCYizPU5T3LwgdYJz1fRhh16bU7u6PPmY7", "Satoshi", "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7"],
  12352.                 //EC multiply, no compression, no lot/sequence numbers
  12353.                     ["6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", "TestingOneTwoThree", "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2"],
  12354.                     ["6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", "Satoshi", "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH"],
  12355.                 //EC multiply, no compression, lot/sequence numbers
  12356.                     ["6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", "MOLON LABE", "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8"],
  12357.                     ["6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH", Crypto.charenc.UTF8.bytesToString([206, 156, 206, 159, 206, 155, 206, 169, 206, 157, 32, 206, 155, 206, 145, 206, 146, 206, 149])/*UTF-8 characters, encoded in source so they don't get corrupted*/, "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D"]];
  12358.  
  12359.                 // running each test uses a lot of memory, which isn't freed
  12360.                 // immediately, so give the VM a little time to reclaim memory
  12361.                 function waitThenCall(callback) {
  12362.                     return function () { setTimeout(callback, 10000); }
  12363.                 }
  12364.  
  12365.                 var decryptTest = function (test, i, onComplete) {
  12366.                     ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(test[0], test[1], function (privBytes) {
  12367.                         if (privBytes.constructor == Error) {
  12368.                             document.getElementById("asyncunittestresults").innerHTML += "fail testDecryptBip38 #" + i + ", error: " + privBytes.message + "<br/>";
  12369.                         } else {
  12370.                             var btcKey = new Bitcoin.ECKey(privBytes);
  12371.                             var wif = !test[2].substr(0, 1).match(/[LK]/) ? btcKey.setCompressed(false).getBitcoinWalletImportFormat() : btcKey.setCompressed(true).getBitcoinWalletImportFormat();
  12372.                             if (wif != test[2]) {
  12373.                                 document.getElementById("asyncunittestresults").innerHTML += "fail testDecryptBip38 #" + i + "<br/>";
  12374.                             } else {
  12375.                                 document.getElementById("asyncunittestresults").innerHTML += "pass testDecryptBip38 #" + i + "<br/>";
  12376.                             }
  12377.                         }
  12378.                         onComplete();
  12379.                     });
  12380.                 };
  12381.  
  12382.                 var encryptTest = function (test, compressed, i, onComplete) {
  12383.                     ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(test[2], test[1], compressed, function (encryptedKey) {
  12384.                         if (encryptedKey === test[0]) {
  12385.                             document.getElementById("asyncunittestresults").innerHTML += "pass testBip38Encrypt #" + i + "<br/>";
  12386.                         } else {
  12387.                             document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Encrypt #" + i + "<br/>";
  12388.                             document.getElementById("asyncunittestresults").innerHTML += "expected " + test[0] + "<br/>received " + encryptedKey + "<br/>";
  12389.                         }
  12390.                         onComplete();
  12391.                     });
  12392.                 };
  12393.  
  12394.                 // test randomly generated encryption-decryption cycle
  12395.                 var cycleTest = function (i, compress, onComplete) {
  12396.                     // create new private key
  12397.                     var privKey = (new Bitcoin.ECKey(false)).getBitcoinWalletImportFormat();
  12398.  
  12399.                     // encrypt private key
  12400.                     ninja.privateKey.BIP38PrivateKeyToEncryptedKeyAsync(privKey, 'testing', compress, function (encryptedKey) {
  12401.                         // decrypt encryptedKey
  12402.                         ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(encryptedKey, 'testing', function (decryptedBytes) {
  12403.                             var decryptedKey = (new Bitcoin.ECKey(decryptedBytes)).getBitcoinWalletImportFormat();
  12404.  
  12405.                             if (decryptedKey === privKey) {
  12406.                                 document.getElementById("asyncunittestresults").innerHTML += "pass cycleBip38 test #" + i + "<br/>";
  12407.                             }
  12408.                             else {
  12409.                                 document.getElementById("asyncunittestresults").innerHTML += "fail cycleBip38 test #" + i + " " + privKey + "<br/>";
  12410.                                 document.getElementById("asyncunittestresults").innerHTML += "encrypted key: " + encryptedKey + "<br/>decrypted key: " + decryptedKey;
  12411.                             }
  12412.                             onComplete();
  12413.                         });
  12414.                     });
  12415.                 };
  12416.  
  12417.                 // intermediate test - create some encrypted keys from an intermediate
  12418.                 // then decrypt them to check that the private keys are recoverable
  12419.                 var intermediateTest = function (i, onComplete) {
  12420.                     var pass = Math.random().toString(36).substr(2);
  12421.                     ninja.privateKey.BIP38GenerateIntermediatePointAsync(pass, null, null, function (intermediatePoint) {
  12422.                         ninja.privateKey.BIP38GenerateECAddressAsync(intermediatePoint, false, function (address, encryptedKey) {
  12423.                             ninja.privateKey.BIP38EncryptedKeyToByteArrayAsync(encryptedKey, pass, function (privBytes) {
  12424.                                 if (privBytes.constructor == Error) {
  12425.                                     document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Intermediate #" + i + ", error: " + privBytes.message + "<br/>";
  12426.                                 } else {
  12427.                                     var btcKey = new Bitcoin.ECKey(privBytes);
  12428.                                     var btcAddress = btcKey.getBitcoinAddress();
  12429.                                     if (address !== btcKey.getBitcoinAddress()) {
  12430.                                         document.getElementById("asyncunittestresults").innerHTML += "fail testBip38Intermediate #" + i + "<br/>";
  12431.                                     } else {
  12432.                                         document.getElementById("asyncunittestresults").innerHTML += "pass testBip38Intermediate #" + i + "<br/>";
  12433.                                     }
  12434.                                 }
  12435.                                 onComplete();
  12436.                             });
  12437.                         });
  12438.                     });
  12439.                 }
  12440.  
  12441.                 document.getElementById("asyncunittestresults").innerHTML += "running " + tests.length + " tests named testDecryptBip38<br/>";
  12442.                 document.getElementById("asyncunittestresults").innerHTML += "running 4 tests named testBip38Encrypt<br/>";
  12443.                 document.getElementById("asyncunittestresults").innerHTML += "running 2 tests named cycleBip38<br/>";
  12444.                 document.getElementById("asyncunittestresults").innerHTML += "running 5 tests named testBip38Intermediate<br/>";
  12445.                 ninja.runSerialized([
  12446.                     function (cb) {
  12447.                         ninja.forSerialized(0, tests.length, function (i, callback) {
  12448.                             decryptTest(tests[i], i, waitThenCall(callback));
  12449.                         }, waitThenCall(cb));
  12450.                     },
  12451.                     function (cb) {
  12452.                         ninja.forSerialized(0, 4, function (i, callback) {
  12453.                             // only first 4 test vectors are not EC-multiply,
  12454.                             // compression param false for i = 1,2 and true for i = 3,4
  12455.                             encryptTest(tests[i], i >= 2, i, waitThenCall(callback));
  12456.                         }, waitThenCall(cb));
  12457.                     },
  12458.                     function (cb) {
  12459.                         ninja.forSerialized(0, 2, function (i, callback) {
  12460.                             cycleTest(i, i % 2 ? true : false, waitThenCall(callback));
  12461.                         }, waitThenCall(cb));
  12462.                     },
  12463.                     function (cb) {
  12464.                         ninja.forSerialized(0, 5, function (i, callback) {
  12465.                             intermediateTest(i, waitThenCall(callback));
  12466.                         }, cb);
  12467.                     }
  12468.                 ], done);
  12469.             }
  12470.         }
  12471.     };
  12472. })(ninja);
  12473. </script>
  12474.  
  12475. <script type="text/javascript">
  12476.     // run unit tests
  12477.     if (ninja.getQueryString()["unittests"] == "true" || ninja.getQueryString()["unittests"] == "1") {
  12478.         ninja.unitTests.runSynchronousTests();
  12479.         // ninja.translator.showEnglishJson();
  12480.         // no need to show translations until we actually have some. 9/5/2013 - Canton
  12481.     }
  12482.     // run async unit tests
  12483.     if (ninja.getQueryString()["asyncunittests"] == "true" || ninja.getQueryString()["asyncunittests"] == "1") {
  12484.         ninja.unitTests.runAsynchronousTests();
  12485.     }
  12486.     // change language
  12487.     if (ninja.getQueryString()["culture"] != undefined) {
  12488.         ninja.translator.translate(ninja.getQueryString()["culture"]);
  12489.     }
  12490.  
  12491.     if (ninja.getQueryString()["showseedpool"] == "true" || ninja.getQueryString()["showseedpool"] == "1") {
  12492.         document.getElementById("seedpoolarea").style.display = "block";
  12493.     }
  12494. </script>
  12495.  
  12496. <script type="text/javascript">
  12497.  
  12498.     /********************************************************
  12499.      Brand new JS functions added for bitcoinpaperwallet.com
  12500.      ********************************************************/
  12501.  
  12502.     var inlineMediaStyle = null;
  12503.  
  12504.     function printZoom (changeBy) { /* handle +/- buttons for print zoom */
  12505.         var currentZoom = document.getElementById("printerzoom").value * 1;
  12506.         document.getElementById("printerzoom").value = currentZoom + changeBy;
  12507.         updateCalibrationInfo();
  12508.     }
  12509.  
  12510.     function printShift (changeBy) { /* handle +/- buttons for print shift */
  12511.         var currentShift = document.getElementById("printershift").value * 1;
  12512.         document.getElementById("printershift").value = currentShift + changeBy;
  12513.         updateCalibrationInfo();
  12514.     }
  12515.  
  12516.     // apply the printer zoom & shift values as !important <head> styles
  12517.     // thanks http://stackoverflow.com/questions/798535/changing-media-specific-css-properties-from-javascript
  12518.     function updateCalibrationInfo() {
  12519.  
  12520.         var currentZoom = document.getElementById("printerzoom").value;
  12521.         var currentShift = document.getElementById("printershift").value;
  12522.         // first write values onto printable area for reference
  12523.         document.getElementById("calibrationinfo").innerHTML="Zoom: " + currentZoom + " / Horizontal shift: " + currentShift;
  12524.         // now update the @print style accordingly
  12525.         var head = document.getElementsByTagName('head')[0];
  12526.         var printerStyle = document.createElement('style');
  12527.         printerStyle.setAttribute('type', 'text/css');
  12528.         printerStyle.setAttribute('media', 'print');
  12529.         printerStyle.appendChild(document.createTextNode('body { width: ' + ( 950 + (currentZoom * 10)) + 'px !important;} #main { left: ' + ((currentShift * 5)) + 'px !important;}'));
  12530.  
  12531.         if (inlineMediaStyle != null) {
  12532.             head.replaceChild(printerStyle, inlineMediaStyle)
  12533.         } else {
  12534.             head.appendChild(printerStyle);
  12535.         }
  12536.         inlineMediaStyle = printerStyle;
  12537.     }
  12538.    
  12539.     var printCounter=0;
  12540.     var landscapeAlert=0;
  12541.    
  12542.     function doPrint(myContext) { /* What to do anytime a print button is clicked */
  12543.         window.landscapeAlert ++;
  12544.         updateCalibrationInfo();
  12545.         if (window.landscapeAlert == 1) {
  12546.             alert ('Important note: This design requires that you set your printer to output in LANDSCAPE (wide) format.');
  12547.         }
  12548.        
  12549.         if (myContext == 'generate') {
  12550.             window.printCounter ++;
  12551.             if (window.printCounter == 2) {
  12552.                 alert (" *** WARNING *** WARNING *** WARNING *** \n\nYou are about to print a second wallet with the same set of keys. \n\nUnless you intended to make a backup wallet, cancel this print job and generate a fresh set of keys.");
  12553.             }
  12554.         }
  12555.         window.print();
  12556.     }
  12557.    
  12558.     function testAndApplyVanityKey() { /* Verify that a self-entered key is valid, and compute the corresponding public address, render the wallet. */
  12559.         var suppliedKey = document.getElementById('suppliedPrivateKey').value;
  12560.         suppliedKey = suppliedKey.trim(); // in case any spaces or whitespace got pasted in
  12561.         document.getElementById('suppliedPrivateKey').value = suppliedKey;
  12562.         if (!ninja.privateKey.isPrivateKey(suppliedKey)) {
  12563.             var message = 'What you entered does not appear to be a Darkcoin Wallet Import Format (WIF) private key.';
  12564.             if (suppliedKey == null || suppliedKey.length == 0) {
  12565.                 alert(message);
  12566.                 return;
  12567.             }
  12568.             if (suppliedKey.length < ninja.wallets.paperwallet.minPassphraseLength) {
  12569.                 alert(message + '\n\nIf you would like to use this text as a random data source or "brain wallet" passphrase, please supply a longer input.');
  12570.                 return;
  12571.             }
  12572.             if (confirm(message + '\n\nClick OK to interpret this text as a random data source or "brain wallet" passphrase from which a keypair will be computed.')) {
  12573.                 var wallet = new Bitcoin.ECKey(Crypto.SHA256(suppliedKey, { asBytes: true }));
  12574.                 var computedPublicAddress = wallet.getBitcoinAddress();
  12575.                 var privateKey = wallet.getBitcoinWalletImportFormat();
  12576.                 ninja.wallets.paperwallet.buildManual({ address: computedPublicAddress, wifKey: privateKey }, document.getElementById('paperpassphrase').value);
  12577.             }
  12578.         } else {           
  12579.             var computedPublicAddress = new Bitcoin.ECKey(suppliedKey).getBitcoinAddress();
  12580.             alert ('OK! This is a valid WIF-format private key whose public address is:\r\r'+computedPublicAddress);
  12581.             ninja.wallets.paperwallet.buildManual({ address: computedPublicAddress, wifKey: suppliedKey }, document.getElementById('paperpassphrase').value);
  12582.             window.printCounter = 0;
  12583.         }
  12584.     }
  12585.  
  12586.     function guessPrinterSettings() {
  12587.         // detect browser / OS human-readable
  12588.         txt = "<p><small style=\"color: #666666;\"><b>User-agent:</b> " + navigator.userAgent + "</small><br />&nbsp;<br />";
  12589.         var parser = new UAParser();
  12590.         parser.setUA(navigator.userAgent);
  12591.         var result = parser.getResult();
  12592.         txt+=result.browser.name + " version " + result.browser.version + " (" + result.engine.name + ")<br />";
  12593.         txt+=result.os.name + " version " + result.os.version + " (" + result.cpu.architecture + ")<br />";
  12594.         txt += "</p>";
  12595.         document.getElementById("browserinfo").innerHTML=txt;
  12596.        
  12597.         // some common printer calibration settings here
  12598.         if (result.browser.name == 'Safari') { // OS X Safari
  12599.             document.getElementById("printerzoom").value = 5;
  12600.             document.getElementById("printershift").value = 6;
  12601.         } else if (result.browser.name == 'Chrome' && result.os.name == 'Mac OS X') {
  12602.             document.getElementById("printerzoom").value = 3;
  12603.             document.getElementById("printershift").value = 3;
  12604.         } else if (result.browser.name == 'Firefox' && result.os.name == 'Ubuntu') { // live CD?
  12605.             document.getElementById("printerzoom").value = 2;
  12606.             document.getElementById("printershift").value = 3;
  12607.         } else if (result.browser.name == 'Iceweasel' && result.os.name == 'Debian') {
  12608.             document.getElementById("printerzoom").value = 1.8;
  12609.             document.getElementById("printershift").value = 2.9;
  12610.         } else if (result.browser.name == 'IE' && result.os.name == 'Windows') {
  12611.             document.getElementById("printerzoom").value = 5;
  12612.             document.getElementById("printershift").value = 6;
  12613.         }
  12614.  
  12615.         updateCalibrationInfo();
  12616.     }
  12617.  
  12618. function setDesign (whichDesign, isOnLoad) {
  12619.     if (!whichDesign) whichDesign = 'default'; 
  12620.     // if we used the dropdown menu to select an alt-coin, we need to reload the page altogether.
  12621.     if (!isOnLoad && whichDesign.substring(0,4) == 'alt-') window.location='?design=' + whichDesign;
  12622.     // if we're already using an altcoin, reload the page no matter which design we choose.
  12623.     if (!isOnLoad && window.networkVersion != 0x00 ) window.location='?design=' + whichDesign;
  12624.  
  12625.     // reload background and add altcoin donation addresses if necessary
  12626.     if (isOnLoad && whichDesign.substring(0,4) == 'alt-') {
  12627.         document.getElementById('logoback').style.backgroundImage = 'url(images/logo-' + whichDesign + '.png)';
  12628.     }
  12629.  
  12630.     if (whichDesign == 'default') {
  12631.         var myFront = './images/front-300dpi.jpg';
  12632.         var myBack = './images/back-300dpi.jpg';
  12633.         var myPreview = './images/finished-sample-sealed.jpg';
  12634.     } else {
  12635.         var myFront = './images/front-300dpi-' + whichDesign + '.jpg';
  12636.         var myBack = './images/back-300dpi-' + whichDesign + '.jpg';
  12637.         var myPreview = './images/finished-sample-' + whichDesign + '.jpg';
  12638.     }
  12639.     window.frontJPG=myFront;
  12640.     if (document.getElementById('papersvg1') != null) document.getElementById('papersvg1').src=myFront;
  12641.     // document.getElementById('backsvg1').src=myBack;
  12642.     // document.getElementById('designPreview').src=myPreview;
  12643.     // document.getElementById('designPicker').value = whichDesign; // force menu option in case it was picked during onload.
  12644.     ninja.seeder.seedCount = ninja.seeder.seedLimit; ninja.seeder.seed();
  12645. }
  12646.  
  12647. </script>
  12648.  
  12649.  
  12650.  
  12651. </b></b></body></html>
Add Comment
Please, Sign In to add comment