diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..28e71bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+bower_components
+dist
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..a927593
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,40 @@
+{
+ "camelcase": false,
+ "curly": true,
+ "forin": false,
+ "latedef": "nofunc",
+ "newcap": false,
+ "noarg": true,
+ "nonew": true,
+ "quotmark": "single",
+ "undef": true,
+ "unused": "vars",
+ "strict": true,
+ "trailing": true,
+ "maxlen": 80,
+
+ "eqnull": true,
+ "esnext": true,
+ "expr": true,
+ "globalstrict": true,
+
+ "maxerr": 1000,
+ "regexdash": true,
+ "laxcomma": true,
+ "proto": true,
+
+ "browser": true,
+ "devel": true,
+ "nonstandard": true,
+ "worker": true,
+ "bitwise": true,
+
+ "-W078": true,
+
+ "globals": {
+ "require" : false,
+ "module" : false,
+ "define" : false,
+ "global" : false
+ }
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..328faf1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 - Vincent Cassé
+
+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:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5080c0f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+# Amaretti.js
+
+Amaretti.js is a library to encrypt and decrypt message into the browser. They use native implementation (WebCrypto APIs) when available, or SJCL library when not.
+
+## Getting started
+
+### Installation
+
+This library can be installed with npm or bower, as you prefer:
+
+```bash
+bower install amaretti
+```
+
+```bash
+npm install amaretti
+```
+
+### How to use it
+
+Just import the javascript file and require the library. Require system is included into amaretti library
+
+```html
+
+
+var Amaretti = require('amaretti').init();
+```
+
+### Generate a salt
+
+Salt are used into key generation and to randomize the encryption of a message. You can get a base64 salt using this `Amaretti.getSalt()`
+
+```javascript
+Amaretti.getSalt().then(function(salt) {
+ // Manipulate your salt
+}, function (error) {
+ // There was an error
+});
+```
+
+### Generate a key
+
+To encrypt or decrypt messages, you need to use a key. You can generate a key usable with a passphrase (like a password). Key generated is returned as base64. To randomize the generation, you need to give a salt and a hash algorithm
+
+```javascript
+Amaretti.generateKey(passphrase, salt, hash).then(function(key) {
+ // Manipulate your key
+}, function (error) {
+ // There was an error
+});
+```
+ * __passphrase__: is the passphrase used to encrypt or decrypt messages
+ * __salt__: is the salt, base64 encoded, used to randomize the key generator
+ * __hash__: is the name of algorithm used to hash the key. It could be _SHA-1_ or _SHA-256_
+
+### Encrypt a message
+
+You can encrypt a message with your key. Amaretti use AES-GCM to encrypt data. To avoid brut-force attack agains the encrypted data, each data had to be encrypt with a different and random nonce. You can use a salt as nonce. Don't lose this nonce, you will need it to decrypt the message.
+
+```javascript
+Amaretti.encrypt(key, message, nonce).then(function(encrypted) {
+ // Manipulate your encrypted message
+}, function (error) {
+ // There was an error
+});
+```
+ * __key__: is the base64 used to encrypt message
+ * __message__: is the message to encrypt
+ * __nonce__: is a random value, in base64 format, use to avoid attacks
+
+### Decrypt a message
+
+```javascript
+Amaretti..decrypt(key, encrypted, nonce).then(function(decrypted) {
+ // Manipulate your encrypted message
+}, function (error) {
+ // There was an error
+});
+```
+
+ * __key__: is the base64 used to encrypt message
+ * __encrypted: is the encrypted message to decrypt, in base64 format
+ * __nonce__: is a random value, in base64 format, use to avoid attacks
+
+## License
+
+MIT
+
+## How to contribute
+
+Hum ... on github :)
+
+### To build library
+
+```bash
+npm install
+bower install
+brunch build
+```
+
+### To run tests
+
+```bash
+npm run test
+```
+
+## Ideas for a roadmap
+
+* Return key and crypted data with JOSE standard (JWE and JWT)
+* Check sha-256 for firefox and sha-1 for SJCL ito key generation
diff --git a/app/amaretti.js b/app/amaretti.js
new file mode 100644
index 0000000..d60878b
--- /dev/null
+++ b/app/amaretti.js
@@ -0,0 +1,339 @@
+"use strict";
+
+var encode = function(str) {
+ return new TextEncoder('utf-8').encode(str);
+};
+var decode = function(buf) {
+ return new TextDecoder('utf-8').decode(new Uint8Array(buf));
+};
+/*var ab2str = function(buf) {
+ return String.fromCharCode.apply(null, new Uint16Array(buf));
+};*/
+function b64ToUint6 (nChr) {
+
+ return nChr > 64 && nChr < 91 ?
+ nChr - 65
+ : nChr > 96 && nChr < 123 ?
+ nChr - 71
+ : nChr > 47 && nChr < 58 ?
+ nChr + 4
+ : nChr === 43 ?
+ 62
+ : nChr === 47 ?
+ 63
+ :
+ 0;
+
+}
+
+function arrayBufferToBase64 (arrayBuffer) {
+ return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
+}
+/**
+* TODO add better way to use atob whe possible
+*/
+//https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer
+function base64ToArrayByte(sBase64, nBlocksSize) {
+
+ var
+ sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
+ nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
+
+ for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
+ nMod4 = nInIdx & 3;
+ nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
+ if (nMod4 === 3 || nInLen - nInIdx === 1) {
+ for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
+ taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
+ }
+ nUint24 = 0;
+
+ }
+ }
+
+ return taBytes;
+
+}
+var arrayByteToBase64 = function(arrayByte) {
+ //http://stackoverflow.com/a/12713326
+ var CHUNK_SZ = 0x8000;
+ var c = [];
+ for (var i = 0; i < arrayByte.length; i += CHUNK_SZ) {
+ c.push(String.fromCharCode.apply(
+ null,
+ arrayByte.subarray(i, i + CHUNK_SZ)
+ ));
+ }
+ return btoa(c.join(''));
+};
+
+var Amaretti = {
+
+ authTagLength : 128,
+ paranoia: 10,
+ iterations: 5000,
+ enableNative: true,
+
+ init: function (opts) {
+ this.authTagUsedSpace = this.authTagLength / 4;
+ sjcl.random.startCollectors();
+
+ if (opts) {
+ this.iterations = opts.iterations ? opts.iterations : 5000;
+ this.enableNative = opts.enableNative !== undefined ? opts.enableNative : true;
+ }
+ return this;
+ },
+
+ getCrypto: function() {
+ return window.crypto || window.msCrypto;
+ },
+
+ getSalt: function() {
+ var origSalt;
+ var salt;
+ return new Promise(function(resolve, reject) {
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().getRandomValues) {
+ try {
+ origSalt = Amaretti.getCrypto().getRandomValues(new Uint8Array(64));
+ salt = arrayByteToBase64(origSalt);
+ resolve(salt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ return;
+ }
+
+ if (sjcl.random.isReady(Amaretti.paranoia) === 0) {
+ reject('sjcl random is not ready');
+ return;
+ }
+ try {
+ origSalt = sjcl.random.randomWords(8, Amaretti.paranoia);
+ salt = sjcl.codec.base64.fromBits(origSalt);
+ resolve(salt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ },
+
+ generateKey: function(passphrase, salt, algo) {
+ if (!algo) {
+ return new Promise(function(resolve, reject) {
+ reject('Please add an algo');
+ });
+ }
+
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.deriveKey &&
+ Amaretti.getCrypto().subtle.exportKey) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ encode(passphrase),
+ { name: 'PBKDF2' },
+ false,
+ ['deriveKey']
+ ).then(function(baseKey) {
+
+ var cryptoAlgo;
+ if (algo === 'SHA-1') {
+ cryptoAlgo = 'SHA-1';
+ } else if (algo === 'SHA-256') {
+ throw 'SHA-256 is not yet available on firefox';
+ } else {
+ throw 'Your algo is not available';
+ }
+
+ return Amaretti.getCrypto().subtle.deriveKey(
+ {
+ name: 'PBKDF2',
+ hash: cryptoAlgo,
+ salt: base64ToArrayByte(salt),
+ iterations: Amaretti.iterations
+ },
+ baseKey,
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (key) {
+ return Amaretti.getCrypto().subtle.exportKey('raw', key)
+ .then(function (rawKey) {
+ return new Promise(function(resolve, reject) {
+ try {
+ resolve(arrayByteToBase64(new Uint8Array(rawKey)));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var sjclAlgo;
+
+ if (algo === 'SHA-1') {
+ sjclAlgo = function (key) {
+ // todo sha-1
+ var hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );
+ this.encrypt = function () {
+ return hasher.encrypt.apply( hasher, arguments );
+ };
+ };
+ } else if (algo === 'SHA-256') {
+ sjclAlgo = function (key) {
+ var hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );
+ this.encrypt = function () {
+ return hasher.encrypt.apply( hasher, arguments );
+ };
+ };
+ } else {
+ throw 'Your algo is not available';
+ }
+
+ var key = sjcl.misc.pbkdf2(
+ passphrase,
+ sjcl.codec.base64.toBits(salt),
+ Amaretti.iterations,
+ 256,
+ sjclAlgo
+ );
+ // TODO fix SHA1
+ // https://github.com/bitwiseshiftleft/sjcl/issues/75
+ resolve(sjcl.codec.base64.fromBits(key));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ },
+
+ encrypt: function(key, message, nonce) {
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.encrypt) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ base64ToArrayByte(key),
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (rawKey) {
+
+ return Amaretti.getCrypto().subtle.encrypt(
+ {
+ name: 'AES-GCM',
+ iv: base64ToArrayByte(nonce),
+ tagLength: Amaretti.authTagLength
+ },
+ rawKey,
+ encode(message)
+ ).then(function (crypted) {
+ return new Promise(function (resolve, reject) {
+ try {
+ resolve(arrayBufferToBase64(crypted));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var rawKey = sjcl.codec.base64.toBits(key);
+ var rawNonce = sjcl.codec.base64.toBits(nonce);
+ var keyAES = new sjcl.cipher.aes(rawKey);
+ var crypt = sjcl.mode.gcm.encrypt(
+ keyAES,
+ sjcl.codec.utf8String.toBits(message),
+ rawNonce,
+ sjcl.codec.utf8String.toBits(Amaretti.authData),
+ Amaretti.authentificationTagLength);
+
+ resolve(sjcl.codec.base64.fromBits(crypt));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ },
+
+ decrypt: function(key, crypted, nonce) {
+
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.decrypt) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ base64ToArrayByte(key),
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (rawKey) {
+ return Amaretti.getCrypto().subtle.decrypt(
+ {
+ name: 'AES-GCM',
+ iv: base64ToArrayByte(nonce),
+ tagLength: Amaretti.authTagLength
+ },
+ rawKey,
+ base64ToArrayByte(crypted)
+ ).then(function(plaintext) {
+ return new Promise(function(resolve, reject) {
+ resolve(decode(plaintext));
+ });
+ }, function (err) {
+ return new Promise(function(resolve, reject) {
+ reject('Integrity/Authenticity check failed! Invalid password?');
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var rawKey = sjcl.codec.base64.toBits(key);
+ var rawNonce = sjcl.codec.base64.toBits(nonce);
+ var rawCrypted = sjcl.codec.base64.toBits(crypted);
+ var keyAES = new sjcl.cipher.aes(rawKey);
+
+ var crypt = sjcl.mode.gcm.decrypt(
+ keyAES,
+ rawCrypted,
+ rawNonce,
+ sjcl.codec.utf8String.toBits(Amaretti.authData),
+ Amaretti.authentificationTagLength);
+ var decrypt = sjcl.codec.utf8String.fromBits(crypt);
+ resolve(decrypt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ }
+};
+
+module.exports = Amaretti;
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..fcb35b3
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,22 @@
+{
+ "name": "amaretti",
+ "description": "Wrapper of mutiple encryption library to encrypt/decrypt messages with a passphrase, everywhere",
+ "version": "0.1.0",
+ "author": {
+ "name": "Vincent Cassé",
+ "url": "https://beveloper.fr"
+ },
+ "main": [
+ "public/vendor.js",
+ "public/amaretti.js"
+ ],
+ "license": "MIT",
+ "ignore": [
+ "node_modules",
+ "bower_components"
+ ],
+ "dependencies": {
+ "sjcl": "^1.0.3",
+ "es6-promise": "^2.1.x"
+ }
+}
diff --git a/brunch-config.coffee b/brunch-config.coffee
new file mode 100644
index 0000000..50cd359
--- /dev/null
+++ b/brunch-config.coffee
@@ -0,0 +1,30 @@
+module.exports = config:
+ paths:
+ watched:
+ ['app']
+ files:
+ javascripts:
+ joinTo:
+ 'vendor.js': /^bower_components/
+ 'amaretti.js': /^app/
+ plugins:
+ jshint:
+ pattern: /^app\/.*\.js$/
+ options:
+ bitwise: false
+ curly: true
+ node: true
+ globals:
+ jQuery: true
+ window: true
+ global: true
+ btoa: true
+ Uint8Array: true
+ require: true
+ console: true
+ module: true
+ Promise: true
+ TextDecoder: true
+ TextEncoder: true
+ sjcl: true
+ warnOnly: true
diff --git a/karma.conf.coffee b/karma.conf.coffee
new file mode 100644
index 0000000..76485ac
--- /dev/null
+++ b/karma.conf.coffee
@@ -0,0 +1,53 @@
+module.exports = (config) -> config.set
+ # base path, that will be used to resolve files and exclude
+ basePath: ''
+
+ frameworks: ['jasmine']
+
+ # list of files / patterns to load in the browser
+ files: [
+ 'public/vendor.js',
+ 'public/amaretti.js',
+ 'node_modules/mock-promises/lib/mock-promises.js',
+ 'test/*.js'
+ ]
+
+ # list of files to exclude
+ exclude: []
+
+ # use dots reporter, as travis terminal does not support escaping sequences
+ # possible values: 'dots' || 'progress'
+ reporters: ['progress']
+
+ # Where to save JUnit test results
+ junitReporter:
+ outputFile: 'test-results-frontend.xml'
+
+ # web server port
+ port: 9876
+
+ # cli runner port
+ runnerPort: 9100
+
+ # enable / disable colors in the output (reporters and logs)
+ colors: true
+
+ # level of logging
+ # possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+ logLevel: config.LOG_INFO
+
+ # enable / disable watching file and executing tests whenever any file changes
+ autoWatch: true
+
+ # Start these browsers, currently available:
+ # - Chrome
+ # - ChromeCanary
+ # - Firefox
+ # - Opera
+ # - Safari
+ # - PhantomJS
+ browsers: ['Chrome', 'ChromeCanary', 'Firefox']
+
+ # Auto run tests on start (when browsers are captured) and exit
+ #singleRun: true
+ singleRun: false
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d9be1b9
--- /dev/null
+++ b/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "Amaretti",
+ "description": "Wrapper of mutiple encryption library to encrypt/decrypt messages with a passphrase, everywhere",
+ "version": "0.1.0",
+ "author": {
+ "name": "Vincent Cassé",
+ "url": "https://beveloper.fr"
+ },
+ "scripts": {
+ "start": "npm install && bower install && rm -rf public/*; brunch watch --server",
+ "test": "npm install && bower install && node_modules/.bin/karma start",
+ "clean": "rm -rf node_modules/; rm -rf bower_components/; rm -rf public/"
+ },
+ "main": "public/amaretti.js",
+ "licenses": [
+ {
+ "type": "MIT License",
+ "url": "http://opensource.org/licenses/mit-license.html"
+ }
+ ],
+ "readme": "README.md",
+ "devDependencies": {
+ "brunch": "^1.8.2",
+ "coffee-script": "^1.9.2",
+ "del": "^1.1.1",
+ "fb-flo-brunch": "^1.7.22",
+ "javascript-brunch": "1.7.1",
+ "jshint-brunch": "^1.8.0",
+ "karma": "~0.12.0",
+ "karma-chrome-launcher": "~0.1.0",
+ "karma-cli": "0.0.4",
+ "karma-firefox-launcher": "^0.1.6",
+ "karma-jasmine": "~0.2.0",
+ "karma-junit-reporter": "~0.2.0",
+ "karma-phantomjs-launcher": "^0.1.4",
+ "mock-promises": "^0.3.0"
+ }
+}
diff --git a/public/amaretti.js b/public/amaretti.js
new file mode 100644
index 0000000..71482eb
--- /dev/null
+++ b/public/amaretti.js
@@ -0,0 +1,456 @@
+(function() {
+ 'use strict';
+
+ var globals = typeof window === 'undefined' ? global : window;
+ if (typeof globals.require === 'function') return;
+
+ var modules = {};
+ var cache = {};
+ var has = ({}).hasOwnProperty;
+
+ var aliases = {};
+
+ var endsWith = function(str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ };
+
+ var unalias = function(alias, loaderPath) {
+ var start = 0;
+ if (loaderPath) {
+ if (loaderPath.indexOf('components/' === 0)) {
+ start = 'components/'.length;
+ }
+ if (loaderPath.indexOf('/', start) > 0) {
+ loaderPath = loaderPath.substring(start, loaderPath.indexOf('/', start));
+ }
+ }
+ var result = aliases[alias + '/index.js'] || aliases[loaderPath + '/deps/' + alias + '/index.js'];
+ if (result) {
+ return 'components/' + result.substring(0, result.length - '.js'.length);
+ }
+ return alias;
+ };
+
+ var expand = (function() {
+ var reg = /^\.\.?(\/|$)/;
+ return function(root, name) {
+ var results = [], parts, part;
+ parts = (reg.test(name) ? root + '/' + name : name).split('/');
+ for (var i = 0, length = parts.length; i < length; i++) {
+ part = parts[i];
+ if (part === '..') {
+ results.pop();
+ } else if (part !== '.' && part !== '') {
+ results.push(part);
+ }
+ }
+ return results.join('/');
+ };
+ })();
+ var dirname = function(path) {
+ return path.split('/').slice(0, -1).join('/');
+ };
+
+ var localRequire = function(path) {
+ return function(name) {
+ var absolute = expand(dirname(path), name);
+ return globals.require(absolute, path);
+ };
+ };
+
+ var initModule = function(name, definition) {
+ var module = {id: name, exports: {}};
+ cache[name] = module;
+ definition(module.exports, localRequire(name), module);
+ return module.exports;
+ };
+
+ var require = function(name, loaderPath) {
+ var path = expand(name, '.');
+ if (loaderPath == null) loaderPath = '/';
+ path = unalias(name, loaderPath);
+
+ if (has.call(cache, path)) return cache[path].exports;
+ if (has.call(modules, path)) return initModule(path, modules[path]);
+
+ var dirIndex = expand(path, './index');
+ if (has.call(cache, dirIndex)) return cache[dirIndex].exports;
+ if (has.call(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
+
+ throw new Error('Cannot find module "' + name + '" from '+ '"' + loaderPath + '"');
+ };
+
+ require.alias = function(from, to) {
+ aliases[to] = from;
+ };
+
+ require.register = require.define = function(bundle, fn) {
+ if (typeof bundle === 'object') {
+ for (var key in bundle) {
+ if (has.call(bundle, key)) {
+ modules[key] = bundle[key];
+ }
+ }
+ } else {
+ modules[bundle] = fn;
+ }
+ };
+
+ require.list = function() {
+ var result = [];
+ for (var item in modules) {
+ if (has.call(modules, item)) {
+ result.push(item);
+ }
+ }
+ return result;
+ };
+
+ require.brunch = true;
+ globals.require = require;
+})();
+require.register("amaretti", function(exports, require, module) {
+"use strict";
+
+var encode = function(str) {
+ return new TextEncoder('utf-8').encode(str);
+};
+var decode = function(buf) {
+ return new TextDecoder('utf-8').decode(new Uint8Array(buf));
+};
+/*var ab2str = function(buf) {
+ return String.fromCharCode.apply(null, new Uint16Array(buf));
+};*/
+function b64ToUint6 (nChr) {
+
+ return nChr > 64 && nChr < 91 ?
+ nChr - 65
+ : nChr > 96 && nChr < 123 ?
+ nChr - 71
+ : nChr > 47 && nChr < 58 ?
+ nChr + 4
+ : nChr === 43 ?
+ 62
+ : nChr === 47 ?
+ 63
+ :
+ 0;
+
+}
+
+function arrayBufferToBase64 (arrayBuffer) {
+ return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
+}
+/**
+* TODO add better way to use atob whe possible
+*/
+//https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer
+function base64ToArrayByte(sBase64, nBlocksSize) {
+
+ var
+ sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
+ nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
+
+ for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
+ nMod4 = nInIdx & 3;
+ nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
+ if (nMod4 === 3 || nInLen - nInIdx === 1) {
+ for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
+ taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
+ }
+ nUint24 = 0;
+
+ }
+ }
+
+ return taBytes;
+
+}
+var arrayByteToBase64 = function(arrayByte) {
+ //http://stackoverflow.com/a/12713326
+ var CHUNK_SZ = 0x8000;
+ var c = [];
+ for (var i = 0; i < arrayByte.length; i += CHUNK_SZ) {
+ c.push(String.fromCharCode.apply(
+ null,
+ arrayByte.subarray(i, i + CHUNK_SZ)
+ ));
+ }
+ return btoa(c.join(''));
+};
+
+var Amaretti = {
+
+ authTagLength : 128,
+ paranoia: 10,
+ iterations: 5000,
+ enableNative: true,
+
+ init: function (opts) {
+ this.authTagUsedSpace = this.authTagLength / 4;
+ sjcl.random.startCollectors();
+
+ if (opts) {
+ this.iterations = opts.iterations ? opts.iterations : 5000;
+ this.enableNative = opts.enableNative !== undefined ? opts.enableNative : true;
+ }
+ return this;
+ },
+
+ getCrypto: function() {
+ return window.crypto || window.msCrypto;
+ },
+
+ getSalt: function() {
+ var origSalt;
+ var salt;
+ return new Promise(function(resolve, reject) {
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().getRandomValues) {
+ try {
+ origSalt = Amaretti.getCrypto().getRandomValues(new Uint8Array(64));
+ salt = arrayByteToBase64(origSalt);
+ resolve(salt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ return;
+ }
+
+ if (sjcl.random.isReady(Amaretti.paranoia) === 0) {
+ reject('sjcl random is not ready');
+ return;
+ }
+ try {
+ origSalt = sjcl.random.randomWords(8, Amaretti.paranoia);
+ salt = sjcl.codec.base64.fromBits(origSalt);
+ resolve(salt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ },
+
+ generateKey: function(passphrase, salt, algo) {
+ if (!algo) {
+ return new Promise(function(resolve, reject) {
+ reject('Please add an algo');
+ });
+ }
+
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.deriveKey &&
+ Amaretti.getCrypto().subtle.exportKey) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ encode(passphrase),
+ { name: 'PBKDF2' },
+ false,
+ ['deriveKey']
+ ).then(function(baseKey) {
+
+ var cryptoAlgo;
+ if (algo === 'SHA-1') {
+ cryptoAlgo = 'SHA-1';
+ } else if (algo === 'SHA-256') {
+ throw 'SHA-256 is not yet available on firefox';
+ } else {
+ throw 'Your algo is not available';
+ }
+
+ return Amaretti.getCrypto().subtle.deriveKey(
+ {
+ name: 'PBKDF2',
+ hash: cryptoAlgo,
+ salt: base64ToArrayByte(salt),
+ iterations: Amaretti.iterations
+ },
+ baseKey,
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (key) {
+ return Amaretti.getCrypto().subtle.exportKey('raw', key)
+ .then(function (rawKey) {
+ return new Promise(function(resolve, reject) {
+ try {
+ resolve(arrayByteToBase64(new Uint8Array(rawKey)));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var sjclAlgo;
+
+ if (algo === 'SHA-1') {
+ sjclAlgo = function (key) {
+ // todo sha-1
+ var hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );
+ this.encrypt = function () {
+ return hasher.encrypt.apply( hasher, arguments );
+ };
+ };
+ } else if (algo === 'SHA-256') {
+ sjclAlgo = function (key) {
+ var hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );
+ this.encrypt = function () {
+ return hasher.encrypt.apply( hasher, arguments );
+ };
+ };
+ } else {
+ throw 'Your algo is not available';
+ }
+
+ var key = sjcl.misc.pbkdf2(
+ passphrase,
+ sjcl.codec.base64.toBits(salt),
+ Amaretti.iterations,
+ 256,
+ sjclAlgo
+ );
+ // TODO fix SHA1
+ // https://github.com/bitwiseshiftleft/sjcl/issues/75
+ resolve(sjcl.codec.base64.fromBits(key));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ },
+
+ encrypt: function(key, message, nonce) {
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.encrypt) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ base64ToArrayByte(key),
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (rawKey) {
+
+ return Amaretti.getCrypto().subtle.encrypt(
+ {
+ name: 'AES-GCM',
+ iv: base64ToArrayByte(nonce),
+ tagLength: Amaretti.authTagLength
+ },
+ rawKey,
+ encode(message)
+ ).then(function (crypted) {
+ return new Promise(function (resolve, reject) {
+ try {
+ resolve(arrayBufferToBase64(crypted));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var rawKey = sjcl.codec.base64.toBits(key);
+ var rawNonce = sjcl.codec.base64.toBits(nonce);
+ var keyAES = new sjcl.cipher.aes(rawKey);
+ var crypt = sjcl.mode.gcm.encrypt(
+ keyAES,
+ sjcl.codec.utf8String.toBits(message),
+ rawNonce,
+ sjcl.codec.utf8String.toBits(Amaretti.authData),
+ Amaretti.authentificationTagLength);
+
+ resolve(sjcl.codec.base64.fromBits(crypt));
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ },
+
+ decrypt: function(key, crypted, nonce) {
+
+ if (Amaretti.enableNative &&
+ Amaretti.getCrypto() &&
+ Amaretti.getCrypto().subtle &&
+ Amaretti.getCrypto().subtle.importKey &&
+ Amaretti.getCrypto().subtle.decrypt) {
+
+ return Amaretti.getCrypto().subtle.importKey(
+ 'raw',
+ base64ToArrayByte(key),
+ {
+ name: 'AES-GCM',
+ length: 256
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then(function (rawKey) {
+ return Amaretti.getCrypto().subtle.decrypt(
+ {
+ name: 'AES-GCM',
+ iv: base64ToArrayByte(nonce),
+ tagLength: Amaretti.authTagLength
+ },
+ rawKey,
+ base64ToArrayByte(crypted)
+ ).then(function(plaintext) {
+ return new Promise(function(resolve, reject) {
+ resolve(decode(plaintext));
+ });
+ }, function (err) {
+ return new Promise(function(resolve, reject) {
+ reject('Integrity/Authenticity check failed! Invalid password?');
+ });
+ });
+ });
+ } else {
+ return new Promise(function(resolve, reject) {
+ try {
+ var rawKey = sjcl.codec.base64.toBits(key);
+ var rawNonce = sjcl.codec.base64.toBits(nonce);
+ var rawCrypted = sjcl.codec.base64.toBits(crypted);
+ var keyAES = new sjcl.cipher.aes(rawKey);
+
+ var crypt = sjcl.mode.gcm.decrypt(
+ keyAES,
+ rawCrypted,
+ rawNonce,
+ sjcl.codec.utf8String.toBits(Amaretti.authData),
+ Amaretti.authentificationTagLength);
+ var decrypt = sjcl.codec.utf8String.fromBits(crypt);
+ resolve(decrypt);
+ } catch (exception) {
+ reject(exception.message);
+ }
+ });
+ }
+ }
+};
+
+module.exports = Amaretti;
+
+});
+
+
+//# sourceMappingURL=amaretti.js.map
\ No newline at end of file
diff --git a/public/amaretti.js.map b/public/amaretti.js.map
new file mode 100644
index 0000000..910f2eb
--- /dev/null
+++ b/public/amaretti.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["app/amaretti.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAnVA;AAAA","file":"public/amaretti.js","sourcesContent":["\"use strict\";\n\nvar encode = function(str) {\n\treturn new TextEncoder('utf-8').encode(str);\n};\nvar decode = function(buf) {\n\treturn new TextDecoder('utf-8').decode(new Uint8Array(buf));\n};\n/*var ab2str = function(buf) {\n\treturn String.fromCharCode.apply(null, new Uint16Array(buf));\n};*/\nfunction b64ToUint6 (nChr) {\n\n return nChr > 64 && nChr < 91 ?\n nChr - 65\n : nChr > 96 && nChr < 123 ?\n nChr - 71\n : nChr > 47 && nChr < 58 ?\n nChr + 4\n : nChr === 43 ?\n 62\n : nChr === 47 ?\n 63\n :\n 0;\n\n}\n\nfunction arrayBufferToBase64 (arrayBuffer) {\n\treturn btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));\n}\n/**\n* TODO add better way to use atob whe possible\n*/\n//https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer\nfunction base64ToArrayByte(sBase64, nBlocksSize) { \n\n var\n sB64Enc = sBase64.replace(/[^A-Za-z0-9\\+\\/]/g, \"\"), nInLen = sB64Enc.length,\n nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);\n\n for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {\n nMod4 = nInIdx & 3;\n nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);\n if (nMod4 === 3 || nInLen - nInIdx === 1) {\n for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {\n taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;\n }\n nUint24 = 0;\n\n }\n }\n\n return taBytes;\n\n}\nvar arrayByteToBase64 = function(arrayByte) {\n\t//http://stackoverflow.com/a/12713326\n\tvar CHUNK_SZ = 0x8000;\n\tvar c = [];\n\tfor (var i = 0; i < arrayByte.length; i += CHUNK_SZ) {\n\t\tc.push(String.fromCharCode.apply(\n\t\t\tnull,\n\t\t\tarrayByte.subarray(i, i + CHUNK_SZ)\n\t\t));\n\t}\n\treturn btoa(c.join(''));\n};\n\nvar Amaretti = {\n\n\tauthTagLength : 128,\n\tparanoia: 10,\n\titerations: 5000,\n\tenableNative: true,\n\n\tinit: function (opts) {\n\t\tthis.authTagUsedSpace = this.authTagLength / 4;\n\t\tsjcl.random.startCollectors();\n\n\t\tif (opts) {\n\t\t\tthis.iterations = opts.iterations ? opts.iterations : 5000;\n\t\t\tthis.enableNative = opts.enableNative !== undefined ? opts.enableNative : true; \n\t\t}\n\t\treturn this;\n\t},\n\n\tgetCrypto: function() {\n\t\treturn window.crypto || window.msCrypto;\n\t},\n\n\tgetSalt: function() {\n\t\tvar origSalt;\n\t\tvar salt;\n\t\treturn new Promise(function(resolve, reject) {\n\t\t\tif (Amaretti.enableNative &&\n\t\t\t\tAmaretti.getCrypto() &&\n\t\t\t\tAmaretti.getCrypto().getRandomValues) {\n\t\t\t\ttry {\n\t\t\t\t\torigSalt = Amaretti.getCrypto().getRandomValues(new Uint8Array(64));\n\t\t\t\t\tsalt = arrayByteToBase64(origSalt);\n\t\t\t\t\tresolve(salt);\n\t\t\t\t} catch (exception) {\n\t\t\t\t\treject(exception.message);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (sjcl.random.isReady(Amaretti.paranoia) === 0) {\n\t\t\t\treject('sjcl random is not ready');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\torigSalt = sjcl.random.randomWords(8, Amaretti.paranoia);\n\t\t\t\tsalt = sjcl.codec.base64.fromBits(origSalt);\n\t\t\t\tresolve(salt);\n\t\t\t} catch (exception) {\n\t\t\t\treject(exception.message);\n\t\t\t}\n\t\t});\n\t},\n\n\tgenerateKey: function(passphrase, salt, algo) {\n\t\tif (!algo) {\n\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\treject('Please add an algo');\n\t\t\t});\n\t\t}\n\n\t\tif (Amaretti.enableNative &&\n\t\t\tAmaretti.getCrypto() &&\n\t\t\tAmaretti.getCrypto().subtle &&\n\t\t\tAmaretti.getCrypto().subtle.importKey && \n\t\t\tAmaretti.getCrypto().subtle.deriveKey && \n\t\t\tAmaretti.getCrypto().subtle.exportKey) {\n\n\t\t\treturn Amaretti.getCrypto().subtle.importKey(\n\t\t\t\t'raw',\n\t\t\t\tencode(passphrase),\n\t\t\t\t{ name: 'PBKDF2' },\n\t\t\t\tfalse,\n\t\t\t\t['deriveKey']\n\t\t\t).then(function(baseKey) {\n\n\t\t\t\tvar cryptoAlgo;\n\t\t\t\tif (algo === 'SHA-1') {\n\t\t\t\t\tcryptoAlgo = 'SHA-1';\n\t\t\t\t} else if (algo === 'SHA-256') {\n\t\t\t\t\tthrow 'SHA-256 is not yet available on firefox';\n\t\t\t\t} else {\n\t\t\t\t\tthrow 'Your algo is not available';\n\t\t\t\t}\n\n\t\t\t\treturn Amaretti.getCrypto().subtle.deriveKey(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'PBKDF2',\n\t\t\t\t\t\thash: cryptoAlgo,\n\t\t\t\t\t\tsalt: base64ToArrayByte(salt),\n\t\t\t\t\t\titerations: Amaretti.iterations\n\t\t\t\t\t},\n\t\t\t\t\tbaseKey,\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'AES-GCM',\n\t\t\t\t\t\tlength: 256\n\t\t\t\t\t},\n\t\t\t\t\ttrue,\n\t\t\t\t\t['encrypt', 'decrypt']\n\t\t\t\t).then(function (key) {\n\t\t\t\t\treturn Amaretti.getCrypto().subtle.exportKey('raw', key)\n\t\t\t\t\t\t.then(function (rawKey) {\n\t\t\t\t\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t \t\tresolve(arrayByteToBase64(new Uint8Array(rawKey)));\n\t\t\t\t\t\t\t \t} catch (exception) {\n\t\t\t\t\t\t\t \t\treject(exception.message);\n\t\t\t\t\t\t\t \t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\ttry {\n\t\t\t\t\tvar sjclAlgo;\n\n\t\t\t\t\tif (algo === 'SHA-1') {\n\t\t\t\t\t\tsjclAlgo = function (key) {\n\t\t\t\t\t\t\t// todo sha-1\n\t\t\t\t\t \tvar hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );\n\t\t\t\t\t\t this.encrypt = function () {\n\t\t\t\t\t\t return hasher.encrypt.apply( hasher, arguments );\n\t\t\t\t\t\t };\n\t\t\t\t\t\t};\n\t\t\t\t\t} else if (algo === 'SHA-256') {\n\t\t\t\t\t\tsjclAlgo = function (key) {\n\t\t\t\t\t \tvar hasher = new sjcl.misc.hmac( key, sjcl.hash.sha256 );\n\t\t\t\t\t\t this.encrypt = function () {\n\t\t\t\t\t\t return hasher.encrypt.apply( hasher, arguments );\n\t\t\t\t\t\t };\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow 'Your algo is not available';\n\t\t\t\t\t}\n\n\t\t\t\t\tvar key = sjcl.misc.pbkdf2(\n\t\t\t\t\t\tpassphrase,\n\t\t\t\t\t\tsjcl.codec.base64.toBits(salt),\n\t\t\t\t\t\tAmaretti.iterations,\n\t\t\t\t\t\t256,\n\t\t\t\t\t\tsjclAlgo\n\t\t\t\t\t);\n\t\t\t\t\t// TODO fix SHA1\n\t\t\t\t\t// https://github.com/bitwiseshiftleft/sjcl/issues/75\n\t\t\t\t\tresolve(sjcl.codec.base64.fromBits(key));\n\t\t\t\t} catch (exception) {\n\t\t\t\t\treject(exception.message);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t},\n\n\tencrypt: function(key, message, nonce) {\n\t\tif (Amaretti.enableNative &&\n\t\t\tAmaretti.getCrypto() &&\n\t\t\tAmaretti.getCrypto().subtle &&\n\t\t\tAmaretti.getCrypto().subtle.importKey &&\n\t\t\tAmaretti.getCrypto().subtle.encrypt) {\n\n\t\t\treturn Amaretti.getCrypto().subtle.importKey(\n\t\t\t\t'raw',\n\t\t\t\tbase64ToArrayByte(key),\n\t\t\t\t{\n\t\t\t\t\tname: 'AES-GCM',\n\t\t\t\t\tlength: 256\n\t\t\t\t},\n\t\t\t\ttrue,\n\t\t\t\t['encrypt', 'decrypt']\n\t\t\t).then(function (rawKey) {\n\t\t\t\t\n\t\t\t\treturn Amaretti.getCrypto().subtle.encrypt(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'AES-GCM',\n\t\t\t\t\t\tiv: base64ToArrayByte(nonce),\n\t\t\t\t\t\ttagLength: Amaretti.authTagLength\n\t\t\t\t\t},\n\t\t\t\t\trawKey,\n\t\t\t\t\tencode(message)\n\t\t\t\t).then(function (crypted) {\n\t\t\t\t\treturn new Promise(function (resolve, reject) {\n\t\t\t\t\t\ttry {\t\n\t\t\t\t\t\t\tresolve(arrayBufferToBase64(crypted));\n\t\t\t\t\t\t} catch (exception) {\n\t\t\t\t\t\t\treject(exception.message);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\ttry {\n\t\t\t\t\tvar rawKey = sjcl.codec.base64.toBits(key);\n\t\t\t\t\tvar rawNonce = sjcl.codec.base64.toBits(nonce);\n\t\t\t\t\tvar keyAES = new sjcl.cipher.aes(rawKey);\n\t\t\t\t\tvar crypt = sjcl.mode.gcm.encrypt(\n\t\t\t\t\t\tkeyAES,\n\t\t\t\t\t\tsjcl.codec.utf8String.toBits(message),\n\t\t\t\t\t\trawNonce,\n\t\t\t\t\t\tsjcl.codec.utf8String.toBits(Amaretti.authData),\n\t\t\t\t\t\tAmaretti.authentificationTagLength);\n\n\t\t\t\t\tresolve(sjcl.codec.base64.fromBits(crypt));\n\t\t\t\t} catch (exception) {\n\t\t\t\t\treject(exception.message);\n\t\t\t\t}\n\t\t\t});\n\t\t}\t\n\t},\n\n\tdecrypt: function(key, crypted, nonce) {\n\n\t\tif (Amaretti.enableNative &&\n\t\t\tAmaretti.getCrypto() &&\n\t\t\tAmaretti.getCrypto().subtle &&\n\t\t\tAmaretti.getCrypto().subtle.importKey &&\n\t\t\tAmaretti.getCrypto().subtle.decrypt) {\n\n\t\t\treturn Amaretti.getCrypto().subtle.importKey(\n\t\t\t\t'raw',\n\t\t\t\tbase64ToArrayByte(key),\n\t\t\t\t{\n\t\t\t\t\tname: 'AES-GCM',\n\t\t\t\t\tlength: 256\n\t\t\t\t},\n\t\t\t\ttrue,\n\t\t\t\t['encrypt', 'decrypt']\n\t\t\t).then(function (rawKey) {\n\t\t\t\treturn Amaretti.getCrypto().subtle.decrypt(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'AES-GCM',\n\t\t\t\t\t\tiv: base64ToArrayByte(nonce),\n\t\t\t\t\t\ttagLength: Amaretti.authTagLength\n\t\t\t\t\t},\n\t\t\t\t\trawKey,\n\t\t\t\t\tbase64ToArrayByte(crypted)\n\t\t\t\t).then(function(plaintext) {\n\t\t\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\t\t\tresolve(decode(plaintext));\n\t\t\t\t\t});\n\t\t\t\t}, function (err) {\n\t\t\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\t\t\treject('Integrity/Authenticity check failed! Invalid password?');\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\treturn new Promise(function(resolve, reject) {\n\t\t\t\ttry {\n\t\t\t\t\tvar rawKey = sjcl.codec.base64.toBits(key);\n\t\t\t\t\tvar rawNonce = sjcl.codec.base64.toBits(nonce);\n\t\t\t\t\tvar rawCrypted = sjcl.codec.base64.toBits(crypted);\n\t\t\t\t\tvar keyAES = new sjcl.cipher.aes(rawKey);\n\n\t\t\t\t\tvar crypt = sjcl.mode.gcm.decrypt(\n\t\t\t\t\t\tkeyAES,\n\t\t\t\t\t\trawCrypted,\n\t\t\t\t\t\trawNonce,\n\t\t\t\t\t\tsjcl.codec.utf8String.toBits(Amaretti.authData),\n\t\t\t\t\t\tAmaretti.authentificationTagLength);\n\t\t\t\t\tvar decrypt = sjcl.codec.utf8String.fromBits(crypt);\n\t\t\t\t\tresolve(decrypt);\n\t\t\t\t} catch (exception) {\n\t\t\t\t\treject(exception.message);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n};\n\nmodule.exports = Amaretti;\n"]}
\ No newline at end of file
diff --git a/public/vendor.js b/public/vendor.js
new file mode 100644
index 0000000..2b5179f
--- /dev/null
+++ b/public/vendor.js
@@ -0,0 +1,1137 @@
+(function() {
+ 'use strict';
+
+ var globals = typeof window === 'undefined' ? global : window;
+ if (typeof globals.require === 'function') return;
+
+ var modules = {};
+ var cache = {};
+ var has = ({}).hasOwnProperty;
+
+ var aliases = {};
+
+ var endsWith = function(str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ };
+
+ var unalias = function(alias, loaderPath) {
+ var start = 0;
+ if (loaderPath) {
+ if (loaderPath.indexOf('components/' === 0)) {
+ start = 'components/'.length;
+ }
+ if (loaderPath.indexOf('/', start) > 0) {
+ loaderPath = loaderPath.substring(start, loaderPath.indexOf('/', start));
+ }
+ }
+ var result = aliases[alias + '/index.js'] || aliases[loaderPath + '/deps/' + alias + '/index.js'];
+ if (result) {
+ return 'components/' + result.substring(0, result.length - '.js'.length);
+ }
+ return alias;
+ };
+
+ var expand = (function() {
+ var reg = /^\.\.?(\/|$)/;
+ return function(root, name) {
+ var results = [], parts, part;
+ parts = (reg.test(name) ? root + '/' + name : name).split('/');
+ for (var i = 0, length = parts.length; i < length; i++) {
+ part = parts[i];
+ if (part === '..') {
+ results.pop();
+ } else if (part !== '.' && part !== '') {
+ results.push(part);
+ }
+ }
+ return results.join('/');
+ };
+ })();
+ var dirname = function(path) {
+ return path.split('/').slice(0, -1).join('/');
+ };
+
+ var localRequire = function(path) {
+ return function(name) {
+ var absolute = expand(dirname(path), name);
+ return globals.require(absolute, path);
+ };
+ };
+
+ var initModule = function(name, definition) {
+ var module = {id: name, exports: {}};
+ cache[name] = module;
+ definition(module.exports, localRequire(name), module);
+ return module.exports;
+ };
+
+ var require = function(name, loaderPath) {
+ var path = expand(name, '.');
+ if (loaderPath == null) loaderPath = '/';
+ path = unalias(name, loaderPath);
+
+ if (has.call(cache, path)) return cache[path].exports;
+ if (has.call(modules, path)) return initModule(path, modules[path]);
+
+ var dirIndex = expand(path, './index');
+ if (has.call(cache, dirIndex)) return cache[dirIndex].exports;
+ if (has.call(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
+
+ throw new Error('Cannot find module "' + name + '" from '+ '"' + loaderPath + '"');
+ };
+
+ require.alias = function(from, to) {
+ aliases[to] = from;
+ };
+
+ require.register = require.define = function(bundle, fn) {
+ if (typeof bundle === 'object') {
+ for (var key in bundle) {
+ if (has.call(bundle, key)) {
+ modules[key] = bundle[key];
+ }
+ }
+ } else {
+ modules[bundle] = fn;
+ }
+ };
+
+ require.list = function() {
+ var result = [];
+ for (var item in modules) {
+ if (has.call(modules, item)) {
+ result.push(item);
+ }
+ }
+ return result;
+ };
+
+ require.brunch = true;
+ globals.require = require;
+})();
+/*!
+ * @overview es6-promise - a tiny implementation of Promises/A+.
+ * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
+ * @license Licensed under MIT license
+ * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
+ * @version 2.2.0
+ */
+
+(function() {
+ "use strict";
+ function lib$es6$promise$utils$$objectOrFunction(x) {
+ return typeof x === 'function' || (typeof x === 'object' && x !== null);
+ }
+
+ function lib$es6$promise$utils$$isFunction(x) {
+ return typeof x === 'function';
+ }
+
+ function lib$es6$promise$utils$$isMaybeThenable(x) {
+ return typeof x === 'object' && x !== null;
+ }
+
+ var lib$es6$promise$utils$$_isArray;
+ if (!Array.isArray) {
+ lib$es6$promise$utils$$_isArray = function (x) {
+ return Object.prototype.toString.call(x) === '[object Array]';
+ };
+ } else {
+ lib$es6$promise$utils$$_isArray = Array.isArray;
+ }
+
+ var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray;
+ var lib$es6$promise$asap$$len = 0;
+ var lib$es6$promise$asap$$toString = {}.toString;
+ var lib$es6$promise$asap$$vertxNext;
+ var lib$es6$promise$asap$$customSchedulerFn;
+
+ function lib$es6$promise$asap$$asap(callback, arg) {
+ lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback;
+ lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg;
+ lib$es6$promise$asap$$len += 2;
+ if (lib$es6$promise$asap$$len === 2) {
+ // If len is 2, that means that we need to schedule an async flush.
+ // If additional callbacks are queued before the queue is flushed, they
+ // will be processed by this flush that we are scheduling.
+ if (lib$es6$promise$asap$$customSchedulerFn) {
+ lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush);
+ } else {
+ lib$es6$promise$asap$$scheduleFlush();
+ }
+ }
+ }
+
+ var lib$es6$promise$asap$$default = lib$es6$promise$asap$$asap;
+ function lib$es6$promise$asap$$setScheduler(scheduleFn) {
+ lib$es6$promise$asap$$customSchedulerFn = scheduleFn;
+ }
+
+ var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
+ var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {};
+ var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;
+ var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
+
+ // test for web worker but not in IE10
+ var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
+ typeof importScripts !== 'undefined' &&
+ typeof MessageChannel !== 'undefined';
+
+ // node
+ function lib$es6$promise$asap$$useNextTick() {
+ var nextTick = process.nextTick;
+ // node version 0.10.x displays a deprecation warning when nextTick is used recursively
+ // setImmediate should be used instead instead
+ var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
+ if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
+ nextTick = setImmediate;
+ }
+ return function() {
+ nextTick(lib$es6$promise$asap$$flush);
+ };
+ }
+
+ // vertx
+ function lib$es6$promise$asap$$useVertxTimer() {
+ return function() {
+ lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush);
+ };
+ }
+
+ function lib$es6$promise$asap$$useMutationObserver() {
+ var iterations = 0;
+ var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);
+ var node = document.createTextNode('');
+ observer.observe(node, { characterData: true });
+
+ return function() {
+ node.data = (iterations = ++iterations % 2);
+ };
+ }
+
+ // web worker
+ function lib$es6$promise$asap$$useMessageChannel() {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = lib$es6$promise$asap$$flush;
+ return function () {
+ channel.port2.postMessage(0);
+ };
+ }
+
+ function lib$es6$promise$asap$$useSetTimeout() {
+ return function() {
+ setTimeout(lib$es6$promise$asap$$flush, 1);
+ };
+ }
+
+ var lib$es6$promise$asap$$queue = new Array(1000);
+ function lib$es6$promise$asap$$flush() {
+ for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) {
+ var callback = lib$es6$promise$asap$$queue[i];
+ var arg = lib$es6$promise$asap$$queue[i+1];
+
+ callback(arg);
+
+ lib$es6$promise$asap$$queue[i] = undefined;
+ lib$es6$promise$asap$$queue[i+1] = undefined;
+ }
+
+ lib$es6$promise$asap$$len = 0;
+ }
+
+ function lib$es6$promise$asap$$attemptVertex() {
+ try {
+ var r = require;
+ var vertx = r('vertx');
+ lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
+ return lib$es6$promise$asap$$useVertxTimer();
+ } catch(e) {
+ return lib$es6$promise$asap$$useSetTimeout();
+ }
+ }
+
+ var lib$es6$promise$asap$$scheduleFlush;
+ // Decide what async method to use to triggering processing of queued callbacks:
+ if (lib$es6$promise$asap$$isNode) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick();
+ } else if (lib$es6$promise$asap$$BrowserMutationObserver) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver();
+ } else if (lib$es6$promise$asap$$isWorker) {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel();
+ } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex();
+ } else {
+ lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout();
+ }
+
+ function lib$es6$promise$$internal$$noop() {}
+
+ var lib$es6$promise$$internal$$PENDING = void 0;
+ var lib$es6$promise$$internal$$FULFILLED = 1;
+ var lib$es6$promise$$internal$$REJECTED = 2;
+
+ var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject();
+
+ function lib$es6$promise$$internal$$selfFullfillment() {
+ return new TypeError("You cannot resolve a promise with itself");
+ }
+
+ function lib$es6$promise$$internal$$cannotReturnOwn() {
+ return new TypeError('A promises callback cannot return that same promise.');
+ }
+
+ function lib$es6$promise$$internal$$getThen(promise) {
+ try {
+ return promise.then;
+ } catch(error) {
+ lib$es6$promise$$internal$$GET_THEN_ERROR.error = error;
+ return lib$es6$promise$$internal$$GET_THEN_ERROR;
+ }
+ }
+
+ function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
+ try {
+ then.call(value, fulfillmentHandler, rejectionHandler);
+ } catch(e) {
+ return e;
+ }
+ }
+
+ function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) {
+ lib$es6$promise$asap$$default(function(promise) {
+ var sealed = false;
+ var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) {
+ if (sealed) { return; }
+ sealed = true;
+ if (thenable !== value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ }
+ }, function(reason) {
+ if (sealed) { return; }
+ sealed = true;
+
+ lib$es6$promise$$internal$$reject(promise, reason);
+ }, 'Settle: ' + (promise._label || ' unknown promise'));
+
+ if (!sealed && error) {
+ sealed = true;
+ lib$es6$promise$$internal$$reject(promise, error);
+ }
+ }, promise);
+ }
+
+ function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) {
+ if (thenable._state === lib$es6$promise$$internal$$FULFILLED) {
+ lib$es6$promise$$internal$$fulfill(promise, thenable._result);
+ } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, thenable._result);
+ } else {
+ lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }, function(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ });
+ }
+ }
+
+ function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) {
+ if (maybeThenable.constructor === promise.constructor) {
+ lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable);
+ } else {
+ var then = lib$es6$promise$$internal$$getThen(maybeThenable);
+
+ if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error);
+ } else if (then === undefined) {
+ lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
+ } else if (lib$es6$promise$utils$$isFunction(then)) {
+ lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
+ }
+ }
+ }
+
+ function lib$es6$promise$$internal$$resolve(promise, value) {
+ if (promise === value) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment());
+ } else if (lib$es6$promise$utils$$objectOrFunction(value)) {
+ lib$es6$promise$$internal$$handleMaybeThenable(promise, value);
+ } else {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ }
+ }
+
+ function lib$es6$promise$$internal$$publishRejection(promise) {
+ if (promise._onerror) {
+ promise._onerror(promise._result);
+ }
+
+ lib$es6$promise$$internal$$publish(promise);
+ }
+
+ function lib$es6$promise$$internal$$fulfill(promise, value) {
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
+
+ promise._result = value;
+ promise._state = lib$es6$promise$$internal$$FULFILLED;
+
+ if (promise._subscribers.length !== 0) {
+ lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, promise);
+ }
+ }
+
+ function lib$es6$promise$$internal$$reject(promise, reason) {
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
+ promise._state = lib$es6$promise$$internal$$REJECTED;
+ promise._result = reason;
+
+ lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publishRejection, promise);
+ }
+
+ function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
+ var subscribers = parent._subscribers;
+ var length = subscribers.length;
+
+ parent._onerror = null;
+
+ subscribers[length] = child;
+ subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment;
+ subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection;
+
+ if (length === 0 && parent._state) {
+ lib$es6$promise$asap$$default(lib$es6$promise$$internal$$publish, parent);
+ }
+ }
+
+ function lib$es6$promise$$internal$$publish(promise) {
+ var subscribers = promise._subscribers;
+ var settled = promise._state;
+
+ if (subscribers.length === 0) { return; }
+
+ var child, callback, detail = promise._result;
+
+ for (var i = 0; i < subscribers.length; i += 3) {
+ child = subscribers[i];
+ callback = subscribers[i + settled];
+
+ if (child) {
+ lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail);
+ } else {
+ callback(detail);
+ }
+ }
+
+ promise._subscribers.length = 0;
+ }
+
+ function lib$es6$promise$$internal$$ErrorObject() {
+ this.error = null;
+ }
+
+ var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject();
+
+ function lib$es6$promise$$internal$$tryCatch(callback, detail) {
+ try {
+ return callback(detail);
+ } catch(e) {
+ lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e;
+ return lib$es6$promise$$internal$$TRY_CATCH_ERROR;
+ }
+ }
+
+ function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) {
+ var hasCallback = lib$es6$promise$utils$$isFunction(callback),
+ value, error, succeeded, failed;
+
+ if (hasCallback) {
+ value = lib$es6$promise$$internal$$tryCatch(callback, detail);
+
+ if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) {
+ failed = true;
+ error = value.error;
+ value = null;
+ } else {
+ succeeded = true;
+ }
+
+ if (promise === value) {
+ lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn());
+ return;
+ }
+
+ } else {
+ value = detail;
+ succeeded = true;
+ }
+
+ if (promise._state !== lib$es6$promise$$internal$$PENDING) {
+ // noop
+ } else if (hasCallback && succeeded) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ } else if (failed) {
+ lib$es6$promise$$internal$$reject(promise, error);
+ } else if (settled === lib$es6$promise$$internal$$FULFILLED) {
+ lib$es6$promise$$internal$$fulfill(promise, value);
+ } else if (settled === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, value);
+ }
+ }
+
+ function lib$es6$promise$$internal$$initializePromise(promise, resolver) {
+ try {
+ resolver(function resolvePromise(value){
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }, function rejectPromise(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ });
+ } catch(e) {
+ lib$es6$promise$$internal$$reject(promise, e);
+ }
+ }
+
+ function lib$es6$promise$enumerator$$Enumerator(Constructor, input) {
+ var enumerator = this;
+
+ enumerator._instanceConstructor = Constructor;
+ enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop);
+
+ if (enumerator._validateInput(input)) {
+ enumerator._input = input;
+ enumerator.length = input.length;
+ enumerator._remaining = input.length;
+
+ enumerator._init();
+
+ if (enumerator.length === 0) {
+ lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result);
+ } else {
+ enumerator.length = enumerator.length || 0;
+ enumerator._enumerate();
+ if (enumerator._remaining === 0) {
+ lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result);
+ }
+ }
+ } else {
+ lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError());
+ }
+ }
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) {
+ return lib$es6$promise$utils$$isArray(input);
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() {
+ return new Error('Array Methods must be provided an Array');
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._init = function() {
+ this._result = new Array(this.length);
+ };
+
+ var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator;
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() {
+ var enumerator = this;
+
+ var length = enumerator.length;
+ var promise = enumerator.promise;
+ var input = enumerator._input;
+
+ for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
+ enumerator._eachEntry(input[i], i);
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
+ var enumerator = this;
+ var c = enumerator._instanceConstructor;
+
+ if (lib$es6$promise$utils$$isMaybeThenable(entry)) {
+ if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) {
+ entry._onerror = null;
+ enumerator._settledAt(entry._state, i, entry._result);
+ } else {
+ enumerator._willSettleAt(c.resolve(entry), i);
+ }
+ } else {
+ enumerator._remaining--;
+ enumerator._result[i] = entry;
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
+ var enumerator = this;
+ var promise = enumerator.promise;
+
+ if (promise._state === lib$es6$promise$$internal$$PENDING) {
+ enumerator._remaining--;
+
+ if (state === lib$es6$promise$$internal$$REJECTED) {
+ lib$es6$promise$$internal$$reject(promise, value);
+ } else {
+ enumerator._result[i] = value;
+ }
+ }
+
+ if (enumerator._remaining === 0) {
+ lib$es6$promise$$internal$$fulfill(promise, enumerator._result);
+ }
+ };
+
+ lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
+ var enumerator = this;
+
+ lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) {
+ enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value);
+ }, function(reason) {
+ enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason);
+ });
+ };
+ function lib$es6$promise$promise$all$$all(entries) {
+ return new lib$es6$promise$enumerator$$default(this, entries).promise;
+ }
+ var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all;
+ function lib$es6$promise$promise$race$$race(entries) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+
+ if (!lib$es6$promise$utils$$isArray(entries)) {
+ lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
+ return promise;
+ }
+
+ var length = entries.length;
+
+ function onFulfillment(value) {
+ lib$es6$promise$$internal$$resolve(promise, value);
+ }
+
+ function onRejection(reason) {
+ lib$es6$promise$$internal$$reject(promise, reason);
+ }
+
+ for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
+ lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
+ }
+
+ return promise;
+ }
+ var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race;
+ function lib$es6$promise$promise$resolve$$resolve(object) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ if (object && typeof object === 'object' && object.constructor === Constructor) {
+ return object;
+ }
+
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+ lib$es6$promise$$internal$$resolve(promise, object);
+ return promise;
+ }
+ var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve;
+ function lib$es6$promise$promise$reject$$reject(reason) {
+ /*jshint validthis:true */
+ var Constructor = this;
+ var promise = new Constructor(lib$es6$promise$$internal$$noop);
+ lib$es6$promise$$internal$$reject(promise, reason);
+ return promise;
+ }
+ var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject;
+
+ var lib$es6$promise$promise$$counter = 0;
+
+ function lib$es6$promise$promise$$needsResolver() {
+ throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
+ }
+
+ function lib$es6$promise$promise$$needsNew() {
+ throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
+ }
+
+ var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise;
+ /**
+ Promise objects represent the eventual result of an asynchronous operation. The
+ primary way of interacting with a promise is through its `then` method, which
+ registers callbacks to receive either a promise’s eventual value or the reason
+ why the promise cannot be fulfilled.
+
+ Terminology
+ -----------
+
+ - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
+ - `thenable` is an object or function that defines a `then` method.
+ - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
+ - `exception` is a value that is thrown using the throw statement.
+ - `reason` is a value that indicates why a promise was rejected.
+ - `settled` the final resting state of a promise, fulfilled or rejected.
+
+ A promise can be in one of three states: pending, fulfilled, or rejected.
+
+ Promises that are fulfilled have a fulfillment value and are in the fulfilled
+ state. Promises that are rejected have a rejection reason and are in the
+ rejected state. A fulfillment value is never a thenable.
+
+ Promises can also be said to *resolve* a value. If this value is also a
+ promise, then the original promise's settled state will match the value's
+ settled state. So a promise that *resolves* a promise that rejects will
+ itself reject, and a promise that *resolves* a promise that fulfills will
+ itself fulfill.
+
+
+ Basic Usage:
+ ------------
+
+ ```js
+ var promise = new Promise(function(resolve, reject) {
+ // on success
+ resolve(value);
+
+ // on failure
+ reject(reason);
+ });
+
+ promise.then(function(value) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Advanced Usage:
+ ---------------
+
+ Promises shine when abstracting away asynchronous interactions such as
+ `XMLHttpRequest`s.
+
+ ```js
+ function getJSON(url) {
+ return new Promise(function(resolve, reject){
+ var xhr = new XMLHttpRequest();
+
+ xhr.open('GET', url);
+ xhr.onreadystatechange = handler;
+ xhr.responseType = 'json';
+ xhr.setRequestHeader('Accept', 'application/json');
+ xhr.send();
+
+ function handler() {
+ if (this.readyState === this.DONE) {
+ if (this.status === 200) {
+ resolve(this.response);
+ } else {
+ reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
+ }
+ }
+ };
+ });
+ }
+
+ getJSON('/posts.json').then(function(json) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Unlike callbacks, promises are great composable primitives.
+
+ ```js
+ Promise.all([
+ getJSON('/posts'),
+ getJSON('/comments')
+ ]).then(function(values){
+ values[0] // => postsJSON
+ values[1] // => commentsJSON
+
+ return values;
+ });
+ ```
+
+ @class Promise
+ @param {function} resolver
+ Useful for tooling.
+ @constructor
+ */
+ function lib$es6$promise$promise$$Promise(resolver) {
+ this._id = lib$es6$promise$promise$$counter++;
+ this._state = undefined;
+ this._result = undefined;
+ this._subscribers = [];
+
+ if (lib$es6$promise$$internal$$noop !== resolver) {
+ if (!lib$es6$promise$utils$$isFunction(resolver)) {
+ lib$es6$promise$promise$$needsResolver();
+ }
+
+ if (!(this instanceof lib$es6$promise$promise$$Promise)) {
+ lib$es6$promise$promise$$needsNew();
+ }
+
+ lib$es6$promise$$internal$$initializePromise(this, resolver);
+ }
+ }
+
+ lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;
+ lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;
+ lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;
+ lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;
+ lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler;
+ lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$default;
+
+ lib$es6$promise$promise$$Promise.prototype = {
+ constructor: lib$es6$promise$promise$$Promise,
+
+ /**
+ The primary way of interacting with a promise is through its `then` method,
+ which registers callbacks to receive either a promise's eventual value or the
+ reason why the promise cannot be fulfilled.
+
+ ```js
+ findUser().then(function(user){
+ // user is available
+ }, function(reason){
+ // user is unavailable, and you are given the reason why
+ });
+ ```
+
+ Chaining
+ --------
+
+ The return value of `then` is itself a promise. This second, 'downstream'
+ promise is resolved with the return value of the first promise's fulfillment
+ or rejection handler, or rejected if the handler throws an exception.
+
+ ```js
+ findUser().then(function (user) {
+ return user.name;
+ }, function (reason) {
+ return 'default name';
+ }).then(function (userName) {
+ // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
+ // will be `'default name'`
+ });
+
+ findUser().then(function (user) {
+ throw new Error('Found user, but still unhappy');
+ }, function (reason) {
+ throw new Error('`findUser` rejected and we're unhappy');
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
+ // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
+ });
+ ```
+ If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
+
+ ```js
+ findUser().then(function (user) {
+ throw new PedagogicalException('Upstream error');
+ }).then(function (value) {
+ // never reached
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // The `PedgagocialException` is propagated all the way down to here
+ });
+ ```
+
+ Assimilation
+ ------------
+
+ Sometimes the value you want to propagate to a downstream promise can only be
+ retrieved asynchronously. This can be achieved by returning a promise in the
+ fulfillment or rejection handler. The downstream promise will then be pending
+ until the returned promise is settled. This is called *assimilation*.
+
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // The user's comments are now available
+ });
+ ```
+
+ If the assimliated promise rejects, then the downstream promise will also reject.
+
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // If `findCommentsByAuthor` fulfills, we'll have the value here
+ }, function (reason) {
+ // If `findCommentsByAuthor` rejects, we'll have the reason here
+ });
+ ```
+
+ Simple Example
+ --------------
+
+ Synchronous Example
+
+ ```javascript
+ var result;
+
+ try {
+ result = findResult();
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+
+ Errback Example
+
+ ```js
+ findResult(function(result, err){
+ if (err) {
+ // failure
+ } else {
+ // success
+ }
+ });
+ ```
+
+ Promise Example;
+
+ ```javascript
+ findResult().then(function(result){
+ // success
+ }, function(reason){
+ // failure
+ });
+ ```
+
+ Advanced Example
+ --------------
+
+ Synchronous Example
+
+ ```javascript
+ var author, books;
+
+ try {
+ author = findAuthor();
+ books = findBooksByAuthor(author);
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+
+ Errback Example
+
+ ```js
+
+ function foundBooks(books) {
+
+ }
+
+ function failure(reason) {
+
+ }
+
+ findAuthor(function(author, err){
+ if (err) {
+ failure(err);
+ // failure
+ } else {
+ try {
+ findBoooksByAuthor(author, function(books, err) {
+ if (err) {
+ failure(err);
+ } else {
+ try {
+ foundBooks(books);
+ } catch(reason) {
+ failure(reason);
+ }
+ }
+ });
+ } catch(error) {
+ failure(err);
+ }
+ // success
+ }
+ });
+ ```
+
+ Promise Example;
+
+ ```javascript
+ findAuthor().
+ then(findBooksByAuthor).
+ then(function(books){
+ // found books
+ }).catch(function(reason){
+ // something went wrong
+ });
+ ```
+
+ @method then
+ @param {Function} onFulfilled
+ @param {Function} onRejected
+ Useful for tooling.
+ @return {Promise}
+ */
+ then: function(onFulfillment, onRejection) {
+ var parent = this;
+ var state = parent._state;
+
+ if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) {
+ return this;
+ }
+
+ var child = new this.constructor(lib$es6$promise$$internal$$noop);
+ var result = parent._result;
+
+ if (state) {
+ var callback = arguments[state - 1];
+ lib$es6$promise$asap$$default(function(){
+ lib$es6$promise$$internal$$invokeCallback(state, child, callback, result);
+ });
+ } else {
+ lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);
+ }
+
+ return child;
+ },
+
+ /**
+ `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
+ as the catch block of a try/catch statement.
+
+ ```js
+ function findAuthor(){
+ throw new Error('couldn't find that author');
+ }
+
+ // synchronous
+ try {
+ findAuthor();
+ } catch(reason) {
+ // something went wrong
+ }
+
+ // async with promises
+ findAuthor().catch(function(reason){
+ // something went wrong
+ });
+ ```
+
+ @method catch
+ @param {Function} onRejection
+ Useful for tooling.
+ @return {Promise}
+ */
+ 'catch': function(onRejection) {
+ return this.then(null, onRejection);
+ }
+ };
+ function lib$es6$promise$polyfill$$polyfill() {
+ var local;
+
+ if (typeof global !== 'undefined') {
+ local = global;
+ } else if (typeof self !== 'undefined') {
+ local = self;
+ } else {
+ try {
+ local = Function('return this')();
+ } catch (e) {
+ throw new Error('polyfill failed because global object is unavailable in this environment');
+ }
+ }
+
+ var P = local.Promise;
+
+ if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) {
+ return;
+ }
+
+ local.Promise = lib$es6$promise$promise$$default;
+ }
+ var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;
+
+ var lib$es6$promise$umd$$ES6Promise = {
+ 'Promise': lib$es6$promise$promise$$default,
+ 'polyfill': lib$es6$promise$polyfill$$default
+ };
+
+ /* global define:true module:true window: true */
+ if (typeof define === 'function' && define['amd']) {
+ define(function() { return lib$es6$promise$umd$$ES6Promise; });
+ } else if (typeof module !== 'undefined' && module['exports']) {
+ module['exports'] = lib$es6$promise$umd$$ES6Promise;
+ } else if (typeof this !== 'undefined') {
+ this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise;
+ }
+
+ lib$es6$promise$polyfill$$default();
+}).call(this);
+
+
+"use strict";function q(a){throw a;}var s=void 0,u=!1;var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
+"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});
+sjcl.cipher.aes=function(a){this.k[0][0][0]||this.D();var b,c,d,e,f=this.k[0][4],g=this.k[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid("invalid aes key size"));this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
+255]]};
+sjcl.cipher.aes.prototype={encrypt:function(a){return w(this,a,0)},decrypt:function(a){return w(this,a,1)},k:[[[],[],[],[],[]],[[],[],[],[],[]]],D:function(){var a=this.k[0],b=this.k[1],c=a[4],d=b[4],e,f,g,h=[],l=[],k,n,m,p;for(e=0;0x100>e;e++)l[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=k||1,g=l[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[k=h[f]]];p=0x1010101*n^0x10001*e^0x101*k^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=
+0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
+function w(a,b,c){4!==b.length&&q(new sjcl.exception.invalid("invalid aes block size"));var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,l,k,n=d.length/4-2,m,p=4,t=[0,0,0,0];h=a.k[c];a=h[0];var r=h[1],v=h[2],y=h[3],z=h[4];for(m=0;m>>24]^r[f>>16&255]^v[g>>8&255]^y[b&255]^d[p],l=a[f>>>24]^r[g>>16&255]^v[b>>8&255]^y[e&255]^d[p+1],k=a[g>>>24]^r[b>>16&255]^v[e>>8&255]^y[f&255]^d[p+2],b=a[b>>>24]^r[e>>16&255]^v[f>>8&255]^y[g&255]^d[p+3],p+=4,e=h,f=l,g=k;for(m=0;4>
+m;m++)t[c?3&-m:m]=z[e>>>24]<<24^z[f>>16&255]<<16^z[g>>8&255]<<8^z[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return t}
+sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===s?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return u;var c=0,d;for(d=0;d>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
+sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.J,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;dh&&q(new sjcl.exception.invalid("this isn't base64!")),26>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.D();a?(this.r=a.r.slice(0),this.o=a.o.slice(0),this.h=a.h):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
+sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.r=this.N.slice(0);this.o=[];this.h=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.o=sjcl.bitArray.concat(this.o,a);b=this.h;a=this.h=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)x(this,c.splice(0,16));return this},finalize:function(){var a,b=this.o,c=this.r,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.h/
+4294967296));for(b.push(this.h|0);b.length;)x(this,b.splice(0,16));this.reset();return c},N:[],b:[],D:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.N[b]=a(Math.pow(c,0.5)));this.b[b]=a(Math.pow(c,1/3));b++}}};
+function x(a,b){var c,d,e,f=b.slice(0),g=a.r,h=a.b,l=g[0],k=g[1],n=g[2],m=g[3],p=g[4],t=g[5],r=g[6],v=g[7];for(c=0;64>c;c++)16>c?d=f[c]:(d=f[c+1&15],e=f[c+14&15],d=f[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+f[c&15]+f[c+9&15]|0),d=d+v+(p>>>6^p>>>11^p>>>25^p<<26^p<<21^p<<7)+(r^p&(t^r))+h[c],v=r,r=t,t=p,p=m+d|0,m=n,n=k,k=l,l=d+(k&n^m&(k^n))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;g[0]=g[0]+l|0;g[1]=g[1]+k|0;g[2]=g[2]+n|0;g[3]=g[3]+m|0;g[4]=g[4]+p|0;g[5]=g[5]+t|0;g[6]=
+g[6]+r|0;g[7]=g[7]+v|0}
+sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,l=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];7>l&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(f=2;4>f&&k>>>8*f;f++);f<15-l&&(f=15-l);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.L(a,b,c,d,e,f);g=sjcl.mode.ccm.p(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),l=f.clamp(b,h-e),k=f.bitSlice(b,
+h-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));l=sjcl.mode.ccm.p(a,l,c,k,e,b);a=sjcl.mode.ccm.L(a,l.data,c,d,e,b);f.equal(l.tag,a)||q(new sjcl.exception.corrupt("ccm: tag doesn't match"));return l.data},L:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,l=h.l;e/=8;(e%2||4>e||16=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;de.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,
+d(h))),g))},H:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
+sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.p(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.p(u,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt("gcm: tag doesn't match"));return a.data},Z:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.l;e=[0,0,0,0];f=b.slice(0);
+for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},g:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;de&&(a=b.hash(a));for(d=0;dd||0>c)&&q(sjcl.exception.invalid("invalid params to pbkdf2"));"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,l,k=[],n=sjcl.bitArray;for(l=1;32*k.length<(d||1);l++){e=f=a.encrypt(n.concat(b,[l]));for(g=1;gg;g++)e.push(0x100000000*Math.random()|0);for(g=0;g=1<this.j&&(this.j=f);this.F++;
+this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.A=new sjcl.cipher.aes(this.b);for(d=0;4>d&&!(this.f[d]=this.f[d]+1|0,this.f[d]);d++);}for(d=0;d>>=1;this.c[g].update([d,this.C++,2,b,f,a.length].concat(a))}break;case "string":b===s&&(b=a.length);this.c[g].update([d,this.C++,3,b,f,a.length]);this.c[g].update(a);break;default:l=1}l&&q(new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"));this.i[g]+=b;this.d+=b;h===this.m&&(this.isReady()!==this.m&&C("seeded",Math.max(this.j,this.d)),C("progress",this.getProgress()))},isReady:function(a){a=this.I[a!==s?a:this.B];return this.j&&this.j>=a?this.i[0]>this.R&&
+(new Date).valueOf()>this.O?this.u|this.t:this.t:this.d>=a?this.u|this.m:this.m},getProgress:function(a){a=this.I[a?a:this.B];return this.j>=a?1:this.d>a?1:this.d/a},startCollectors:function(){this.q||(this.a={loadTimeCollector:D(this,this.aa),mouseCollector:D(this,this.ba),keyboardCollector:D(this,this.$),accelerometerCollector:D(this,this.U),touchCollector:D(this,this.da)},window.addEventListener?(window.addEventListener("load",this.a.loadTimeCollector,u),window.addEventListener("mousemove",this.a.mouseCollector,
+u),window.addEventListener("keypress",this.a.keyboardCollector,u),window.addEventListener("devicemotion",this.a.accelerometerCollector,u),window.addEventListener("touchmove",this.a.touchCollector,u)):document.attachEvent?(document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector)):q(new sjcl.exception.bug("can't attach event")),this.q=!0)},stopCollectors:function(){this.q&&(window.removeEventListener?
+(window.removeEventListener("load",this.a.loadTimeCollector,u),window.removeEventListener("mousemove",this.a.mouseCollector,u),window.removeEventListener("keypress",this.a.keyboardCollector,u),window.removeEventListener("devicemotion",this.a.accelerometerCollector,u),window.removeEventListener("touchmove",this.a.touchCollector,u)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",this.a.mouseCollector),document.detachEvent("keypress",
+this.a.keyboardCollector)),this.q=u)},addEventListener:function(a,b){this.w[a][this.V++]=b},removeEventListener:function(a,b){var c,d,e=this.w[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;cb&&!(a.f[b]=a.f[b]+1|0,a.f[b]);b++);return a.A.encrypt(a.f)}function D(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
+a:try{var F,G,H,I;if(I="undefined"!==typeof module){var J;if(J=module.exports){var K;try{K=require("crypto")}catch(L){K=null}J=(G=K)&&G.randomBytes}I=J}if(I)F=G.randomBytes(128),F=new Uint32Array((new Uint8Array(F)).buffer),sjcl.random.addEntropy(F,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){H=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(H);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(H);
+else break a;sjcl.random.addEntropy(H,1024,"crypto['getRandomValues']")}}catch(M){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(M))}
+sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},Y:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.e({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.e(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||4<
+f.iv.length)&&q(new sjcl.exception.invalid("json encrypt: invalid parameters"));"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.e(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},
+encrypt:function(a,b,c,d){var e=sjcl.json,f=e.Y.apply(e,arguments);return e.encode(f)},X:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.e(e.e(e.e({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4 postsJSON\n values[1] // => commentsJSON\n\n return values;\n });\n ```\n\n @class Promise\n @param {function} resolver\n Useful for tooling.\n @constructor\n */\n function lib$es6$promise$promise$$Promise(resolver) {\n this._id = lib$es6$promise$promise$$counter++;\n this._state = undefined;\n this._result = undefined;\n this._subscribers = [];\n\n if (lib$es6$promise$$internal$$noop !== resolver) {\n if (!lib$es6$promise$utils$$isFunction(resolver)) {\n lib$es6$promise$promise$$needsResolver();\n }\n\n if (!(this instanceof lib$es6$promise$promise$$Promise)) {\n lib$es6$promise$promise$$needsNew();\n }\n\n lib$es6$promise$$internal$$initializePromise(this, resolver);\n }\n }\n\n lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;\n lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;\n lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;\n lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;\n lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler;\n lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$default;\n\n lib$es6$promise$promise$$Promise.prototype = {\n constructor: lib$es6$promise$promise$$Promise,\n\n /**\n The primary way of interacting with a promise is through its `then` method,\n which registers callbacks to receive either a promise's eventual value or the\n reason why the promise cannot be fulfilled.\n\n ```js\n findUser().then(function(user){\n // user is available\n }, function(reason){\n // user is unavailable, and you are given the reason why\n });\n ```\n\n Chaining\n --------\n\n The return value of `then` is itself a promise. This second, 'downstream'\n promise is resolved with the return value of the first promise's fulfillment\n or rejection handler, or rejected if the handler throws an exception.\n\n ```js\n findUser().then(function (user) {\n return user.name;\n }, function (reason) {\n return 'default name';\n }).then(function (userName) {\n // If `findUser` fulfilled, `userName` will be the user's name, otherwise it\n // will be `'default name'`\n });\n\n findUser().then(function (user) {\n throw new Error('Found user, but still unhappy');\n }, function (reason) {\n throw new Error('`findUser` rejected and we're unhappy');\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.\n // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.\n });\n ```\n If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.\n\n ```js\n findUser().then(function (user) {\n throw new PedagogicalException('Upstream error');\n }).then(function (value) {\n // never reached\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // The `PedgagocialException` is propagated all the way down to here\n });\n ```\n\n Assimilation\n ------------\n\n Sometimes the value you want to propagate to a downstream promise can only be\n retrieved asynchronously. This can be achieved by returning a promise in the\n fulfillment or rejection handler. The downstream promise will then be pending\n until the returned promise is settled. This is called *assimilation*.\n\n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // The user's comments are now available\n });\n ```\n\n If the assimliated promise rejects, then the downstream promise will also reject.\n\n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // If `findCommentsByAuthor` fulfills, we'll have the value here\n }, function (reason) {\n // If `findCommentsByAuthor` rejects, we'll have the reason here\n });\n ```\n\n Simple Example\n --------------\n\n Synchronous Example\n\n ```javascript\n var result;\n\n try {\n result = findResult();\n // success\n } catch(reason) {\n // failure\n }\n ```\n\n Errback Example\n\n ```js\n findResult(function(result, err){\n if (err) {\n // failure\n } else {\n // success\n }\n });\n ```\n\n Promise Example;\n\n ```javascript\n findResult().then(function(result){\n // success\n }, function(reason){\n // failure\n });\n ```\n\n Advanced Example\n --------------\n\n Synchronous Example\n\n ```javascript\n var author, books;\n\n try {\n author = findAuthor();\n books = findBooksByAuthor(author);\n // success\n } catch(reason) {\n // failure\n }\n ```\n\n Errback Example\n\n ```js\n\n function foundBooks(books) {\n\n }\n\n function failure(reason) {\n\n }\n\n findAuthor(function(author, err){\n if (err) {\n failure(err);\n // failure\n } else {\n try {\n findBoooksByAuthor(author, function(books, err) {\n if (err) {\n failure(err);\n } else {\n try {\n foundBooks(books);\n } catch(reason) {\n failure(reason);\n }\n }\n });\n } catch(error) {\n failure(err);\n }\n // success\n }\n });\n ```\n\n Promise Example;\n\n ```javascript\n findAuthor().\n then(findBooksByAuthor).\n then(function(books){\n // found books\n }).catch(function(reason){\n // something went wrong\n });\n ```\n\n @method then\n @param {Function} onFulfilled\n @param {Function} onRejected\n Useful for tooling.\n @return {Promise}\n */\n then: function(onFulfillment, onRejection) {\n var parent = this;\n var state = parent._state;\n\n if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) {\n return this;\n }\n\n var child = new this.constructor(lib$es6$promise$$internal$$noop);\n var result = parent._result;\n\n if (state) {\n var callback = arguments[state - 1];\n lib$es6$promise$asap$$default(function(){\n lib$es6$promise$$internal$$invokeCallback(state, child, callback, result);\n });\n } else {\n lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);\n }\n\n return child;\n },\n\n /**\n `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same\n as the catch block of a try/catch statement.\n\n ```js\n function findAuthor(){\n throw new Error('couldn't find that author');\n }\n\n // synchronous\n try {\n findAuthor();\n } catch(reason) {\n // something went wrong\n }\n\n // async with promises\n findAuthor().catch(function(reason){\n // something went wrong\n });\n ```\n\n @method catch\n @param {Function} onRejection\n Useful for tooling.\n @return {Promise}\n */\n 'catch': function(onRejection) {\n return this.then(null, onRejection);\n }\n };\n function lib$es6$promise$polyfill$$polyfill() {\n var local;\n\n if (typeof global !== 'undefined') {\n local = global;\n } else if (typeof self !== 'undefined') {\n local = self;\n } else {\n try {\n local = Function('return this')();\n } catch (e) {\n throw new Error('polyfill failed because global object is unavailable in this environment');\n }\n }\n\n var P = local.Promise;\n\n if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) {\n return;\n }\n\n local.Promise = lib$es6$promise$promise$$default;\n }\n var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;\n\n var lib$es6$promise$umd$$ES6Promise = {\n 'Promise': lib$es6$promise$promise$$default,\n 'polyfill': lib$es6$promise$polyfill$$default\n };\n\n /* global define:true module:true window: true */\n if (typeof define === 'function' && define['amd']) {\n define(function() { return lib$es6$promise$umd$$ES6Promise; });\n } else if (typeof module !== 'undefined' && module['exports']) {\n module['exports'] = lib$es6$promise$umd$$ES6Promise;\n } else if (typeof this !== 'undefined') {\n this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise;\n }\n\n lib$es6$promise$polyfill$$default();\n}).call(this);\n\n","\"use strict\";function q(a){throw a;}var s=void 0,u=!1;var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return\"CORRUPT: \"+this.message};this.message=a},invalid:function(a){this.toString=function(){return\"INVALID: \"+this.message};this.message=a},bug:function(a){this.toString=function(){return\"BUG: \"+this.message};this.message=a},notReady:function(a){this.toString=function(){return\"NOT READY: \"+this.message};this.message=a}}};\n\"undefined\"!==typeof module&&module.exports&&(module.exports=sjcl);\"function\"===typeof define&&define([],function(){return sjcl});\nsjcl.cipher.aes=function(a){this.k[0][0][0]||this.D();var b,c,d,e,f=this.k[0][4],g=this.k[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid(\"invalid aes key size\"));this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&\n255]]};\nsjcl.cipher.aes.prototype={encrypt:function(a){return w(this,a,0)},decrypt:function(a){return w(this,a,1)},k:[[[],[],[],[],[]],[[],[],[],[],[]]],D:function(){var a=this.k[0],b=this.k[1],c=a[4],d=b[4],e,f,g,h=[],l=[],k,n,m,p;for(e=0;0x100>e;e++)l[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=k||1,g=l[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[k=h[f]]];p=0x1010101*n^0x10001*e^0x101*k^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=\n0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};\nfunction w(a,b,c){4!==b.length&&q(new sjcl.exception.invalid(\"invalid aes block size\"));var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,l,k,n=d.length/4-2,m,p=4,t=[0,0,0,0];h=a.k[c];a=h[0];var r=h[1],v=h[2],y=h[3],z=h[4];for(m=0;m>>24]^r[f>>16&255]^v[g>>8&255]^y[b&255]^d[p],l=a[f>>>24]^r[g>>16&255]^v[b>>8&255]^y[e&255]^d[p+1],k=a[g>>>24]^r[b>>16&255]^v[e>>8&255]^y[f&255]^d[p+2],b=a[b>>>24]^r[e>>16&255]^v[f>>8&255]^y[g&255]^d[p+3],p+=4,e=h,f=l,g=k;for(m=0;4>\nm;m++)t[c?3&-m:m]=z[e>>>24]<<24^z[f>>16&255]<<16^z[g>>8&255]<<8^z[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return t}\nsjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===s?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return u;var c=0,d;for(d=0;d>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};\nsjcl.codec.utf8String={fromBits:function(a){var b=\"\",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+=\"=\";return d},toBits:function(a,b){a=a.replace(/\\s|=/g,\"\");var c=[],d,e=0,f=sjcl.codec.base64.J,g=0,h;b&&(f=f.substr(0,62)+\"-_\");for(d=0;dh&&q(new sjcl.exception.invalid(\"this isn't base64!\")),26>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.D();a?(this.r=a.r.slice(0),this.o=a.o.slice(0),this.h=a.h):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};\nsjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.r=this.N.slice(0);this.o=[];this.h=0;return this},update:function(a){\"string\"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.o=sjcl.bitArray.concat(this.o,a);b=this.h;a=this.h=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)x(this,c.splice(0,16));return this},finalize:function(){var a,b=this.o,c=this.r,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.h/\n4294967296));for(b.push(this.h|0);b.length;)x(this,b.splice(0,16));this.reset();return c},N:[],b:[],D:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.N[b]=a(Math.pow(c,0.5)));this.b[b]=a(Math.pow(c,1/3));b++}}};\nfunction x(a,b){var c,d,e,f=b.slice(0),g=a.r,h=a.b,l=g[0],k=g[1],n=g[2],m=g[3],p=g[4],t=g[5],r=g[6],v=g[7];for(c=0;64>c;c++)16>c?d=f[c]:(d=f[c+1&15],e=f[c+14&15],d=f[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+f[c&15]+f[c+9&15]|0),d=d+v+(p>>>6^p>>>11^p>>>25^p<<26^p<<21^p<<7)+(r^p&(t^r))+h[c],v=r,r=t,t=p,p=m+d|0,m=n,n=k,k=l,l=d+(k&n^m&(k^n))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;g[0]=g[0]+l|0;g[1]=g[1]+k|0;g[2]=g[2]+n|0;g[3]=g[3]+m|0;g[4]=g[4]+p|0;g[5]=g[5]+t|0;g[6]=\ng[6]+r|0;g[7]=g[7]+v|0}\nsjcl.mode.ccm={name:\"ccm\",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,l=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];7>l&&q(new sjcl.exception.invalid(\"ccm: iv must be at least 7 bytes\"));for(f=2;4>f&&k>>>8*f;f++);f<15-l&&(f=15-l);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.L(a,b,c,d,e,f);g=sjcl.mode.ccm.p(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),l=f.clamp(b,h-e),k=f.bitSlice(b,\nh-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid(\"ccm: iv must be at least 7 bytes\"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));l=sjcl.mode.ccm.p(a,l,c,k,e,b);a=sjcl.mode.ccm.L(a,l.data,c,d,e,b);f.equal(l.tag,a)||q(new sjcl.exception.corrupt(\"ccm: tag doesn't match\"));return l.data},L:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,l=h.l;e/=8;(e%2||4>e||16=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;de.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,\nd(h))),g))},H:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};\nsjcl.mode.gcm={name:\"gcm\",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.p(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.p(u,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt(\"gcm: tag doesn't match\"));return a.data},Z:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.l;e=[0,0,0,0];f=b.slice(0);\nfor(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},g:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;de&&(a=b.hash(a));for(d=0;dd||0>c)&&q(sjcl.exception.invalid(\"invalid params to pbkdf2\"));\"string\"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));\"string\"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,l,k=[],n=sjcl.bitArray;for(l=1;32*k.length<(d||1);l++){e=f=a.encrypt(n.concat(b,[l]));for(g=1;gg;g++)e.push(0x100000000*Math.random()|0);for(g=0;g=1<this.j&&(this.j=f);this.F++;\nthis.b=sjcl.hash.sha256.hash(this.b.concat(e));this.A=new sjcl.cipher.aes(this.b);for(d=0;4>d&&!(this.f[d]=this.f[d]+1|0,this.f[d]);d++);}for(d=0;d>>=1;this.c[g].update([d,this.C++,2,b,f,a.length].concat(a))}break;case \"string\":b===s&&(b=a.length);this.c[g].update([d,this.C++,3,b,f,a.length]);this.c[g].update(a);break;default:l=1}l&&q(new sjcl.exception.bug(\"random: addEntropy only supports number, array of numbers or string\"));this.i[g]+=b;this.d+=b;h===this.m&&(this.isReady()!==this.m&&C(\"seeded\",Math.max(this.j,this.d)),C(\"progress\",this.getProgress()))},isReady:function(a){a=this.I[a!==s?a:this.B];return this.j&&this.j>=a?this.i[0]>this.R&&\n(new Date).valueOf()>this.O?this.u|this.t:this.t:this.d>=a?this.u|this.m:this.m},getProgress:function(a){a=this.I[a?a:this.B];return this.j>=a?1:this.d>a?1:this.d/a},startCollectors:function(){this.q||(this.a={loadTimeCollector:D(this,this.aa),mouseCollector:D(this,this.ba),keyboardCollector:D(this,this.$),accelerometerCollector:D(this,this.U),touchCollector:D(this,this.da)},window.addEventListener?(window.addEventListener(\"load\",this.a.loadTimeCollector,u),window.addEventListener(\"mousemove\",this.a.mouseCollector,\nu),window.addEventListener(\"keypress\",this.a.keyboardCollector,u),window.addEventListener(\"devicemotion\",this.a.accelerometerCollector,u),window.addEventListener(\"touchmove\",this.a.touchCollector,u)):document.attachEvent?(document.attachEvent(\"onload\",this.a.loadTimeCollector),document.attachEvent(\"onmousemove\",this.a.mouseCollector),document.attachEvent(\"keypress\",this.a.keyboardCollector)):q(new sjcl.exception.bug(\"can't attach event\")),this.q=!0)},stopCollectors:function(){this.q&&(window.removeEventListener?\n(window.removeEventListener(\"load\",this.a.loadTimeCollector,u),window.removeEventListener(\"mousemove\",this.a.mouseCollector,u),window.removeEventListener(\"keypress\",this.a.keyboardCollector,u),window.removeEventListener(\"devicemotion\",this.a.accelerometerCollector,u),window.removeEventListener(\"touchmove\",this.a.touchCollector,u)):document.detachEvent&&(document.detachEvent(\"onload\",this.a.loadTimeCollector),document.detachEvent(\"onmousemove\",this.a.mouseCollector),document.detachEvent(\"keypress\",\nthis.a.keyboardCollector)),this.q=u)},addEventListener:function(a,b){this.w[a][this.V++]=b},removeEventListener:function(a,b){var c,d,e=this.w[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;cb&&!(a.f[b]=a.f[b]+1|0,a.f[b]);b++);return a.A.encrypt(a.f)}function D(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);\na:try{var F,G,H,I;if(I=\"undefined\"!==typeof module){var J;if(J=module.exports){var K;try{K=require(\"crypto\")}catch(L){K=null}J=(G=K)&&G.randomBytes}I=J}if(I)F=G.randomBytes(128),F=new Uint32Array((new Uint8Array(F)).buffer),sjcl.random.addEntropy(F,1024,\"crypto['randomBytes']\");else if(\"undefined\"!==typeof window&&\"undefined\"!==typeof Uint32Array){H=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(H);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(H);\nelse break a;sjcl.random.addEntropy(H,1024,\"crypto['getRandomValues']\")}}catch(M){\"undefined\"!==typeof window&&window.console&&(console.log(\"There was an error collecting entropy from the browser:\"),console.log(M))}\nsjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:\"ccm\",adata:\"\",cipher:\"aes\"},Y:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.e({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.e(f,c);c=f.adata;\"string\"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));\"string\"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||\"string\"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||4<\nf.iv.length)&&q(new sjcl.exception.invalid(\"json encrypt: invalid parameters\"));\"string\"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));\"string\"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));\"string\"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.e(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},\nencrypt:function(a,b,c,d){var e=sjcl.json,f=e.Y.apply(e,arguments);return e.encode(f)},X:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.e(e.e(e.e({},e.defaults),b),c,!0);var f,g;f=b.adata;\"string\"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));\"string\"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||\"string\"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4