From ef1d72a2cec7c2d15651df24f639c6ce31953aaa Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 26 Apr 2018 16:20:17 +0200 Subject: [PATCH 01/72] trying to get encryption working --- mmt-metadata.js | 167 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 49 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 43fffd2..a8ecbc7 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -1,14 +1,30 @@ +// todo: +// electron front end +// encrypt messages +// interact with wallet +// re-write rates tool into node var pull = require('pull-stream') var ssbClient = require('ssb-client') +var count = 0 + // will hold current payments var payments = {} +var verbose = true + ssbClient(function (err, sbot) { - console.log('ssb ready.') + if (verbose) console.log('ssb ready.') + // In order for messages to be encrypted we need to specify recipients + // there can be a maximum of 7, which means if we wanted more we need multiple + // messages + // + // in order to use this script you need to set this to your own public key + // or make new one for test perposes + var recipients = ['@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519'] var payment = { @@ -24,7 +40,7 @@ ssbClient(function (err, sbot) { comments: [] } - //addPayment(sbot, payment) + // addPayment(sbot, payment, recipients) var paymentComment = { @@ -33,55 +49,110 @@ ssbClient(function (err, sbot) { comment: 'this payment was a mistake' } - //addPaymentComment(sbot, paymentComment) + // addPaymentComment(sbot, paymentComment, recipients) - pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) + //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) + + pull( + sbot.createLogStream(), + pull.collect(function (err, msgs) { + msgs.forEach( function (item,index) { + decryptAndProcess(sbot,item) + } ) + }) + ) //pull(sbot.messagesByType({ type: 'addMmtPaymentTest', live: true }), pull.drain(processMsg)) - sbot.close() }) function testPublish() { //publish a test message sbot.publish({ type: 'testtype', text: 'hello, scuttleverse' }, function (err, msg) { - console.log(msg.key) - console.log(msg.value.author) - console.log(msg.value.content) - + if (verbose) { + console.log(msg.key) + console.log(msg.value.author) + console.log(msg.value.content) + } }) } - -function processMsg (msg) { + + +function decryptAndProcess (sbot,msg){ + sbot.private.unbox(msg, function (err, msg) { + if (msg) { + switch(msg.value.content.type) { + + case 'addMmtPaymentTest': + if (verbose) { + console.log('Found a payment:') + console.log(msg.value.content) + } + + // if we've never seen this transaction before, add it + if (!payments[msg.value.content.payment.key]) { + payments[msg.value.content.payment.key] = msg.value.content.payment + } else { + // what to do here? + } + break + + case 'modifyMmtPaymentTest': + if (verbose) { + console.log('Found a payment comment:') + console.log(msg.value.content) + } + payments[msg.value.content.paymentComment.key].comments.push( { + author: msg.value.author, + comment: msg.value.content.paymentComment.comment + } ) + } + } + }) +} + +function processMsg (message) { // process a message from the drain // is this the right way to handle the end of the message stream? try { - if (msg) - switch(msg.value.content.type) { - - case 'addMmtPaymentTest': - console.log('Found a payment:') - console.log(msg.value.content) - - // if we've never seen this transaction before, add it - if (!payments[msg.value.content.payment.key]) { - payments[msg.value.content.payment.key] = msg.value.content.payment - } else { - // what to do here? - } - break - case 'modifyMmtPaymentTest': - console.log('Found a payment comment:') - console.log(msg.value.content) - payments[msg.value.content.paymentComment.key].comments.push( { - author: msg.value.author, - comment: msg.value.content.paymentComment.comment - } ) - - } - + count++ + console.log(count) + if (message) + console.log(message) + // attempt to decrypt message + sbot.private.unbox(message, function (err, msg) { + if (msg) { + switch(msg.value.content.type) { + + case 'addMmtPaymentTest': + if (verbose) { + console.log('Found a payment:') + console.log(msg.value.content) + } + + // if we've never seen this transaction before, add it + if (!payments[msg.value.content.payment.key]) { + payments[msg.value.content.payment.key] = msg.value.content.payment + } else { + // what to do here? + } + break + + case 'modifyMmtPaymentTest': + if (verbose) { + console.log('Found a payment comment:') + console.log(msg.value.content) + } + payments[msg.value.content.paymentComment.key].comments.push( { + author: msg.value.author, + comment: msg.value.content.paymentComment.comment + } ) + } + } + }) } catch(e) { + // when we've processed all messagese displayPayments() return false } @@ -102,27 +173,25 @@ function pullWithFeedStream() { -function addPayment(sbot, paymentToAdd) { +function addPayment(sbot, paymentToAdd, recipients) { - sbot.publish({ type: 'addMmtPaymentTest', payment: paymentToAdd }, function (err, msg) { - console.log('Adding payment:') - console.log(msg.key) - console.log(msg.value.author) - console.log(msg.value.content) - + sbot.private.publish({ type: 'addMmtPaymentTest', payment: paymentToAdd }, recipients, function (err, msg) { + if (verbose) { + console.log('Adding payment:') + console.log(JSON.stringify(msg, null, 4)) + } }) } -function addPaymentComment(sbot, paymentComment) { - - sbot.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, function (err, msg) { - console.log('Adding payment Comment:') - console.log(msg.key) - console.log(msg.value.author) - console.log(msg.value.content) +function addPaymentComment(sbot, paymentComment, recipients) { + sbot.private.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, recipients, function (err, msg) { + if (verbose) { + console.log('Adding payment Comment:') + console.log(JSON.stringify(msg, null, 4)) + } }) } From 4590bafec2cc7caacb47e3be1a36975b7d054ecb Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 27 Apr 2018 12:08:17 +0200 Subject: [PATCH 02/72] finally works with private messages --- mmt-metadata.js | 211 ++++++++++++++++++++++++++---------------------- readme.md | 3 + 2 files changed, 117 insertions(+), 97 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index a8ecbc7..767db70 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -1,31 +1,50 @@ // todo: +// save db locally (as json file?) +// make less ugly +// speed up somehow -scanning messages takes ages making debugging slow // electron front end -// encrypt messages -// interact with wallet +// interact with wallet either electrum locally or bitcoin on a server // re-write rates tool into node +// make more modular -split into many tiny node modules var pull = require('pull-stream') var ssbClient = require('ssb-client') -var count = 0 // will hold current payments var payments = {} var verbose = true +var cosigners = [ + { + name: 'alice', // i think theres away to grab this from ssb's 'about' + // message. probably avatar image as well + // this is my own public key (which one could get using ssb-keys, key.id) + // you wont be able to decrypt messages made using this script without your + // own public key + ssbPubKey: '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519', + // this will be an array of bitcoin addresses, which we will pop off and not reuse. + addresses: ['bc1sdfljsdl','bc1ldskfjsdfl'] + + } + // other cosigners will be added here +] + + ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') // In order for messages to be encrypted we need to specify recipients // there can be a maximum of 7, which means if we wanted more we need multiple // messages - // - // in order to use this script you need to set this to your own public key - // or make new one for test perposes - var recipients = ['@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519'] + + // in most cases we want all cosigners as recipients, but for partially signed + // transactions we would want only those who are designated to sign + var recipients = [cosigners[0].ssbPubkey] + // an example payment to add to the db var payment = { // the 'key' would be a bitcoin transaction id @@ -42,31 +61,63 @@ ssbClient(function (err, sbot) { // addPayment(sbot, payment, recipients) + // an example payment comment to add to the db var paymentComment = { key: 'd5f2a6a8cd1e8c35466cfec16551', comment: 'this payment was a mistake' } + // addPaymentComment(sbot, paymentComment, recipients) - + //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) + + // collect waits till we have everything then give us an array + // pull( + // sbot.createLogStream(), + // pull.collect(function (err, msgs) { + // msgs.forEach( function (item,index) { + // decryptAndProcess(sbot,item) + // } ) + // }) + // ) + + // drain lets us process stuff as it comes + pull(sbot.createLogStream({ live: true }), pull.drain(function (message){ + try { + if (message.value.content) { + // attempt to decrypt message + try { + sbot.private.unbox(message.value.content, function (err, msg) { + if (msg) { + //console.log('decrypted a message') + //console.log(msg) + processMsg(msg) + } + //console.log('eer: ', err) + }) + } catch(e) { + console.log('error while decrypting') + } + + } + } catch(e) { + displayPayments() + + + sbot.close() + // why? + return false + } - pull( - sbot.createLogStream(), - pull.collect(function (err, msgs) { - msgs.forEach( function (item,index) { - decryptAndProcess(sbot,item) - } ) - }) - ) - //pull(sbot.messagesByType({ type: 'addMmtPaymentTest', live: true }), pull.drain(processMsg)) + })) - sbot.close() }) + function testPublish() { //publish a test message sbot.publish({ type: 'testtype', text: 'hello, scuttleverse' }, function (err, msg) { @@ -79,83 +130,35 @@ function testPublish() { } -function decryptAndProcess (sbot,msg){ - sbot.private.unbox(msg, function (err, msg) { - if (msg) { - switch(msg.value.content.type) { - - case 'addMmtPaymentTest': - if (verbose) { - console.log('Found a payment:') - console.log(msg.value.content) - } - - // if we've never seen this transaction before, add it - if (!payments[msg.value.content.payment.key]) { - payments[msg.value.content.payment.key] = msg.value.content.payment - } else { - // what to do here? - } - break - - case 'modifyMmtPaymentTest': - if (verbose) { - console.log('Found a payment comment:') - console.log(msg.value.content) - } - payments[msg.value.content.paymentComment.key].comments.push( { - author: msg.value.author, - comment: msg.value.content.paymentComment.comment - } ) - } - } - }) -} -function processMsg (message) { - // process a message from the drain - // is this the right way to handle the end of the message stream? - try { - count++ - console.log(count) - if (message) - console.log(message) - // attempt to decrypt message - sbot.private.unbox(message, function (err, msg) { - if (msg) { - switch(msg.value.content.type) { - - case 'addMmtPaymentTest': - if (verbose) { - console.log('Found a payment:') - console.log(msg.value.content) - } - - // if we've never seen this transaction before, add it - if (!payments[msg.value.content.payment.key]) { - payments[msg.value.content.payment.key] = msg.value.content.payment - } else { - // what to do here? - } - break - - case 'modifyMmtPaymentTest': - if (verbose) { - console.log('Found a payment comment:') - console.log(msg.value.content) - } - payments[msg.value.content.paymentComment.key].comments.push( { - author: msg.value.author, - comment: msg.value.content.paymentComment.comment - } ) - } - } - }) - } catch(e) { - // when we've processed all messagese - displayPayments() - return false - } +function processMsg (msg) { + // process an unencrypted message + switch(msg.type) { + + case 'addMmtPaymentTest': + if (verbose) { + console.log('Found a payment:') + //console.log(msg) + } + + // if we've never seen this transaction before, add it + if (!payments[msg.payment.key]) { + payments[msg.payment.key] = msg.payment + } else { + // what to do here? + } + break + + case 'modifyMmtPaymentTest': + if (verbose) { + console.log('Found a payment comment:') + } + payments[msg.paymentComment.key].comments.push( { + // todo get the order from higher up and pass it to this function + //author: msg.value.author, + comment: msg.paymentComment.comment + } ) + } } function pullWithFeedStream() { @@ -177,7 +180,7 @@ function addPayment(sbot, paymentToAdd, recipients) { sbot.private.publish({ type: 'addMmtPaymentTest', payment: paymentToAdd }, recipients, function (err, msg) { if (verbose) { - console.log('Adding payment:') + console.log('Added payment:') console.log(JSON.stringify(msg, null, 4)) } }) @@ -189,7 +192,7 @@ function addPaymentComment(sbot, paymentComment, recipients) { sbot.private.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, recipients, function (err, msg) { if (verbose) { - console.log('Adding payment Comment:') + console.log('Added payment Comment:') console.log(JSON.stringify(msg, null, 4)) } }) @@ -197,8 +200,22 @@ function addPaymentComment(sbot, paymentComment, recipients) { } function displayPayments() { - + // this would be the place to create a snazzy html table console.log('payments now looks like this:') console.log(JSON.stringify(payments, null, 4)) + +} + +function exampleDecryptMessage() { + + // this is an example of decrypting a message that i know worked for me + // (it wont work for you as its for me but shows the idea) + sbot.get('%69q4XMVlrwG3GAeykTQLiU/oZlRvF7bRZFAR1CmECIA=.sha256', function(err,msg) { + if (err) console.error(err) + sbot.private.unbox(msg.content, function (err,msg) { + if (err) console.error(err) + console.log(msg) + }) + }) } diff --git a/readme.md b/readme.md index add7804..a5fa2cb 100644 --- a/readme.md +++ b/readme.md @@ -7,3 +7,6 @@ Multi-sig wallets such as Electrum do not allow us to see cosigners in payment h This project will use secure-scuttlebutt to store this information, as well as to provide a mechanism for sending and viewing partially signed transactions. Currently its a work in progress. + +* [pull-stream docs](https://pull-stream.github.io/) +* [Scuttlebot API - Scuttlebot](https://scuttlebot.io/apis/scuttlebot/ssb.html) From 23df161a2bd3a6f59dc7aaa5a5b81fc03dded14b Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 27 Apr 2018 12:55:18 +0200 Subject: [PATCH 03/72] write locally to json file --- .gitignore | 1 + mmt-metadata.js | 194 ++++++++++++++++++++++++++-------------------- package-lock.json | 5 ++ package.json | 1 + 4 files changed, 116 insertions(+), 85 deletions(-) diff --git a/.gitignore b/.gitignore index c2658d7..469e144 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +localdb.json diff --git a/mmt-metadata.js b/mmt-metadata.js index 767db70..2cae60c 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -1,6 +1,5 @@ // todo: -// save db locally (as json file?) // make less ugly // speed up somehow -scanning messages takes ages making debugging slow // electron front end @@ -10,9 +9,11 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') +var fs = require('fs'); - +var localDbFile = './localdb.json' // will hold current payments +// yes i know global variables bad im gonna tidy it up var payments = {} var verbose = true @@ -33,89 +34,6 @@ var cosigners = [ ] -ssbClient(function (err, sbot) { - if (verbose) console.log('ssb ready.') - - // In order for messages to be encrypted we need to specify recipients - // there can be a maximum of 7, which means if we wanted more we need multiple - // messages - - // in most cases we want all cosigners as recipients, but for partially signed - // transactions we would want only those who are designated to sign - var recipients = [cosigners[0].ssbPubkey] - - // an example payment to add to the db - var payment = { - - // the 'key' would be a bitcoin transaction id - key: 'd5f2a6a8cd1e8c35466cfec16551', - - // the actual metadata - // note - no date, amounts or recieve addresses - for this we have a better - // source of truth - rate: 5000, - cosigners: ['ssbpublickey1', 'ssbpublickey2'], - description: 'this is just an example', - comments: [] - } - - // addPayment(sbot, payment, recipients) - - // an example payment comment to add to the db - var paymentComment = { - - key: 'd5f2a6a8cd1e8c35466cfec16551', - - comment: 'this payment was a mistake' - } - - - // addPaymentComment(sbot, paymentComment, recipients) - - //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) - - // collect waits till we have everything then give us an array - // pull( - // sbot.createLogStream(), - // pull.collect(function (err, msgs) { - // msgs.forEach( function (item,index) { - // decryptAndProcess(sbot,item) - // } ) - // }) - // ) - - // drain lets us process stuff as it comes - pull(sbot.createLogStream({ live: true }), pull.drain(function (message){ - try { - if (message.value.content) { - // attempt to decrypt message - try { - sbot.private.unbox(message.value.content, function (err, msg) { - if (msg) { - //console.log('decrypted a message') - //console.log(msg) - processMsg(msg) - } - //console.log('eer: ', err) - }) - } catch(e) { - console.log('error while decrypting') - } - - } - } catch(e) { - displayPayments() - - - sbot.close() - // why? - return false - } - - })) - - -}) function testPublish() { @@ -219,3 +137,109 @@ function exampleDecryptMessage() { }) } + +function readDbLocally() { + // for now just use a file as db is not likely to get big + fs.readFile(localDbFile,function(err,content){ + if(err) { return {} + } else { + if (verbose) console.log('read locally: ',JSON.stringify(JSON.parse(content),null,4)) + return JSON.parse(content) } + + }) +} + +function writeDbLocally() { + if (verbose) console.log('writing locally') + fs.writeFile(localDbFile,JSON.stringify(payments),function(err){ + if(err) throw err + }) +} + +payments = readDbLocally() +// if the file didnt exist yet (sort this out) +if (typeof(payments) === 'undefined') payments = {} + +ssbClient(function (err, sbot) { + if (verbose) console.log('ssb ready.') + + // In order for messages to be encrypted we need to specify recipients + // there can be a maximum of 7, which means if we wanted more we need multiple + // messages + + // in most cases we want all cosigners as recipients, but for partially signed + // transactions we would want only those who are designated to sign + var recipients = [cosigners[0].ssbPubkey] + + // an example payment to add to the db + var payment = { + + // the 'key' would be a bitcoin transaction id + key: 'd5f2a6a8cd1e8c35466cfec16551', + + // the actual metadata + // note - no date, amounts or recieve addresses - for this we have a better + // source of truth + rate: 5000, + cosigners: ['ssbpublickey1', 'ssbpublickey2'], + description: 'this is just an example', + comments: [] + } + + // addPayment(sbot, payment, recipients) + + // an example payment comment to add to the db + var paymentComment = { + + key: 'd5f2a6a8cd1e8c35466cfec16551', + + comment: 'this payment was a mistake' + } + + + // addPaymentComment(sbot, paymentComment, recipients) + + //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) + + // collect waits till we have everything then give us an array + // pull( + // sbot.createLogStream(), + // pull.collect(function (err, msgs) { + // msgs.forEach( function (item,index) { + // decryptAndProcess(sbot,item) + // } ) + // }) + // ) + + // drain lets us process stuff as it comes + pull(sbot.createLogStream({ live: true }), pull.drain(function (message){ + try { + if (message.value.content) { + // attempt to decrypt message + try { + sbot.private.unbox(message.value.content, function (err, msg) { + if (msg) { + //console.log('decrypted a message') + //console.log(msg) + processMsg(msg) + } + //console.log('eer: ', err) + }) + } catch(e) { + console.log('error while decrypting') + } + + } + } catch(e) { + displayPayments() + writeDbLocally() + + sbot.close() + // why? + return false + } + + })) + + +}) diff --git a/package-lock.json b/package-lock.json index 803d5e6..0bef294 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,11 @@ "resolved": "https://registry.npmjs.org/explain-error/-/explain-error-1.0.4.tgz", "integrity": "sha1-p5PTrAytTGq1cemWj7urbLJTKSk=" }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" + }, "increment-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/increment-buffer/-/increment-buffer-1.0.1.tgz", diff --git a/package.json b/package.json index 00c33a2..14d33db 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "author": "", "license": "ISC", "dependencies": { + "fs": "0.0.1-security", "pull-stream": "^3.6.7", "sbot": "0.0.3", "ssb-client": "^4.5.7" From f06907e08006cd192de877805154fdfa977ddb1f Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 27 Apr 2018 13:01:14 +0200 Subject: [PATCH 04/72] electron hello world --- index.html | 11 +++++++++++ main.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 index.html create mode 100644 main.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..0562312 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + mmt payment metadata app + + +

mmt payment metadata app

+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..c08e532 --- /dev/null +++ b/main.js @@ -0,0 +1,56 @@ +const electron = require('electron') +// Module to control application life. + +const app = electron.app + +// Module to create native browser window. +const BrowserWindow = electron.BrowserWindow + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow + +function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({width: 800, height: 600}) + + // and load the index.html of the app. + mainWindow.loadURL(`file://${__dirname}/index.html`) + + // Open the DevTools. + //mainWindow.webContents.openDevTools() + + // Emitted when the window is closed. + mainWindow.on('closed', function () { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null + }) +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.on('ready', createWindow) + +// Quit when all windows are closed. +app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit() + } +}) + +app.on('activate', function () { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow() + } +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. +require ('./mmt-metadata.js') diff --git a/package.json b/package.json index 14d33db..0d0a283 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mmt-metadata", "version": "1.0.0", "description": "first stab at fiddling with sbot", - "main": "mmt-metadata.js", + "main": "main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, From fdd37eb9b2a963b4739d9fa8f36ef1d752b61159 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 27 Apr 2018 13:02:43 +0200 Subject: [PATCH 05/72] readme --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index a5fa2cb..08d1af7 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,5 @@ +## mmt-metadata Using ssb to record metadata associated with multi-signature bitcoin transactions. @@ -8,5 +9,7 @@ This project will use secure-scuttlebutt to store this information, as well as t Currently its a work in progress. +electron front end in a separate branch + * [pull-stream docs](https://pull-stream.github.io/) * [Scuttlebot API - Scuttlebot](https://scuttlebot.io/apis/scuttlebot/ssb.html) From 1856f304838b8478a5be674c0a481d25f8811f3c Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 27 Apr 2018 14:22:34 +0200 Subject: [PATCH 06/72] cant get electron and jquery to work together --- index.html | 11 ++++++++++- main.js | 4 +++- mmt-metadata.js | 3 +++ scripts/jquery-3.3.1.min.js | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 scripts/jquery-3.3.1.min.js diff --git a/index.html b/index.html index 0562312..01e855f 100644 --- a/index.html +++ b/index.html @@ -3,9 +3,18 @@ mmt payment metadata app + + + + + + + + +

mmt payment metadata app

- +
diff --git a/main.js b/main.js index c08e532..6f8ed61 100644 --- a/main.js +++ b/main.js @@ -53,4 +53,6 @@ app.on('activate', function () { // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here. -require ('./mmt-metadata.js') +//require ('./mmt-metadata.js') + +$("#putStuffHere").html('

hello

') diff --git a/mmt-metadata.js b/mmt-metadata.js index 2cae60c..bb1e30d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -119,6 +119,7 @@ function addPaymentComment(sbot, paymentComment, recipients) { function displayPayments() { // this would be the place to create a snazzy html table + console.log('payments now looks like this:') console.log(JSON.stringify(payments, null, 4)) @@ -156,6 +157,8 @@ function writeDbLocally() { }) } + $("#putStuffHere").html('

hello

') + payments = readDbLocally() // if the file didnt exist yet (sort this out) if (typeof(payments) === 'undefined') payments = {} diff --git a/scripts/jquery-3.3.1.min.js b/scripts/jquery-3.3.1.min.js new file mode 100644 index 0000000..4d9b3a2 --- /dev/null +++ b/scripts/jquery-3.3.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + - + - -

mmt payment metadata app

diff --git a/main.js b/main.js index 6f8ed61..c66fcad 100644 --- a/main.js +++ b/main.js @@ -54,5 +54,3 @@ app.on('activate', function () { // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here. //require ('./mmt-metadata.js') - -$("#putStuffHere").html('

hello

') diff --git a/mmt-metadata.js b/mmt-metadata.js index bb1e30d..3ffb554 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -56,6 +56,7 @@ function processMsg (msg) { case 'addMmtPaymentTest': if (verbose) { console.log('Found a payment:') + $("#putStuffHere").append("

" + msg.payment.key + "

") //console.log(msg) } @@ -172,7 +173,7 @@ ssbClient(function (err, sbot) { // in most cases we want all cosigners as recipients, but for partially signed // transactions we would want only those who are designated to sign - var recipients = [cosigners[0].ssbPubkey] + var recipients = [cosigners[0].ssbPubKey] // an example payment to add to the db var payment = { @@ -215,7 +216,7 @@ ssbClient(function (err, sbot) { // ) // drain lets us process stuff as it comes - pull(sbot.createLogStream({ live: true }), pull.drain(function (message){ + pull(sbot.messagesByType({ live: true, type: "addMmtPaymentTest" }), pull.drain(function (message){ try { if (message.value.content) { // attempt to decrypt message From 6f9a69a811ad16f7d0a80388f2617b6aef40d52c Mon Sep 17 00:00:00 2001 From: ameba23 Date: Sat, 28 Apr 2018 20:09:48 +0200 Subject: [PATCH 15/72] try to make a table --- mmt-metadata.js | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 3ffb554..3b03c9c 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -13,8 +13,10 @@ var fs = require('fs'); var localDbFile = './localdb.json' // will hold current payments + + // yes i know global variables bad im gonna tidy it up -var payments = {} +//var payments = {} var verbose = true @@ -56,16 +58,21 @@ function processMsg (msg) { case 'addMmtPaymentTest': if (verbose) { console.log('Found a payment:') - $("#putStuffHere").append("

" + msg.payment.key + "

") + $("#putStuffHere").append("" + msg.payment.key + ""+msg.payment.description+"") //console.log(msg) } - + + payments = readDbLocally() + // if we've never seen this transaction before, add it if (!payments[msg.payment.key]) { payments[msg.payment.key] = msg.payment } else { // what to do here? } + + writeDbLocally(payments) + break case 'modifyMmtPaymentTest': @@ -142,31 +149,31 @@ function exampleDecryptMessage() { function readDbLocally() { // for now just use a file as db is not likely to get big - fs.readFile(localDbFile,function(err,content){ - if(err) { return {} - } else { - if (verbose) console.log('read locally: ',JSON.stringify(JSON.parse(content),null,4)) - return JSON.parse(content) } - - }) + if (fs.existsSync(localDbFile)) { + payments = JSON.parse(fs.readFileSync(localDbFile)) + } else { + payments = {} + } + return payments } -function writeDbLocally() { + + +function writeDbLocally(payments) { if (verbose) console.log('writing locally') - fs.writeFile(localDbFile,JSON.stringify(payments),function(err){ - if(err) throw err - }) + fs.writeFileSync(localDbFile,JSON.stringify(payments)) + } - $("#putStuffHere").html('

hello

') -payments = readDbLocally() +//payments = readDbLocally() // if the file didnt exist yet (sort this out) if (typeof(payments) === 'undefined') payments = {} ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') + //$("#putStuffHere").append("

hello

") // In order for messages to be encrypted we need to specify recipients // there can be a maximum of 7, which means if we wanted more we need multiple // messages @@ -215,6 +222,7 @@ ssbClient(function (err, sbot) { // }) // ) + $("#putStuffHere").append("") // drain lets us process stuff as it comes pull(sbot.messagesByType({ live: true, type: "addMmtPaymentTest" }), pull.drain(function (message){ try { @@ -235,10 +243,11 @@ ssbClient(function (err, sbot) { } } catch(e) { - displayPayments() - writeDbLocally() + //displayPayments() + //writeDbLocally() - sbot.close() + // $("#putStuffHere").append("

finished

") + //sbot.close() // why? return false } From d8d382c0d81f8b616f1adeb2405ea9d74cc49a14 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Sun, 29 Apr 2018 11:39:30 +0200 Subject: [PATCH 16/72] sorted readme, made a mess of everything else --- mmt-metadata.js | 242 ++++++++++++++++++++++++------------------------ readme.md | 75 ++++++++++++++- 2 files changed, 193 insertions(+), 124 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index bb9532b..d0c8f14 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -9,14 +9,12 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') -var fs = require('fs'); +var fs = require('fs') var localDbFile = './localdb.json' -// will hold current payments - -// yes i know global variables bad im gonna tidy it up -//var payments = {} +// will also include 'initiateMmtMultisigTest','shareMmtPublicKeyTest' +const messageTypes = ['initiateMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true @@ -29,103 +27,98 @@ var cosigners = [ // you wont be able to decrypt messages made using this script without your // own public key ssbPubKey: '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519', - // this will be an array of bitcoin addresses, which we will pop off and not reuse. - addresses: ['bc1sdfljsdl','bc1ldskfjsdfl'] } // other cosigners will be added here ] +function processMsg(msg,messageType) { - - -function testPublish() { - //publish a test message - sbot.publish({ type: 'testtype', text: 'hello, scuttleverse' }, function (err, msg) { - if (verbose) { - console.log(msg.key) - console.log(msg.value.author) - console.log(msg.value.content) + // todo: we need the author to be passed to this function + if (verbose) console.log('Found an initiate payment') + + $("#putStuffHere").append("") + + + payments = readDbLocally() + + // if we've never seen this transaction before, add it + if (!payments[msg.payment.key]) { + payments[msg.payment.key] = msg.payment + } else { + // what to do here? this shouldnt happen } - }) -} - - - -function processMsg (msg) { - // process an unencrypted message - switch(msg.type) { - - case 'addMmtPaymentTest': - if (verbose) { - console.log('Found a payment:') - $("#putStuffHere").append("") - //console.log(msg) - } - - payments = readDbLocally() - - // if we've never seen this transaction before, add it - if (!payments[msg.payment.key]) { - payments[msg.payment.key] = msg.payment - } else { - // what to do here? - } - - writeDbLocally(payments) - - break - case 'modifyMmtPaymentTest': - if (verbose) { - console.log('Found a payment comment:') - } - payments[msg.paymentComment.key].comments.push( { - // todo get the order from higher up and pass it to this function - //author: msg.value.author, - comment: msg.paymentComment.comment - } ) - } + writeDbLocally(payments) } -function pullWithFeedStream() { - // not using this right now - pull( - sbot.createFeedStream(), - pull.collect(function (err, msgs) { - console.log(msgs[1].key) - console.log(msgs[1].value) - - }) - ) +function processInitiatePayment (msg) { + // todo: we need the author to be passed to this function + if (verbose) console.log('Found an initiate payment') + + $("#putStuffHere").append("") + + + payments = readDbLocally() + + // if we've never seen this transaction before, add it + if (!payments[msg.payment.key]) { + payments[msg.payment.key] = msg.payment + } else { + // what to do here? this shouldnt happen + } + + writeDbLocally(payments) } - - - -function addPayment(sbot, paymentToAdd, recipients) { - - sbot.private.publish({ type: 'addMmtPaymentTest', payment: paymentToAdd }, recipients, function (err, msg) { +function processAddPaymentComment { + + // todo get the order from higher up and pass it to this function if (verbose) { - console.log('Added payment:') - console.log(JSON.stringify(msg, null, 4)) + console.log('Found a payment comment') } - }) -} + payments = readDbLocally() + // todo: check the comment doesnt already exist + payments[msg.paymentComment.key].comments.push( { + //author: msg.value.author, + comment: msg.paymentComment.comment + } ) +} -function addPaymentComment(sbot, paymentComment, recipients) { - - sbot.private.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, recipients, function (err, msg) { +function publishMessage(sbot, messageType, content, recipients) { + sbot.private.publish({ type: messageType, content: content }, recipients, function (err, msg) { if (verbose) { - console.log('Added payment Comment:') + console.log('Added ', messageType) console.log(JSON.stringify(msg, null, 4)) } }) - } +// function initiatePayment(sbot, paymentToAdd, recipients) { +// // this message will be published when somebody initiates a payment for others to sign +// sbot.private.publish({ type: 'initiateMmtPaymentTest', payment: paymentToAdd }, recipients, function (err, msg) { +// if (verbose) { +// console.log('Added payment:') +// console.log(JSON.stringify(msg, null, 4)) +// } +// }) +// +// } +// +// +// function addPaymentComment(sbot, paymentComment, recipients) { +// +// sbot.private.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, recipients, function (err, msg) { +// if (verbose) { +// console.log('Added payment Comment:') +// console.log(JSON.stringify(msg, null, 4)) +// } +// }) +// +// } + function displayPayments() { // this would be the place to create a snazzy html table @@ -167,14 +160,51 @@ function writeDbLocally(payments) { } -//payments = readDbLocally() -// if the file didnt exist yet (sort this out) -if (typeof(payments) === 'undefined') payments = {} +function ProcessDecryptedMessage(payments, messageType) + return function (err, msg) { + if (msg) { + //console.log('decrypted a message') + //console.log(msg) + processMsg(msg,messageType) + } +} +decryptMessage(payments) { + return function (message){ + try { + if (message.value.content) { + // attempt to decrypt message + try { + // todo: how to pass the message author to this callback function? + sbot.private.unbox(message.value.content, ProcessDecryptedMessage(payments, messageType)) + } catch(e) { + console.error('error while decrypting') + } + + } + } catch(e) { + //displayPayments() + //writeDbLocally() + + // $("#putStuffHere").append("

finished

") + //sbot.close() + // why? + return false + } + + } +} + +function drainMessages(payments) { + return function (messageType) { + // drain lets us process stuff as it comes + pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(decryptMessage(payments))) + } +} + ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') - //$("#putStuffHere").append("

hello

") // In order for messages to be encrypted we need to specify recipients // there can be a maximum of 7, which means if we wanted more we need multiple // messages @@ -193,18 +223,18 @@ ssbClient(function (err, sbot) { // the 'key' would be a bitcoin transaction id key: 'd5f2a6a8cd1e8c35466cfec16551', - + rawTransaction: 'a294b83........', // the actual metadata // note - no date, amounts or recieve addresses - for this we have a better // source of truth + + // this will be calculated at the time of initiating the payment rate: 5000, - cosigners: ['ssbpublickey1', 'ssbpublickey2'], - description: 'this is just an example', - comments: [] + comment: 'bought a new pencil sharpener' } - // addPayment(sbot, payment, recipients) - + // publishMessage(sbot, 'initiateMmtPaymentTest', payment, recipients) + // an example payment comment to add to the db var paymentComment = { @@ -214,7 +244,7 @@ ssbClient(function (err, sbot) { } - // addPaymentComment(sbot, paymentComment, recipients) + // publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) @@ -228,37 +258,11 @@ ssbClient(function (err, sbot) { // }) // ) - $("#putStuffHere").append("
" + msg.payment.key + ""+msg.payment.description+"
" + msg.payment.key + ""+msg.payment.description+"
" + msg.payment.key + ""+msg.payment.description+"
") - // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: true, type: "addMmtPaymentTest" }), pull.drain(function (message){ - try { - if (message.value.content) { - // attempt to decrypt message - try { - sbot.private.unbox(message.value.content, function (err, msg) { - if (msg) { - //console.log('decrypted a message') - //console.log(msg) - processMsg(msg) - } - //console.log('eer: ', err) - }) - } catch(e) { - console.log('error while decrypting') - } - } - } catch(e) { - //displayPayments() - //writeDbLocally() - - // $("#putStuffHere").append("

finished

") - //sbot.close() - // why? - return false - } + payments = readDbLocally() + $("#putStuffHere").append("
") + messageTypes.foreach(drainMessages(payments)) - })) }) diff --git a/readme.md b/readme.md index 62429e1..a308cde 100644 --- a/readme.md +++ b/readme.md @@ -3,18 +3,83 @@ Using ssb to record metadata associated with multi-signature bitcoin transactions. -Multi-sig wallets such as Electrum do not allow us to see cosigners in payment history, or to share payment descriptions and other notes. +Currently its a work in progress and doesnt do very much. -What this project should do: (can be separated into smaller modules) +Multi-sig wallets such as Electrum do not allow us to see cosigners in payment history, or to share payment descriptions and other notes. This project will provide these features using secure-scuttlebutt. + +### What this project should do: (can be separated into smaller modules) - Use secure-scuttlebutt for sharing information between holders of the wallet - Provide shared access to payment meta-data - Provide a mechanism for sending and viewing partially signed transactions. - Provide a mechanism for sharing public keys when initiating the wallet. +- Potentially integrate with a seed sharding system.... +- Have a front end using electron, potentially with mythical language and pictures relating to keys, seeds and shards. + +### Proposed ssb message types: + +This is only a proposal! Its all subject to discussion and change... + +- All type names will be appended with 'test' to stop test types from later interfering. +- All messages will be encrypted. +- No main-net transaction data will be published until we have agreed it is secure. + +#### `initiateMmtMultisigTest` + +This will be published one time per wallet by the person who initiates the wallet and will contain a name for the wallet, the number of cosigners and one bitcoin public key. The list of recipients for this message will remain the same for all future messages related to this wallet. +Example: +``` +content: { + walletName: 'the groovy gang wallet', + requiredCosigners: 2, + numberofCosigners: 6, + xpub: 'xpubblahblah....' +} +``` + +#### `shareMmtPublicKeyTest` + +This will be published once per remaining group member to initiate the wallet. It will contain the ssb message key of the relevant `initiateMmtMultisigTest` message, as well as one bitcoin public key. +Example: +``` +content: { + keyOfInitMessageMmtTest: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', + xpub: 'xpubblahblah.....' +} +``` + +#### `unsignedMmtPaymentTest` + +This will be published each time an outgoing payment needs to be signed. In the case of only two signatures being required it will be published once per outgoing payment. It will contain a bitcoin transaction id, the raw unsigned transaction in hex, optionally the rate in another currency at the time of initiating, and optionally a description. + +Potentially an alias or unique indentifier could be associated with each receive address, but im not sure how to do this in a reliable way. + +It could possibly also contain an identifier of the wallet, but it should be possible to derive this from the transaction data. + +``` +content: { + // is the transaction id needed? it can also be derived from the transaction data + key: 'd5f2a6a8cd1e8c35466cfec16551', + rawTransaction: 'a294b83........', + rate: 5000, + comment: 'bought a new pencil sharpener' +} +``` + +#### `addMmtPaymentCommentTest` + +This will be published any number of times to add notes and comments to payments. This can also be extended to add extra functionality for specific use cases. For example a payroll system could add the pay period dates and days worked. It will contain a bitcoin transaction id, a comment, and optional extra information. + +Example: +``` +content: { + key: 'd5f2a6a8cd1e8c35466cfec16551', + comment: 'this payment was a mistake' +} +``` -Currently its a work in progress. -electron front end in a separate branch +### Relevant resources +* [scuttlebot api docs](https://github.com/ssbc/scuttlebot/blob/master/api.md) * [pull-stream docs](https://pull-stream.github.io/) -* [Scuttlebot API - Scuttlebot](https://scuttlebot.io/apis/scuttlebot/ssb.html) From a64dc6740fc3f8847e269225366ada6271b3dffc Mon Sep 17 00:00:00 2001 From: ameba23 Date: Sun, 29 Apr 2018 12:29:08 +0200 Subject: [PATCH 17/72] still lots to do --- mmt-metadata.js | 148 +++++++++++++++++------------------------------- 1 file changed, 53 insertions(+), 95 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index d0c8f14..bff5f38 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -14,7 +14,7 @@ var fs = require('fs') var localDbFile = './localdb.json' // will also include 'initiateMmtMultisigTest','shareMmtPublicKeyTest' -const messageTypes = ['initiateMmtPaymentTest','addMmtPaymentCommentTest'] +const messageTypes = ['unsignedMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true @@ -32,53 +32,42 @@ var cosigners = [ // other cosigners will be added here ] -function processMsg(msg,messageType) { - // todo: we need the author to be passed to this function - if (verbose) console.log('Found an initiate payment') - - $("#putStuffHere").append("") - - - payments = readDbLocally() - - // if we've never seen this transaction before, add it - if (!payments[msg.payment.key]) { - payments[msg.payment.key] = msg.payment - } else { - // what to do here? this shouldnt happen - } - - writeDbLocally(payments) -} +var payments = {} -function processInitiatePayment (msg) { +function processMsg(msg,messageType) { // todo: we need the author to be passed to this function - if (verbose) console.log('Found an initiate payment') - - $("#putStuffHere").append("") - - - payments = readDbLocally() + + if (verbose) console.log('Found a ', messageType) - // if we've never seen this transaction before, add it - if (!payments[msg.payment.key]) { - payments[msg.payment.key] = msg.payment - } else { - // what to do here? this shouldnt happen - } + //payments = readDbLocally() + switch (messageType) { + case 'unsignedMmtPaymentTest': + // todo: validate that we dont have too many cosigners + // check if its already been added + //payments[msg.payment.key].cosigners.push(message.author) - writeDbLocally(payments) + // todo: check if the transaction has already been signed and broadcast + // (can we see it already) if not prompt the user to review and sign. + // then if there are still more required cosigners, re-publish the + // transaction to ssb, if not broadcast transaction. + + if (msg.payment.comment) addPaymentComment(msg) + if (msg.payment.rate) payments[msg.payment.key].rate = msg.payment.rate + + break + case 'addMmtPaymentCommentTest': + addPaymentComment(msg) + + } + displayPayments() } -function processAddPaymentComment { + +function addPaymentComment(msg) { // todo get the order from higher up and pass it to this function - if (verbose) { - console.log('Found a payment comment') - } - payments = readDbLocally() // todo: check the comment doesnt already exist payments[msg.paymentComment.key].comments.push( { //author: msg.value.author, @@ -96,28 +85,6 @@ function publishMessage(sbot, messageType, content, recipients) { }) } -// function initiatePayment(sbot, paymentToAdd, recipients) { -// // this message will be published when somebody initiates a payment for others to sign -// sbot.private.publish({ type: 'initiateMmtPaymentTest', payment: paymentToAdd }, recipients, function (err, msg) { -// if (verbose) { -// console.log('Added payment:') -// console.log(JSON.stringify(msg, null, 4)) -// } -// }) -// -// } -// -// -// function addPaymentComment(sbot, paymentComment, recipients) { -// -// sbot.private.publish({ type: 'modifyMmtPaymentTest', paymentComment: paymentComment }, recipients, function (err, msg) { -// if (verbose) { -// console.log('Added payment Comment:') -// console.log(JSON.stringify(msg, null, 4)) -// } -// }) -// -// } function displayPayments() { // this would be the place to create a snazzy html table @@ -127,40 +94,34 @@ function displayPayments() { } -function exampleDecryptMessage() { - - // this is an example of decrypting a message that i know worked for me - // (it wont work for you as its for me but shows the idea) - sbot.get('%69q4XMVlrwG3GAeykTQLiU/oZlRvF7bRZFAR1CmECIA=.sha256', function(err,msg) { - if (err) console.error(err) - sbot.private.unbox(msg.content, function (err,msg) { - if (err) console.error(err) - console.log(msg) - }) - }) - -} - function readDbLocally() { + // for now just use a file as db is not likely to get big + + var paymentsFromFile = {} + + // actually this should be async if (fs.existsSync(localDbFile)) { - payments = JSON.parse(fs.readFileSync(localDbFile)) - } else { - payments = {} - } - return payments -} + paymentsFromFile = JSON.parse(fs.readFileSync(localDbFile)) + // todo: this wont work, it will clobber arrays of cosigners and comments. + // this information will need to be parsed the same as the stuff coming from ssb + Object.keys(paymentsFromFile).forEach(key => result[key] = paymentsFromFile[key]); + Object.keys(payments).forEach(key => result[key] = payments[key]); -function writeDbLocally(payments) { + } + return result +} + +function writeDbLocally() { if (verbose) console.log('writing locally') fs.writeFileSync(localDbFile,JSON.stringify(payments)) } - -function ProcessDecryptedMessage(payments, messageType) +// a wrapper to pass on messageType (add author) +function ProcessDecryptedMessage(messageType) return function (err, msg) { if (msg) { //console.log('decrypted a message') @@ -168,14 +129,15 @@ function ProcessDecryptedMessage(payments, messageType) processMsg(msg,messageType) } } -decryptMessage(payments) { + +function decryptMessage() { return function (message){ try { if (message.value.content) { // attempt to decrypt message try { // todo: how to pass the message author to this callback function? - sbot.private.unbox(message.value.content, ProcessDecryptedMessage(payments, messageType)) + sbot.private.unbox(message.value.content, ProcessDecryptedMessage(messageType)) } catch(e) { console.error('error while decrypting') } @@ -194,13 +156,6 @@ decryptMessage(payments) { } } -function drainMessages(payments) { - return function (messageType) { - // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(decryptMessage(payments))) - } -} - ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') @@ -259,10 +214,13 @@ ssbClient(function (err, sbot) { // ) - payments = readDbLocally() - $("#putStuffHere").append("
" + msg.payment.key + ""+msg.payment.description+"
" + msg.payment.key + ""+msg.payment.description+"
") - messageTypes.foreach(drainMessages(payments)) + //payments = readDbLocally() + //$("#putStuffHere").append("
") + messageTypes.foreach(function (messageType) { + // drain lets us process stuff as it comes + pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(decryptMessage)) + } ) }) From 55b99cebd3be07f874cf32332dec8e1733f08ad3 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 30 Apr 2018 09:50:50 +0200 Subject: [PATCH 18/72] slightly less worse --- mmt-metadata.js | 82 ++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index bff5f38..33f531d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -35,13 +35,13 @@ var cosigners = [ var payments = {} -function processMsg(msg,messageType) { +function processMsg(msg) { // todo: we need the author to be passed to this function - - if (verbose) console.log('Found a ', messageType) +//console.log(JSON.stringify(msg,null,4) + if (verbose) console.log('Found a ', msg.type) //payments = readDbLocally() - switch (messageType) { + switch (msg.type) { case 'unsignedMmtPaymentTest': // todo: validate that we dont have too many cosigners // check if its already been added @@ -121,40 +121,22 @@ function writeDbLocally() { } // a wrapper to pass on messageType (add author) -function ProcessDecryptedMessage(messageType) - return function (err, msg) { - if (msg) { - //console.log('decrypted a message') - //console.log(msg) - processMsg(msg,messageType) - } +function processDecryptedMessage(err, msg) { + + if (msg) { + console.log('decrypted a message') + console.log(msg) + processMsg(msg) + } } -function decryptMessage() { - return function (message){ - try { - if (message.value.content) { - // attempt to decrypt message - try { - // todo: how to pass the message author to this callback function? - sbot.private.unbox(message.value.content, ProcessDecryptedMessage(messageType)) - } catch(e) { - console.error('error while decrypting') - } - } - } catch(e) { - //displayPayments() - //writeDbLocally() +// function decryptMessage (message) { +// +// +// return +// } - // $("#putStuffHere").append("

finished

") - //sbot.close() - // why? - return false - } - - } -} ssbClient(function (err, sbot) { @@ -188,7 +170,7 @@ ssbClient(function (err, sbot) { comment: 'bought a new pencil sharpener' } - // publishMessage(sbot, 'initiateMmtPaymentTest', payment, recipients) + //publishMessage(sbot, 'initiateMmtPaymentTest', payment, recipients) // an example payment comment to add to the db var paymentComment = { @@ -199,7 +181,7 @@ ssbClient(function (err, sbot) { } - // publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) + //publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) @@ -217,9 +199,33 @@ ssbClient(function (err, sbot) { //payments = readDbLocally() //$("#putStuffHere").append("
") - messageTypes.foreach(function (messageType) { + messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(decryptMessage)) + console.log(messageType) + pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { + console.log(JSON.stringify(message,null,4)) + try { + if (message.value.content) { + // attempt to decrypt message + try { + console.log(message.value.content) + // todo: how to pass the message author to this callback function? + sbot.private.unbox(message.value.content, processDecryptedMessage) + } catch(e) { + console.error('error while decrypting',e) + } + + } + } catch(e) { + //displayPayments() + //writeDbLocally() + + // $("#putStuffHere").append("

finished

") + //sbot.close() + // why? + return false + } +})) } ) From 5372a7d96a5856c5070afd5f360536d6526d44e6 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 30 Apr 2018 10:23:29 +0200 Subject: [PATCH 19/72] type specification has changed --- mmt-metadata.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 33f531d..8cf9dbc 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -1,6 +1,8 @@ // todo: // make less ugly +// error handling +// validation // speed up somehow -scanning messages takes ages making debugging slow // electron front end // interact with wallet either electrum locally or bitcoin on a server @@ -37,9 +39,9 @@ var payments = {} function processMsg(msg) { // todo: we need the author to be passed to this function -//console.log(JSON.stringify(msg,null,4) if (verbose) console.log('Found a ', msg.type) +console.log(JSON.stringify(msg,null,4)) //payments = readDbLocally() switch (msg.type) { case 'unsignedMmtPaymentTest': @@ -52,8 +54,8 @@ function processMsg(msg) { // then if there are still more required cosigners, re-publish the // transaction to ssb, if not broadcast transaction. - if (msg.payment.comment) addPaymentComment(msg) - if (msg.payment.rate) payments[msg.payment.key].rate = msg.payment.rate + if (msg.content.comment) addPaymentComment(msg) + if (msg.content.rate) payments[msg.content.key].rate = msg.content.rate break case 'addMmtPaymentCommentTest': @@ -69,9 +71,9 @@ function addPaymentComment(msg) { // todo get the order from higher up and pass it to this function // todo: check the comment doesnt already exist - payments[msg.paymentComment.key].comments.push( { + payments[msg.content.key].comments.push( { //author: msg.value.author, - comment: msg.paymentComment.comment + comment: msg.content.comment } ) } From f844760ad23c4b916fa179565a7af60e8b90104f Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 30 Apr 2018 13:11:25 +0200 Subject: [PATCH 20/72] fix problem with undefined variable --- main.js | 2 +- mmt-metadata.js | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/main.js b/main.js index c66fcad..2c615f2 100644 --- a/main.js +++ b/main.js @@ -18,7 +18,7 @@ function createWindow () { mainWindow.loadURL(`file://${__dirname}/index.html`) // Open the DevTools. - //mainWindow.webContents.openDevTools() + mainWindow.webContents.openDevTools() // Emitted when the window is closed. mainWindow.on('closed', function () { diff --git a/mmt-metadata.js b/mmt-metadata.js index 8cf9dbc..1c247ee 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -19,7 +19,7 @@ var localDbFile = './localdb.json' const messageTypes = ['unsignedMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true - +var something = 'foundit' var cosigners = [ { name: 'alice', // i think theres away to grab this from ssb's 'about' @@ -67,8 +67,13 @@ console.log(JSON.stringify(msg,null,4)) function addPaymentComment(msg) { - // todo get the order from higher up and pass it to this function + + // if we dont yet have this entry, define it + if (typeof payments[msg.content.key] === 'undefined') { + payments[msg.content.key] = {} + payments[msg.content.key].comments = [] + } // todo: check the comment doesnt already exist payments[msg.content.key].comments.push( { @@ -77,7 +82,6 @@ function addPaymentComment(msg) { } ) } - function publishMessage(sbot, messageType, content, recipients) { sbot.private.publish({ type: messageType, content: content }, recipients, function (err, msg) { if (verbose) { @@ -205,7 +209,7 @@ ssbClient(function (err, sbot) { // drain lets us process stuff as it comes console.log(messageType) pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { - console.log(JSON.stringify(message,null,4)) + console.log(JSON.stringify(message,null,4)) try { if (message.value.content) { // attempt to decrypt message From a03018612616a882b3bbcd61ad7055205ffb33a1 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 30 Apr 2018 15:09:33 +0200 Subject: [PATCH 21/72] output html --- index.html | 8 +-- mmt-metadata.js | 130 ++++++++++++++++++++++-------------------------- 2 files changed, 64 insertions(+), 74 deletions(-) diff --git a/index.html b/index.html index 02b5194..1765f13 100644 --- a/index.html +++ b/index.html @@ -14,8 +14,10 @@ - -

mmt payment metadata app

-
+ +
+

mmt payment metadata app

+
+
diff --git a/mmt-metadata.js b/mmt-metadata.js index 1c247ee..770583e 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -19,7 +19,7 @@ var localDbFile = './localdb.json' const messageTypes = ['unsignedMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true -var something = 'foundit' + var cosigners = [ { name: 'alice', // i think theres away to grab this from ssb's 'about' @@ -37,47 +37,18 @@ var cosigners = [ var payments = {} -function processMsg(msg) { - // todo: we need the author to be passed to this function - if (verbose) console.log('Found a ', msg.type) - -console.log(JSON.stringify(msg,null,4)) - //payments = readDbLocally() - switch (msg.type) { - case 'unsignedMmtPaymentTest': - // todo: validate that we dont have too many cosigners - // check if its already been added - //payments[msg.payment.key].cosigners.push(message.author) - - // todo: check if the transaction has already been signed and broadcast - // (can we see it already) if not prompt the user to review and sign. - // then if there are still more required cosigners, re-publish the - // transaction to ssb, if not broadcast transaction. - - if (msg.content.comment) addPaymentComment(msg) - if (msg.content.rate) payments[msg.content.key].rate = msg.content.rate - - break - case 'addMmtPaymentCommentTest': - addPaymentComment(msg) - - } - displayPayments() -} -function addPaymentComment(msg) { - // todo get the order from higher up and pass it to this function +function addPaymentComment(msg, author) { // if we dont yet have this entry, define it - if (typeof payments[msg.content.key] === 'undefined') { - payments[msg.content.key] = {} - payments[msg.content.key].comments = [] - } + if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} + if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] + // todo: check the comment doesnt already exist payments[msg.content.key].comments.push( { - //author: msg.value.author, + author: author, comment: msg.content.comment } ) } @@ -95,9 +66,20 @@ function publishMessage(sbot, messageType, content, recipients) { function displayPayments() { // this would be the place to create a snazzy html table - console.log('payments now looks like this:') - console.log(JSON.stringify(payments, null, 4)) + // theres gotta be a better way to do this + $("#putStuffHere").html('
\n\n\n\n\n\n\n\n') + Object.keys(payments).forEach(function( index) { + + $("#putStuffHere").append("") + } ) + + $("#putStuffHere").append("
Date Description and comments Rate Amount Recipient(s)
" + payments[index].rate + "
") + + if (verbose) { + console.log('payments now looks like this:') + console.log(JSON.stringify(payments, null, 4)) + } } function readDbLocally() { @@ -113,8 +95,11 @@ function readDbLocally() { // todo: this wont work, it will clobber arrays of cosigners and comments. // this information will need to be parsed the same as the stuff coming from ssb - Object.keys(paymentsFromFile).forEach(key => result[key] = paymentsFromFile[key]); - Object.keys(payments).forEach(key => result[key] = payments[key]); + Object.keys(paymentsFromFile).forEach(function(key) { + payments[key] = paymentsFromFile[key] + } ) + + //Object.keys(payments).forEach(key => result[key] = payments[key]); } return result @@ -126,24 +111,41 @@ function writeDbLocally() { } -// a wrapper to pass on messageType (add author) -function processDecryptedMessage(err, msg) { +function processDecryptedMessage(err, msg,author) { if (msg) { console.log('decrypted a message') - console.log(msg) - processMsg(msg) + + if (verbose) console.log('Found a ', msg.type) + + console.log(JSON.stringify(msg,null,4)) + switch (msg.type) { + case 'unsignedMmtPaymentTest': + // todo: validate that we dont have too many cosigners + // check if its already been added + //payments[msg.payment.key].cosigners.push(message.author) + + // todo: check if the transaction has already been signed and broadcast + // (can we see it already) if not prompt the user to review and sign. + // then if there are still more required cosigners, re-publish the + // transaction to ssb, if not broadcast transaction. + + if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} + + if (msg.content.comment) addPaymentComment(msg,author) + if (msg.content.rate) payments[msg.content.key].rate = msg.content.rate + + break + + case 'addMmtPaymentCommentTest': + addPaymentComment(msg,author) + + } + displayPayments() } } -// function decryptMessage (message) { -// -// -// return -// } - - ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') @@ -155,7 +157,8 @@ ssbClient(function (err, sbot) { // in most cases we want all cosigners as recipients, but for partially signed // transactions we would want only those who are designated to sign var recipients = [cosigners[0].ssbPubKey] - + + // todo: sort out this callback function //sbot.whoami( function(err,msg) { //console.log('whoami',msg) // recipients = [ msg.id ] @@ -176,7 +179,7 @@ ssbClient(function (err, sbot) { comment: 'bought a new pencil sharpener' } - //publishMessage(sbot, 'initiateMmtPaymentTest', payment, recipients) + //publishMessage(sbot, 'unsignedMmtPaymentTest', payment, recipients) // an example payment comment to add to the db var paymentComment = { @@ -189,21 +192,7 @@ ssbClient(function (err, sbot) { //publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) - //pull(sbot.createLogStream({ live: true }), pull.drain(processMsg)) - - // collect waits till we have everything then give us an array - // pull( - // sbot.createLogStream(), - // pull.collect(function (err, msgs) { - // msgs.forEach( function (item,index) { - // decryptAndProcess(sbot,item) - // } ) - // }) - // ) - - //payments = readDbLocally() - //$("#putStuffHere").append("") messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes @@ -215,8 +204,9 @@ ssbClient(function (err, sbot) { // attempt to decrypt message try { console.log(message.value.content) - // todo: how to pass the message author to this callback function? - sbot.private.unbox(message.value.content, processDecryptedMessage) + sbot.private.unbox(message.value.content, function(err,msg) { + processDecryptedMessage(err,msg,message.value.author) + }) } catch(e) { console.error('error while decrypting',e) } @@ -231,8 +221,6 @@ ssbClient(function (err, sbot) { // why? return false } -})) + })) } ) - - }) From c7d5232d0c0747cd99ffe5d867ba2bbecd259c1e Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 30 Apr 2018 15:33:26 +0200 Subject: [PATCH 22/72] cosigner array --- mmt-metadata.js | 81 ++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 770583e..abaa925 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -3,7 +3,6 @@ // make less ugly // error handling // validation -// speed up somehow -scanning messages takes ages making debugging slow // electron front end // interact with wallet either electrum locally or bitcoin on a server // re-write rates tool into node @@ -20,19 +19,17 @@ const messageTypes = ['unsignedMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true -var cosigners = [ - { - name: 'alice', // i think theres away to grab this from ssb's 'about' - // message. probably avatar image as well +var cosigners = { + // this is my own public key (which one could get using sbot.whoami) // or create new ones with ssb-keys // you wont be able to decrypt messages made using this script without your // own public key - ssbPubKey: '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519', - } - // other cosigners will be added here -] + '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519': { + name: 'alice' + } +} var payments = {} @@ -67,11 +64,25 @@ function displayPayments() { // this would be the place to create a snazzy html table // theres gotta be a better way to do this + // this is really ugly and doesnt work properly $("#putStuffHere").html('
\n\n\n\n\n\n\n\n') Object.keys(payments).forEach(function( index) { - $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") } ) $("#putStuffHere").append("
Date Description and comments Rate Amount Recipient(s)
" + payments[index].rate + "
somedate") + payments[index].comments.forEach(function(comment){ + + $("#putStuffHere").append(comment.comment) + }) + + $("#putStuffHere").append("" + payments[index].rate + "someamountsomerecipients
") @@ -145,24 +156,7 @@ function processDecryptedMessage(err, msg,author) { } } - - -ssbClient(function (err, sbot) { - if (verbose) console.log('ssb ready.') - - // In order for messages to be encrypted we need to specify recipients - // there can be a maximum of 7, which means if we wanted more we need multiple - // messages - - // in most cases we want all cosigners as recipients, but for partially signed - // transactions we would want only those who are designated to sign - var recipients = [cosigners[0].ssbPubKey] - - // todo: sort out this callback function - //sbot.whoami( function(err,msg) { - //console.log('whoami',msg) - // recipients = [ msg.id ] - //}) +function addExampleData(sbot, recipients) { // an example payment to add to the db var payment = { @@ -179,7 +173,7 @@ ssbClient(function (err, sbot) { comment: 'bought a new pencil sharpener' } - //publishMessage(sbot, 'unsignedMmtPaymentTest', payment, recipients) + publishMessage(sbot, 'unsignedMmtPaymentTest', payment, recipients) // an example payment comment to add to the db var paymentComment = { @@ -190,20 +184,39 @@ ssbClient(function (err, sbot) { } - //publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) - + publishMessage(sbot, 'addMmtPaymentCommentTest', paymentComment, recipients) + +} + +ssbClient(function (err, sbot) { + if (verbose) console.log('ssb ready.') + + // In order for messages to be encrypted we need to specify recipients + // there can be a maximum of 7, which means if we wanted more we need multiple + // messages + + var recipients = Object.keys(cosigners) + + // todo: sort out this callback function + //sbot.whoami( function(err,msg) { + //console.log('whoami',msg) + // recipients = [ msg.id ] + //}) + + + // uncomment this line to add example data to scuttlebutt + // note that if this is run multiple times it will create multiply identical entries + //addExampleData(sbot, recipients) + //payments = readDbLocally() messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes - console.log(messageType) pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { - console.log(JSON.stringify(message,null,4)) try { if (message.value.content) { // attempt to decrypt message try { - console.log(message.value.content) sbot.private.unbox(message.value.content, function(err,msg) { processDecryptedMessage(err,msg,message.value.author) }) From 9bd86e8d0d36a072e555bcb0c491caad6232a631 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 1 May 2018 21:11:24 +0200 Subject: [PATCH 23/72] more example types --- mmt-metadata.js | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index abaa925..da1003e 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -36,19 +36,6 @@ var payments = {} -function addPaymentComment(msg, author) { - - // if we dont yet have this entry, define it - if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} - if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] - - - // todo: check the comment doesnt already exist - payments[msg.content.key].comments.push( { - author: author, - comment: msg.content.comment - } ) -} function publishMessage(sbot, messageType, content, recipients) { sbot.private.publish({ type: messageType, content: content }, recipients, function (err, msg) { @@ -125,7 +112,6 @@ function writeDbLocally() { function processDecryptedMessage(err, msg,author) { if (msg) { - console.log('decrypted a message') if (verbose) console.log('Found a ', msg.type) @@ -156,8 +142,42 @@ function processDecryptedMessage(err, msg,author) { } } +function addPaymentComment(msg, author) { + + // if we dont yet have this entry, define it + if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} + if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] + + // todo: check the comment doesnt already exist + payments[msg.content.key].comments.push( { + author: author, + comment: msg.content.comment + } ) +} + function addExampleData(sbot, recipients) { + // an example to initiate a wallet. Note that the recipients for this message + // should be the recipients for all future messages associated with this wallet + + var initWallet { + walletName: 'the groovy gang wallet', + requiredCosigners: 2, + numberofCosigners: 6, + xpub: 'xpubblahblah....' + } + + publishMessage(sbot, 'initiateMmtMultisigTest', initWallet, recipients) + + // an example of sharing a public key to initiate a wallet + + var pubKey { + keyOfInitMessageMmtTest: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', + xpub: 'xpubblahblah.....' + } + + publishMessage(sbot, 'shareMmtPublicKeyTest', pubKey, recipients) + // an example payment to add to the db var payment = { From 9f0dc0fc244cdd682191f55f4833228e7d97b281 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 1 May 2018 21:30:03 +0200 Subject: [PATCH 24/72] tidied message types --- mmt-metadata.js | 26 +++++++++++++++++++++----- readme.md | 7 ++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index da1003e..f37a1d0 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -136,7 +136,21 @@ function processDecryptedMessage(err, msg,author) { case 'addMmtPaymentCommentTest': addPaymentComment(msg,author) - + break + + case 'initiateMmtMultisigTest': + //todo: + // walletName, requiredCosigners, xpub + // - we also need the number of recipients here to as this determines number of + // cosigners + // - we also need to store the message key as this is the wallet id. + + break + + case 'shareMmtPublicKeyTest': + // todo + // keyOfInitMessageMmtTest, xpub + } displayPayments() } @@ -163,7 +177,6 @@ function addExampleData(sbot, recipients) { var initWallet { walletName: 'the groovy gang wallet', requiredCosigners: 2, - numberofCosigners: 6, xpub: 'xpubblahblah....' } @@ -172,7 +185,8 @@ function addExampleData(sbot, recipients) { // an example of sharing a public key to initiate a wallet var pubKey { - keyOfInitMessageMmtTest: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', + // walletId is the key of the initiateMmtMultisig message as above + walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', xpub: 'xpubblahblah.....' } @@ -180,7 +194,7 @@ function addExampleData(sbot, recipients) { // an example payment to add to the db var payment = { - + walletId: '', // the 'key' would be a bitcoin transaction id key: 'd5f2a6a8cd1e8c35466cfec16551', rawTransaction: 'a294b83........', @@ -197,7 +211,8 @@ function addExampleData(sbot, recipients) { // an example payment comment to add to the db var paymentComment = { - + // not sure if wallet is needed here but will keep it for now + walletId = '', key: 'd5f2a6a8cd1e8c35466cfec16551', comment: 'this payment was a mistake' @@ -237,6 +252,7 @@ ssbClient(function (err, sbot) { if (message.value.content) { // attempt to decrypt message try { + // todo: we also need to pass the recipients and validate them sbot.private.unbox(message.value.content, function(err,msg) { processDecryptedMessage(err,msg,message.value.author) }) diff --git a/readme.md b/readme.md index a308cde..1b2450c 100644 --- a/readme.md +++ b/readme.md @@ -26,13 +26,12 @@ This is only a proposal! Its all subject to discussion and change... #### `initiateMmtMultisigTest` -This will be published one time per wallet by the person who initiates the wallet and will contain a name for the wallet, the number of cosigners and one bitcoin public key. The list of recipients for this message will remain the same for all future messages related to this wallet. +This will be published one time per wallet by the person who initiates the wallet and will contain a name for the wallet, the number of required cosigners and one bitcoin public key. The list of recipients for this message will remain the same for all future messages related to this wallet, and also defines the number of cosigners. Example: ``` content: { walletName: 'the groovy gang wallet', requiredCosigners: 2, - numberofCosigners: 6, xpub: 'xpubblahblah....' } ``` @@ -43,7 +42,7 @@ This will be published once per remaining group member to initiate the wallet. Example: ``` content: { - keyOfInitMessageMmtTest: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', + walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', xpub: 'xpubblahblah.....' } ``` @@ -58,6 +57,7 @@ It could possibly also contain an identifier of the wallet, but it should be pos ``` content: { + walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', // is the transaction id needed? it can also be derived from the transaction data key: 'd5f2a6a8cd1e8c35466cfec16551', rawTransaction: 'a294b83........', @@ -73,6 +73,7 @@ This will be published any number of times to add notes and comments to payments Example: ``` content: { + walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', key: 'd5f2a6a8cd1e8c35466cfec16551', comment: 'this payment was a mistake' } From 874ebaa12c865db80c5f4b2163cdd9e211d67d12 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 1 May 2018 21:48:35 +0200 Subject: [PATCH 25/72] began other message types --- mmt-metadata.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index f37a1d0..15530a4 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -31,10 +31,11 @@ var cosigners = { } } - +// this is tempory var payments = {} - +// will be something like wallets[walletId].payments = {} +var wallets = {} function publishMessage(sbot, messageType, content, recipients) { @@ -140,22 +141,36 @@ function processDecryptedMessage(err, msg,author) { case 'initiateMmtMultisigTest': //todo: - // walletName, requiredCosigners, xpub // - we also need the number of recipients here to as this determines number of // cosigners - // - we also need to store the message key as this is the wallet id. + //if (typeof wallets[msg.key] === 'undefined') wallets[msg.key] = {} + // wallets[msg.key].name = msg.content.walletName + // wallets[msg.key].requiredCosigners = msg.content.requiredCosigners + //addXpub(msg,author,msg.key) break case 'shareMmtPublicKeyTest': // todo - // keyOfInitMessageMmtTest, xpub - + // addXpub(msg,author,msg.content.keyOfInitMessageMmtTest) + } displayPayments() } } + +function addXpub(msg,author,walletId) { + + // todo validate duplicate entries, etc + + // if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] + // wallets[walletId].publicKeys.push( { + // owner: author + // xpub: msg.content.xpub + // } ) +} + function addPaymentComment(msg, author) { // if we dont yet have this entry, define it From 8294ffba2457914899690482482de3a266ac6e23 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 1 May 2018 21:57:39 +0200 Subject: [PATCH 26/72] dont add duplicates to arrays --- mmt-metadata.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 15530a4..6b65b18 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -161,27 +161,30 @@ function processDecryptedMessage(err, msg,author) { function addXpub(msg,author,walletId) { - - // todo validate duplicate entries, etc - - // if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] - // wallets[walletId].publicKeys.push( { - // owner: author - // xpub: msg.content.xpub - // } ) + + var xpubToAdd = { + owner: author + xpub: msg.content.xpub + } + + if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] + + if (wallets[walletId].publicKeys.indexOf(xpubToAdd) === -1) wallets[walletId].publicKeys.push(xpubToAdd) } function addPaymentComment(msg, author) { // if we dont yet have this entry, define it if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} - if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] + if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] - // todo: check the comment doesnt already exist - payments[msg.content.key].comments.push( { + var commentToAdd = { author: author, comment: msg.content.comment - } ) + } + + if (payments[msg.content.key].comments.indexOf(commentToAdd) === -1) + payments[msg.content.key].comments.push(commentToAdd) } function addExampleData(sbot, recipients) { From 742ea253c87383839017eb8644fa8575e9df19fc Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 13:52:19 +0200 Subject: [PATCH 27/72] small bugs fixed --- mmt-metadata.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 6b65b18..d38008d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -163,7 +163,7 @@ function processDecryptedMessage(err, msg,author) { function addXpub(msg,author,walletId) { var xpubToAdd = { - owner: author + owner: author, xpub: msg.content.xpub } @@ -192,7 +192,7 @@ function addExampleData(sbot, recipients) { // an example to initiate a wallet. Note that the recipients for this message // should be the recipients for all future messages associated with this wallet - var initWallet { + var initWallet = { walletName: 'the groovy gang wallet', requiredCosigners: 2, xpub: 'xpubblahblah....' @@ -202,7 +202,7 @@ function addExampleData(sbot, recipients) { // an example of sharing a public key to initiate a wallet - var pubKey { + var pubKey = { // walletId is the key of the initiateMmtMultisig message as above walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', xpub: 'xpubblahblah.....' @@ -230,7 +230,7 @@ function addExampleData(sbot, recipients) { // an example payment comment to add to the db var paymentComment = { // not sure if wallet is needed here but will keep it for now - walletId = '', + walletId: '', key: 'd5f2a6a8cd1e8c35466cfec16551', comment: 'this payment was a mistake' From 20510b0aa8cc132f7f330467d96db08e11043566 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 15:07:59 +0200 Subject: [PATCH 28/72] support multiple wallets --- mmt-metadata.js | 125 ++++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 46 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index d38008d..21b396e 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -14,8 +14,8 @@ var fs = require('fs') var localDbFile = './localdb.json' -// will also include 'initiateMmtMultisigTest','shareMmtPublicKeyTest' -const messageTypes = ['unsignedMmtPaymentTest','addMmtPaymentCommentTest'] +const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', + 'unsignedMmtPaymentTest','addMmtPaymentCommentTest'] var verbose = true @@ -32,25 +32,32 @@ var cosigners = { } // this is tempory -var payments = {} +//var payments = {} // will be something like wallets[walletId].payments = {} var wallets = {} function publishMessage(sbot, messageType, content, recipients) { - sbot.private.publish({ type: messageType, content: content }, recipients, function (err, msg) { + + // publish an encrypted message + + // should recipients be embedded in 'content'? + sbot.private.publish({ type: messageType, content: content, recipients: recipients }, recipients, function (err, msg) { if (verbose) { - console.log('Added ', messageType) + console.log('Published: ', messageType) console.log(JSON.stringify(msg, null, 4)) } }) + + // todo: should we also update db in memory and write to file when doing this? } -function displayPayments() { +function displayPayments(walletId) { // this would be the place to create a snazzy html table + var payments = wallets[walletId].payments // theres gotta be a better way to do this // this is really ugly and doesnt work properly $("#putStuffHere").html('\n\n\n\n\n\n\n\n') @@ -82,41 +89,53 @@ function displayPayments() { } function readDbLocally() { - + if (verbose) console.log('reading from local file.') // for now just use a file as db is not likely to get big - var paymentsFromFile = {} + var dataFromFile = {} - // actually this should be async if (fs.existsSync(localDbFile)) { - paymentsFromFile = JSON.parse(fs.readFileSync(localDbFile)) + dataFromFile = JSON.parse(fs.readFileSync(localDbFile)) // todo: this wont work, it will clobber arrays of cosigners and comments. // this information will need to be parsed the same as the stuff coming from ssb - Object.keys(paymentsFromFile).forEach(function(key) { - payments[key] = paymentsFromFile[key] - } ) + //Object.keys(paymentsFromFile).forEach(function(key) { + // payments[key] = paymentsFromFile[key] + //} ) //Object.keys(payments).forEach(key => result[key] = payments[key]); } - return result + return dataFromFile } function writeDbLocally() { - if (verbose) console.log('writing locally') - fs.writeFileSync(localDbFile,JSON.stringify(payments)) + if (verbose) console.log('writing to local file') + + // should use deepmerge + fs.writeFileSync(localDbFile,JSON.stringify(wallets)) } -function processDecryptedMessage(err, msg,author) { +function processDecryptedMessage(err, msg,author, ssbKey) { if (msg) { - if (verbose) console.log('Found a ', msg.type) + if (verbose) console.log('Found a ', msg.type, ' with key:', ssbKey) + //if (verbose) console.log(JSON.stringify(msg,null,4)) + + var walletId = '' + + if (msg.type === 'initiateMmtMultisigTest') { + walletId = ssbKey + } else { + walletId = msg.content.walletId + } + + // if we dont yet have this record, create it + if (typeof wallets[walletId] === 'undefined') wallets[walletId] = {} - console.log(JSON.stringify(msg,null,4)) switch (msg.type) { case 'unsignedMmtPaymentTest': // todo: validate that we dont have too many cosigners @@ -128,15 +147,15 @@ function processDecryptedMessage(err, msg,author) { // then if there are still more required cosigners, re-publish the // transaction to ssb, if not broadcast transaction. - if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} + if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') wallets[walletId].payments[msg.content.key] = {} - if (msg.content.comment) addPaymentComment(msg,author) - if (msg.content.rate) payments[msg.content.key].rate = msg.content.rate + if (msg.content.comment) addPaymentComment(msg, author, walletId) + if (msg.content.rate) wallets[walletId].payments[msg.content.key].rate = msg.content.rate break case 'addMmtPaymentCommentTest': - addPaymentComment(msg,author) + addPaymentComment(msg,author,walletId) break case 'initiateMmtMultisigTest': @@ -144,24 +163,26 @@ function processDecryptedMessage(err, msg,author) { // - we also need the number of recipients here to as this determines number of // cosigners - //if (typeof wallets[msg.key] === 'undefined') wallets[msg.key] = {} - // wallets[msg.key].name = msg.content.walletName - // wallets[msg.key].requiredCosigners = msg.content.requiredCosigners - //addXpub(msg,author,msg.key) + if (typeof wallets[ssbKey] === 'undefined') wallets[ssbKey] = {} + wallets[ssbKey].name = msg.content.walletName + wallets[ssbKey].requiredCosigners = msg.content.requiredCosigners + addXpub(msg,author,ssbKey,true) break case 'shareMmtPublicKeyTest': - // todo - // addXpub(msg,author,msg.content.keyOfInitMessageMmtTest) + if (typeof wallets[msg.content.walletId] === 'undefined') wallets[walletId] = {} + addXpub(msg, author, msg.content.walletId,false) } - displayPayments() + displayPayments(walletId) + // actually we should only do this once we've parse all entries + writeDbLocally() } } -function addXpub(msg,author,walletId) { - +function addXpub(msg,author,walletId,initiator) { + // todo: if this is the initiator, make it the first item in the array var xpubToAdd = { owner: author, xpub: msg.content.xpub @@ -169,22 +190,32 @@ function addXpub(msg,author,walletId) { if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] - if (wallets[walletId].publicKeys.indexOf(xpubToAdd) === -1) wallets[walletId].publicKeys.push(xpubToAdd) + // only add if unique + if (wallets[walletId].publicKeys.indexOf(xpubToAdd) === -1) { + + // if this is the initiators public key, make sure it is the first item in the array + if (initiator) { + wallets[walletId].publicKeys = [xpubToAdd].concat(wallets[walletId].publicKeys) + } else { + wallets[walletId].publicKeys.push(xpubToAdd) + } + } } -function addPaymentComment(msg, author) { +function addPaymentComment(msg, author,walletId) { // if we dont yet have this entry, define it - if (typeof payments[msg.content.key] === 'undefined') payments[msg.content.key] = {} - if (typeof payments[msg.content.key].comments === 'undefined') payments[msg.content.key].comments = [] + if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') wallets[walletId].payments[msg.content.key] = {} + if (typeof wallets[walletId].payments[msg.content.key].comments === 'undefined') wallets[walletId].payments[msg.content.key].comments = [] var commentToAdd = { author: author, comment: msg.content.comment } - if (payments[msg.content.key].comments.indexOf(commentToAdd) === -1) - payments[msg.content.key].comments.push(commentToAdd) + // only add if unique + if (wallets[walletId].payments[msg.content.key].comments.indexOf(commentToAdd) === -1) + wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } function addExampleData(sbot, recipients) { @@ -198,13 +229,14 @@ function addExampleData(sbot, recipients) { xpub: 'xpubblahblah....' } - publishMessage(sbot, 'initiateMmtMultisigTest', initWallet, recipients) + //publishMessage(sbot, 'initiateMmtMultisigTest', initWallet, recipients) // an example of sharing a public key to initiate a wallet var pubKey = { // walletId is the key of the initiateMmtMultisig message as above - walletId: '%9t2AsdffVfrt9+PygOipJP6COtTUy7igJt/SjNWkYnR8=.sha256', + + walletId: '%2idi0F1cCzjhHKSh8gymzvP+LDiXbB/dv2x7mt47n5Q=.sha256', xpub: 'xpubblahblah.....' } @@ -212,7 +244,7 @@ function addExampleData(sbot, recipients) { // an example payment to add to the db var payment = { - walletId: '', + walletId: '%2idi0F1cCzjhHKSh8gymzvP+LDiXbB/dv2x7mt47n5Q=.sha256', // the 'key' would be a bitcoin transaction id key: 'd5f2a6a8cd1e8c35466cfec16551', rawTransaction: 'a294b83........', @@ -229,8 +261,8 @@ function addExampleData(sbot, recipients) { // an example payment comment to add to the db var paymentComment = { - // not sure if wallet is needed here but will keep it for now - walletId: '', + // not sure if wallet id is needed here but will keep it for now + walletId: '%2idi0F1cCzjhHKSh8gymzvP+LDiXbB/dv2x7mt47n5Q=.sha256', key: 'd5f2a6a8cd1e8c35466cfec16551', comment: 'this payment was a mistake' @@ -261,7 +293,7 @@ ssbClient(function (err, sbot) { // note that if this is run multiple times it will create multiply identical entries //addExampleData(sbot, recipients) - //payments = readDbLocally() + wallets = readDbLocally() messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes @@ -270,9 +302,10 @@ ssbClient(function (err, sbot) { if (message.value.content) { // attempt to decrypt message try { + console.log(JSON.stringify(message,null,4)) // todo: we also need to pass the recipients and validate them - sbot.private.unbox(message.value.content, function(err,msg) { - processDecryptedMessage(err,msg,message.value.author) + sbot.private.unbox(message.value.content, function(err, msg) { + processDecryptedMessage(err, msg, message.value.author, message.key) }) } catch(e) { console.error('error while decrypting',e) From 3ed73f08ae042f682e00ac13c07e87bbc37a2e6c Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 15:13:48 +0200 Subject: [PATCH 29/72] readme --- readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readme.md b/readme.md index 1b2450c..77d7d9f 100644 --- a/readme.md +++ b/readme.md @@ -5,6 +5,8 @@ Using ssb to record metadata associated with multi-signature bitcoin transaction Currently its a work in progress and doesnt do very much. +### Motivation + Multi-sig wallets such as Electrum do not allow us to see cosigners in payment history, or to share payment descriptions and other notes. This project will provide these features using secure-scuttlebutt. ### What this project should do: (can be separated into smaller modules) @@ -80,6 +82,7 @@ content: { ``` + ### Relevant resources * [scuttlebot api docs](https://github.com/ssbc/scuttlebot/blob/master/api.md) From 9d2a1c9bbbd0739e82e4ed352ac5fe88e9701107 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 15:48:43 +0200 Subject: [PATCH 30/72] write files (need to write only unique items) --- mmt-metadata.js | 82 ++++---- package-lock.json | 520 +++++++++++++++++++++++----------------------- package.json | 4 + readme.md | 10 +- 4 files changed, 312 insertions(+), 304 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 21b396e..c6fb2d9 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -19,6 +19,8 @@ const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', var verbose = true + +// this is tempory, it will be associated with a particular wallet var cosigners = { // this is my own public key (which one could get using sbot.whoami) @@ -31,10 +33,6 @@ var cosigners = { } } -// this is tempory -//var payments = {} - -// will be something like wallets[walletId].payments = {} var wallets = {} @@ -54,39 +52,6 @@ function publishMessage(sbot, messageType, content, recipients) { } -function displayPayments(walletId) { - // this would be the place to create a snazzy html table - - var payments = wallets[walletId].payments - // theres gotta be a better way to do this - // this is really ugly and doesnt work properly - $("#putStuffHere").html('
Date Description and comments Rate Amount Recipient(s)
\n\n\n\n\n\n\n\n') - - Object.keys(payments).forEach(function( index) { - - $("#putStuffHere").append("") - $("#putStuffHere").append("") - - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") - } ) - - $("#putStuffHere").append("
Date Description and comments Rate Amount Recipient(s)
somedate") - payments[index].comments.forEach(function(comment){ - - $("#putStuffHere").append(comment.comment) - }) - - $("#putStuffHere").append("" + payments[index].rate + "someamountsomerecipients
") - - if (verbose) { - console.log('payments now looks like this:') - console.log(JSON.stringify(payments, null, 4)) - } -} function readDbLocally() { if (verbose) console.log('reading from local file.') @@ -114,7 +79,7 @@ function writeDbLocally() { if (verbose) console.log('writing to local file') // should use deepmerge - fs.writeFileSync(localDbFile,JSON.stringify(wallets)) + fs.writeFileSync(localDbFile,JSON.stringify(wallets,null,4)) } @@ -126,7 +91,6 @@ function processDecryptedMessage(err, msg,author, ssbKey) { //if (verbose) console.log(JSON.stringify(msg,null,4)) var walletId = '' - if (msg.type === 'initiateMmtMultisigTest') { walletId = ssbKey } else { @@ -147,6 +111,7 @@ function processDecryptedMessage(err, msg,author, ssbKey) { // then if there are still more required cosigners, re-publish the // transaction to ssb, if not broadcast transaction. + if (typeof wallets[walletId].payments === 'undefined') wallets[walletId].payments = {} if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') wallets[walletId].payments[msg.content.key] = {} if (msg.content.comment) addPaymentComment(msg, author, walletId) @@ -155,6 +120,7 @@ function processDecryptedMessage(err, msg,author, ssbKey) { break case 'addMmtPaymentCommentTest': + if (typeof wallets[walletId].payments === 'undefined') wallets[walletId].payments = {} addPaymentComment(msg,author,walletId) break @@ -273,6 +239,44 @@ function addExampleData(sbot, recipients) { } +function displayPayments(walletId) { + // this would be the place to create a snazzy html table + if (wallets[walletId].payments) { + var payments = wallets[walletId].payments + // theres gotta be a better way to do this + // this is really ugly and doesnt work properly + $("#putStuffHere").html('\n\n\n\n\n\n\n\n') + + Object.keys(payments).forEach(function( index) { + + $("#putStuffHere").append("") + $("#putStuffHere").append("") + + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + $("#putStuffHere").append("") + } ) + + $("#putStuffHere").append("
Date Description and comments Rate Amount Recipient(s)
somedate") + payments[index].comments.forEach(function(comment){ + + $("#putStuffHere").append(comment.comment) + }) + + $("#putStuffHere").append("" + payments[index].rate + "someamountsomerecipients
") + + if (verbose) { + console.log('payments now looks like this:') + console.log(JSON.stringify(payments, null, 4)) + } + } else { + console.error('cant display payments as no payments associated with wallet') + } +} + + ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') diff --git a/package-lock.json b/package-lock.json index 619d726..e4b810b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,10 +14,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ansi-regex": { @@ -66,7 +66,7 @@ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "boom": { @@ -74,7 +74,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } }, "brace-expansion": { @@ -82,7 +82,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -101,8 +101,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "2.1.1", + "map-obj": "1.0.1" } }, "caseless": { @@ -115,11 +115,11 @@ "resolved": "https://registry.npmjs.org/chloride/-/chloride-2.2.9.tgz", "integrity": "sha512-5nXmworu/Mwelj96V1ho+vKSnb68oyZieoMeit5iUPQquIBypThYH2mpXcXnztN9ahV3xvOXvLpn3gGpIxHjrg==", "requires": { - "is-electron": "^2.0.0", - "sodium-browserify": "^1.2.4", - "sodium-browserify-tweetnacl": "^0.2.2", - "sodium-chloride": "^1.1.0", - "sodium-native": "^2.0.0" + "is-electron": "2.1.0", + "sodium-browserify": "1.2.4", + "sodium-browserify-tweetnacl": "0.2.3", + "sodium-chloride": "1.1.0", + "sodium-native": "2.1.5" } }, "chloride-test": { @@ -127,7 +127,7 @@ "resolved": "https://registry.npmjs.org/chloride-test/-/chloride-test-1.2.2.tgz", "integrity": "sha1-F4aGqF6SeARREulujHkXk/mhCuo=", "requires": { - "json-buffer": "^2.0.11" + "json-buffer": "2.0.11" } }, "co": { @@ -145,7 +145,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "concat-map": { @@ -158,9 +158,9 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" }, "dependencies": { "isarray": { @@ -173,13 +173,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -187,7 +187,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } } } @@ -202,7 +202,7 @@ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "requires": { - "boom": "5.x.x" + "boom": "5.2.0" }, "dependencies": { "boom": { @@ -210,7 +210,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } } } @@ -220,7 +220,7 @@ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "requires": { - "array-find-index": "^1.0.1" + "array-find-index": "1.0.2" } }, "dashdash": { @@ -228,7 +228,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "debug": { @@ -265,7 +265,7 @@ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "ed2curve": { @@ -273,7 +273,7 @@ "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.1.4.tgz", "integrity": "sha1-lKRCSLuH2jXbDv968KpXYWgRf1k=", "requires": { - "tweetnacl": "0.x.x" + "tweetnacl": "0.14.5" } }, "electron": { @@ -281,9 +281,9 @@ "resolved": "https://registry.npmjs.org/electron/-/electron-1.8.6.tgz", "integrity": "sha512-rdbGinUDRh7rO0aJDXcaQ5UuJRg82wLkUU/V63wtaMFH04RVMkd5SUsyqgaP5IlVq3iYlJk/CPSVEsiBbPDMeg==", "requires": { - "@types/node": "^8.0.24", - "electron-download": "^3.0.1", - "extract-zip": "^1.0.3" + "@types/node": "8.10.10", + "electron-download": "3.3.0", + "extract-zip": "1.6.6" } }, "electron-download": { @@ -291,15 +291,15 @@ "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz", "integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=", "requires": { - "debug": "^2.2.0", - "fs-extra": "^0.30.0", - "home-path": "^1.0.1", - "minimist": "^1.2.0", - "nugget": "^2.0.0", - "path-exists": "^2.1.0", - "rc": "^1.1.2", - "semver": "^5.3.0", - "sumchecker": "^1.2.0" + "debug": "2.6.9", + "fs-extra": "0.30.0", + "home-path": "1.0.5", + "minimist": "1.2.0", + "nugget": "2.0.1", + "path-exists": "2.1.0", + "rc": "1.2.6", + "semver": "5.5.0", + "sumchecker": "1.3.1" } }, "error-ex": { @@ -307,7 +307,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es6-promise": { @@ -371,7 +371,7 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", "requires": { - "pend": "~1.2.0" + "pend": "1.2.0" } }, "find-up": { @@ -379,8 +379,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "forever-agent": { @@ -393,9 +393,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.18" } }, "fs": { @@ -408,11 +408,11 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" } }, "fs.realpath": { @@ -430,7 +430,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "glob": { @@ -438,12 +438,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "graceful-fs": { @@ -461,8 +461,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "hawk": { @@ -470,10 +470,10 @@ "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" } }, "hoek": { @@ -496,9 +496,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" } }, "increment-buffer": { @@ -511,7 +511,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "inflight": { @@ -519,8 +519,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -548,7 +548,7 @@ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-electron": { @@ -561,7 +561,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-fullwidth-code-point": { @@ -569,7 +569,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-typedarray": { @@ -623,7 +623,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.1.11" } }, "jsprim": { @@ -642,7 +642,7 @@ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "requires": { - "graceful-fs": "^4.1.9" + "graceful-fs": "4.1.11" } }, "libsodium": { @@ -663,11 +663,11 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, "looper": { @@ -680,8 +680,8 @@ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" } }, "map-obj": { @@ -694,16 +694,16 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" } }, "mime-db": { @@ -716,7 +716,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.33.0" } }, "minimatch": { @@ -724,7 +724,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -762,13 +762,13 @@ "resolved": "https://registry.npmjs.org/multiserver/-/multiserver-1.12.0.tgz", "integrity": "sha512-vyoVDqxiJabvepIKYN2+lYcPDcV5/de54kWXg1nYa1VK0NMJZ+gVIS6bLnQ9FmNzOxpCmVrVOkaQ0pMlMic5Ow==", "requires": { - "pull-cat": "~1.1.5", - "pull-stream": "^3.6.1", - "pull-ws": "^3.3.0", - "secret-handshake": "^1.1.12", + "pull-cat": "1.1.11", + "pull-stream": "3.6.7", + "pull-ws": "3.3.1", + "secret-handshake": "1.1.13", "separator-escape": "0.0.0", "socks": "1.1.9", - "stream-to-pull-stream": "^1.7.2" + "stream-to-pull-stream": "1.7.2" } }, "muxrpc": { @@ -776,11 +776,11 @@ "resolved": "https://registry.npmjs.org/muxrpc/-/muxrpc-6.4.0.tgz", "integrity": "sha1-JPfaBpvUYpsHfpk7BXeUKyaI6ug=", "requires": { - "explain-error": "^1.0.1", - "packet-stream": "~2.0.0", - "packet-stream-codec": "^1.1.1", - "pull-goodbye": "~0.0.1", - "pull-stream": "^3.2.3" + "explain-error": "1.0.4", + "packet-stream": "2.0.4", + "packet-stream-codec": "1.1.2", + "pull-goodbye": "0.0.2", + "pull-stream": "3.6.7" } }, "nan": { @@ -800,7 +800,7 @@ "resolved": "https://registry.npmjs.org/non-private-ip/-/non-private-ip-1.4.3.tgz", "integrity": "sha1-UsrysFOxU6vCKFbr3lOuAJPAYKU=", "requires": { - "ip": "~0.3.2" + "ip": "0.3.3" }, "dependencies": { "ip": { @@ -815,10 +815,10 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" } }, "nugget": { @@ -826,12 +826,12 @@ "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", "requires": { - "debug": "^2.1.3", - "minimist": "^1.1.0", - "pretty-bytes": "^1.0.2", - "progress-stream": "^1.1.0", - "request": "^2.45.0", - "single-line-log": "^1.1.2", + "debug": "2.6.9", + "minimist": "1.2.0", + "pretty-bytes": "1.0.4", + "progress-stream": "1.2.0", + "request": "2.85.0", + "single-line-log": "1.1.2", "throttleit": "0.0.2" } }, @@ -860,7 +860,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "options": { @@ -883,8 +883,8 @@ "resolved": "https://registry.npmjs.org/packet-stream-codec/-/packet-stream-codec-1.1.2.tgz", "integrity": "sha1-ebMC/BRM37tKtv66cEDmpdmcecc=", "requires": { - "pull-reader": "^1.2.4", - "pull-through": "^1.0.17" + "pull-reader": "1.2.9", + "pull-through": "1.0.18" } }, "parse-json": { @@ -892,7 +892,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.1" } }, "path-exists": { @@ -900,7 +900,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "path-is-absolute": { @@ -913,9 +913,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "pend": { @@ -943,7 +943,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pretty-bytes": { @@ -951,8 +951,8 @@ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.1.0" + "get-stdin": "4.0.1", + "meow": "3.7.0" } }, "private-box": { @@ -960,7 +960,7 @@ "resolved": "https://registry.npmjs.org/private-box/-/private-box-0.2.1.tgz", "integrity": "sha1-HfBhr8pbMDnH/qrdDa8PVvB+PsA=", "requires": { - "chloride": "^2.2.1" + "chloride": "2.2.9" } }, "process-nextick-args": { @@ -973,8 +973,8 @@ "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", "requires": { - "speedometer": "~0.1.2", - "through2": "~0.2.3" + "speedometer": "0.1.4", + "through2": "0.2.3" } }, "pull-box-stream": { @@ -982,12 +982,12 @@ "resolved": "https://registry.npmjs.org/pull-box-stream/-/pull-box-stream-1.0.13.tgz", "integrity": "sha1-w+JAOY6rP1lRsu0QeMWYi/egork=", "requires": { - "chloride": "^2.2.7", - "increment-buffer": "~1.0.0", - "pull-reader": "^1.2.5", - "pull-stream": "^3.2.3", - "pull-through": "^1.0.18", - "split-buffer": "~1.0.0" + "chloride": "2.2.9", + "increment-buffer": "1.0.1", + "pull-reader": "1.2.9", + "pull-stream": "3.6.7", + "pull-through": "1.0.18", + "split-buffer": "1.0.0" } }, "pull-cat": { @@ -1000,7 +1000,7 @@ "resolved": "https://registry.npmjs.org/pull-goodbye/-/pull-goodbye-0.0.2.tgz", "integrity": "sha1-jYNX21XiKnEN//DxaoyQtF7+QXE=", "requires": { - "pull-stream": "~3.5.0" + "pull-stream": "3.5.0" }, "dependencies": { "pull-stream": { @@ -1015,10 +1015,10 @@ "resolved": "https://registry.npmjs.org/pull-handshake/-/pull-handshake-1.1.4.tgz", "integrity": "sha1-YACg/QGIhM39c3JU+Mxgqypjd5E=", "requires": { - "pull-cat": "^1.1.9", - "pull-pair": "~1.1.0", - "pull-pushable": "^2.0.0", - "pull-reader": "^1.2.3" + "pull-cat": "1.1.11", + "pull-pair": "1.1.0", + "pull-pushable": "2.2.0", + "pull-reader": "1.2.9" } }, "pull-hash": { @@ -1051,7 +1051,7 @@ "resolved": "https://registry.npmjs.org/pull-through/-/pull-through-1.0.18.tgz", "integrity": "sha1-jdYjFCY+Wc9Qlur7sSeitu8xBzU=", "requires": { - "looper": "~3.0.0" + "looper": "3.0.0" } }, "pull-ws": { @@ -1059,9 +1059,9 @@ "resolved": "https://registry.npmjs.org/pull-ws/-/pull-ws-3.3.1.tgz", "integrity": "sha512-kJodbLQT+oKjcRIQO+vQNw6xWBuEo7Kxp51VMOvb6cvPvHYA+aNLzm+NmkB/5dZwbuTRYGMal9QPvH52tzM1ZA==", "requires": { - "relative-url": "^1.0.2", - "safe-buffer": "^5.1.1", - "ws": "^1.1.0" + "relative-url": "1.0.2", + "safe-buffer": "5.1.1", + "ws": "1.1.5" } }, "punycode": { @@ -1079,10 +1079,10 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=", "requires": { - "deep-extend": "~0.4.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "deep-extend": "0.4.2", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" } }, "read-pkg": { @@ -1090,9 +1090,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" } }, "read-pkg-up": { @@ -1100,8 +1100,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "1.1.2", + "read-pkg": "1.1.0" } }, "readable-stream": { @@ -1109,10 +1109,10 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "redent": { @@ -1120,8 +1120,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "indent-string": "2.1.0", + "strip-indent": "1.0.1" } }, "relative-url": { @@ -1134,7 +1134,7 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "^1.0.0" + "is-finite": "1.0.2" } }, "request": { @@ -1142,28 +1142,28 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" } }, "rimraf": { @@ -1171,7 +1171,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "safe-buffer": { @@ -1189,11 +1189,11 @@ "resolved": "https://registry.npmjs.org/secret-handshake/-/secret-handshake-1.1.13.tgz", "integrity": "sha512-jDpA1kPJGg+jEUOZGvqksQFGPWIx0aA96HpjU+AqIBKIKzmvZeOq0Lfl/XqVC5jviWTVZZM2B8+NqYR38Blz8A==", "requires": { - "chloride": "^2.2.7", - "deep-equal": "~1.0.0", - "pull-box-stream": "^1.0.13", - "pull-handshake": "^1.1.1", - "pull-stream": "^3.4.5" + "chloride": "2.2.9", + "deep-equal": "1.0.1", + "pull-box-stream": "1.0.13", + "pull-handshake": "1.1.4", + "pull-stream": "3.6.7" } }, "semver": { @@ -1211,7 +1211,7 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.5.tgz", "integrity": "sha1-J9Fx78yCoRi5ljn/WBZgJCtQbnw=", "requires": { - "inherits": "^2.0.1" + "inherits": "2.0.3" } }, "signal-exit": { @@ -1224,7 +1224,7 @@ "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", "requires": { - "string-width": "^1.0.1" + "string-width": "1.0.2" } }, "smart-buffer": { @@ -1237,7 +1237,7 @@ "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } }, "socks": { @@ -1245,8 +1245,8 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", "requires": { - "ip": "^1.1.2", - "smart-buffer": "^1.0.4" + "ip": "1.1.5", + "smart-buffer": "1.1.15" } }, "sodium-browserify": { @@ -1254,10 +1254,10 @@ "resolved": "https://registry.npmjs.org/sodium-browserify/-/sodium-browserify-1.2.4.tgz", "integrity": "sha512-IYcxKje/uf/c3a7VhZYJLlUxWMcktfbD4AjqHjUD1/VWKjj0Oq5wNbX8wjJOWVO9UhUMqJQiOn2xFbzKWBmy5w==", "requires": { - "libsodium-wrappers": "^0.7.3", + "libsodium-wrappers": "0.7.3", "sha.js": "2.4.5", - "sodium-browserify-tweetnacl": "^0.2.3", - "tweetnacl": "^0.14.1" + "sodium-browserify-tweetnacl": "0.2.3", + "tweetnacl": "0.14.5" } }, "sodium-browserify-tweetnacl": { @@ -1265,11 +1265,11 @@ "resolved": "https://registry.npmjs.org/sodium-browserify-tweetnacl/-/sodium-browserify-tweetnacl-0.2.3.tgz", "integrity": "sha1-tVN//LufdOvEQ7i2ohGykej8vI4=", "requires": { - "chloride-test": "^1.1.0", - "ed2curve": "^0.1.4", - "sha.js": "^2.4.8", - "tweetnacl": "^0.14.1", - "tweetnacl-auth": "^0.3.0" + "chloride-test": "1.2.2", + "ed2curve": "0.1.4", + "sha.js": "2.4.11", + "tweetnacl": "0.14.5", + "tweetnacl-auth": "0.3.1" }, "dependencies": { "sha.js": { @@ -1277,8 +1277,8 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.1" } } } @@ -1294,9 +1294,9 @@ "integrity": "sha512-We1ANTbM/iWeHbIpCFo5Nd95pwsLHRjH6h6hg2tlKjKDFUBFsVDk+ewlNjK2CRejpQtimD0GOexT0N/TO5PG2Q==", "optional": true, "requires": { - "ini": "^1.3.5", - "nan": "^2.4.0", - "node-gyp-build": "^3.0.0" + "ini": "1.3.5", + "nan": "2.10.0", + "node-gyp-build": "3.3.0" } }, "spdx-correct": { @@ -1304,8 +1304,8 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" } }, "spdx-exceptions": { @@ -1318,8 +1318,8 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" } }, "spdx-license-ids": { @@ -1342,14 +1342,14 @@ "resolved": "https://registry.npmjs.org/ssb-client/-/ssb-client-4.5.7.tgz", "integrity": "sha512-mEOyMlX6sGEUStU02vdSPD4j9ZRQQe3WCQwZCtgOkkrJpp7ARHxC0dx8ahumyq/vUIYWqQSAHHMD0+R63GmpGg==", "requires": { - "explain-error": "^1.0.1", - "multicb": "^1.2.1", - "multiserver": "^1.7.0", - "muxrpc": "^6.4.0", - "pull-hash": "^1.0.0", - "pull-stream": "^3.6.0", - "ssb-config": "^2.2.0", - "ssb-keys": "^7.0.13" + "explain-error": "1.0.4", + "multicb": "1.2.2", + "multiserver": "1.12.0", + "muxrpc": "6.4.0", + "pull-hash": "1.0.0", + "pull-stream": "3.6.7", + "ssb-config": "2.2.0", + "ssb-keys": "7.0.14" } }, "ssb-config": { @@ -1357,10 +1357,10 @@ "resolved": "https://registry.npmjs.org/ssb-config/-/ssb-config-2.2.0.tgz", "integrity": "sha1-QcrQOKhXWvQGLT/VfTsWe+hbA7w=", "requires": { - "deep-extend": "^0.4.0", - "non-private-ip": "^1.2.1", - "os-homedir": "^1.0.1", - "rc": "^1.1.6" + "deep-extend": "0.4.2", + "non-private-ip": "1.4.3", + "os-homedir": "1.0.2", + "rc": "1.2.6" } }, "ssb-keys": { @@ -1368,9 +1368,9 @@ "resolved": "https://registry.npmjs.org/ssb-keys/-/ssb-keys-7.0.14.tgz", "integrity": "sha512-iZJ1DlV+cO+tIst7uM6xJsE8p4813KEKwPyDN0ZGyu5QpHY9DyeTmrvpp1rVxQMSZ2rBu/UMaZwtpAbCspT9pQ==", "requires": { - "chloride": "^2.2.8", - "mkdirp": "~0.5.0", - "private-box": "^0.2.1" + "chloride": "2.2.9", + "mkdirp": "0.5.1", + "private-box": "0.2.1" } }, "sshpk": { @@ -1378,14 +1378,14 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" } }, "stream-to-pull-stream": { @@ -1393,8 +1393,8 @@ "resolved": "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.2.tgz", "integrity": "sha1-dXYJrhzr0zx0MtSvvjH/eGULnd4=", "requires": { - "looper": "^3.0.0", - "pull-stream": "^3.2.3" + "looper": "3.0.0", + "pull-stream": "3.6.7" } }, "string-width": { @@ -1402,9 +1402,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -1422,7 +1422,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -1430,7 +1430,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } }, "strip-indent": { @@ -1438,7 +1438,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "get-stdin": "^4.0.1" + "get-stdin": "4.0.1" } }, "strip-json-comments": { @@ -1451,8 +1451,8 @@ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz", "integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=", "requires": { - "debug": "^2.2.0", - "es6-promise": "^4.0.5" + "debug": "2.6.9", + "es6-promise": "4.2.4" } }, "throttleit": { @@ -1465,8 +1465,8 @@ "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", "requires": { - "readable-stream": "~1.1.9", - "xtend": "~2.1.1" + "readable-stream": "1.1.14", + "xtend": "2.1.2" } }, "tough-cookie": { @@ -1474,7 +1474,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } }, "trim-newlines": { @@ -1487,7 +1487,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.1" } }, "tweetnacl": { @@ -1500,7 +1500,7 @@ "resolved": "https://registry.npmjs.org/tweetnacl-auth/-/tweetnacl-auth-0.3.1.tgz", "integrity": "sha1-t1vC3xVkm7hOi5qjwGacbEvODSU=", "requires": { - "tweetnacl": "0.x.x" + "tweetnacl": "0.14.5" } }, "typedarray": { @@ -1528,8 +1528,8 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" } }, "verror": { @@ -1537,9 +1537,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "wrappy": { @@ -1552,8 +1552,8 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" + "options": "0.0.6", + "ultron": "1.0.2" } }, "xtend": { @@ -1561,7 +1561,7 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", "requires": { - "object-keys": "~0.4.0" + "object-keys": "0.4.0" } }, "yauzl": { @@ -1569,7 +1569,7 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", "requires": { - "fd-slicer": "~1.0.1" + "fd-slicer": "1.0.1" } } } diff --git a/package.json b/package.json index 033016e..4aeb57a 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,10 @@ "start": "electron main.js" }, "author": "", + "repository": { + "type": "git", + "url": "git://github.com/blockades/mmt-metadata.git" + }, "license": "ISC", "dependencies": { "electron": "^1.4.6", diff --git a/readme.md b/readme.md index 77d7d9f..27210e7 100644 --- a/readme.md +++ b/readme.md @@ -3,19 +3,19 @@ Using ssb to record metadata associated with multi-signature bitcoin transactions. -Currently its a work in progress and doesnt do very much. +Currently it is a work in progress. ### Motivation -Multi-sig wallets such as Electrum do not allow us to see cosigners in payment history, or to share payment descriptions and other notes. This project will provide these features using secure-scuttlebutt. +Wallet software with multi-signature functionality such as Electrum do not allow us to see cosigners in payment history, or to share payment descriptions and other notes. This project will provide these features using secure-scuttlebutt as a communication protocol. ### What this project should do: (can be separated into smaller modules) -- Use secure-scuttlebutt for sharing information between holders of the wallet -- Provide shared access to payment meta-data +- Use secure-scuttlebutt for sharing information between holders of the wallet. +- Provide shared access to payment meta-data. - Provide a mechanism for sending and viewing partially signed transactions. - Provide a mechanism for sharing public keys when initiating the wallet. -- Potentially integrate with a seed sharding system.... +- Potentially integrate with a seed sharding backup system.... - Have a front end using electron, potentially with mythical language and pictures relating to keys, seeds and shards. ### Proposed ssb message types: From 00102d0580bdc8551d009725c126834b100ff1b6 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 16:39:51 +0200 Subject: [PATCH 31/72] only add unique items almost works --- mmt-metadata.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index c6fb2d9..f357ae6 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -156,9 +156,14 @@ function addXpub(msg,author,walletId,initiator) { if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] + var alreadyExists = false // only add if unique - if (wallets[walletId].publicKeys.indexOf(xpubToAdd) === -1) { - + wallets[walletId].publicKeys.forEach(function (item) { + if (item.xpub === xpubToAdd.xpub) alreadyExists = true + } ) + + //if (wallets[walletId].publicKeys.indexOf(xpubToAdd) === -1) { + if (!alreadyExists) { // if this is the initiators public key, make sure it is the first item in the array if (initiator) { wallets[walletId].publicKeys = [xpubToAdd].concat(wallets[walletId].publicKeys) @@ -179,9 +184,18 @@ function addPaymentComment(msg, author,walletId) { comment: msg.content.comment } - // only add if unique - if (wallets[walletId].payments[msg.content.key].comments.indexOf(commentToAdd) === -1) - wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) + var alreadyExists = false + + // todo: improve this by having a general function using object.keys + // or using one from a library like deep compare + // ---only add if unique + wallets[walletId].payments[msg.content.key].comments.forEach(function (item) { + if ((item.author == commentToAdd.xpub) && (item.comment == commentToAdd.comment )) alreadyExists = true + if (alreadyExists) console.log('duplicate!') + } ) + //if (wallets[walletId].payments[msg.content.key].comments.indexOf(commentToAdd) === -1) + if (!alreadyExists) + wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } function addExampleData(sbot, recipients) { From 2c5fe5142bdf30d12bafd88f0fc6164ae587bb04 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 2 May 2018 21:23:41 +0200 Subject: [PATCH 32/72] lots of small tweaks --- mmt-metadata.js | 80 +++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index f357ae6..5ca9f62 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -20,18 +20,6 @@ const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', var verbose = true -// this is tempory, it will be associated with a particular wallet -var cosigners = { - - // this is my own public key (which one could get using sbot.whoami) - // or create new ones with ssb-keys - // you wont be able to decrypt messages made using this script without your - // own public key - - '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519': { - name: 'alice' - } -} var wallets = {} @@ -125,12 +113,13 @@ function processDecryptedMessage(err, msg,author, ssbKey) { break case 'initiateMmtMultisigTest': - //todo: - // - we also need the number of recipients here to as this determines number of - // cosigners if (typeof wallets[ssbKey] === 'undefined') wallets[ssbKey] = {} wallets[ssbKey].name = msg.content.walletName + + wallets[ssbKey].cosigners = msg.recipients + // note number of cosigners is wallet[ssbKey].cosigners.length + // todo: validate requiredCosigners < cosigners.length wallets[ssbKey].requiredCosigners = msg.content.requiredCosigners addXpub(msg,author,ssbKey,true) break @@ -190,16 +179,29 @@ function addPaymentComment(msg, author,walletId) { // or using one from a library like deep compare // ---only add if unique wallets[walletId].payments[msg.content.key].comments.forEach(function (item) { - if ((item.author == commentToAdd.xpub) && (item.comment == commentToAdd.comment )) alreadyExists = true - if (alreadyExists) console.log('duplicate!') + if ((item.author === commentToAdd.author) && (item.comment === commentToAdd.comment )) alreadyExists = true } ) //if (wallets[walletId].payments[msg.content.key].comments.indexOf(commentToAdd) === -1) if (!alreadyExists) wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } -function addExampleData(sbot, recipients) { +function addExampleData(sbot) { + + var cosigners = { + + // this is my own public key (which one could get using sbot.whoami) + // or create new a new one with ssb-keys + // you wont be able to decrypt messages made using this script without + // changing this to your own public key + '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519': { + name: 'alice' + } + } + + var recipients = Object.keys(cosigners) + // an example to initiate a wallet. Note that the recipients for this message // should be the recipients for all future messages associated with this wallet @@ -220,7 +222,7 @@ function addExampleData(sbot, recipients) { xpub: 'xpubblahblah.....' } - publishMessage(sbot, 'shareMmtPublicKeyTest', pubKey, recipients) + //publishMessage(sbot, 'shareMmtPublicKeyTest', pubKey, recipients) // an example payment to add to the db var payment = { @@ -298,7 +300,6 @@ ssbClient(function (err, sbot) { // there can be a maximum of 7, which means if we wanted more we need multiple // messages - var recipients = Object.keys(cosigners) // todo: sort out this callback function //sbot.whoami( function(err,msg) { @@ -309,7 +310,7 @@ ssbClient(function (err, sbot) { // uncomment this line to add example data to scuttlebutt // note that if this is run multiple times it will create multiply identical entries - //addExampleData(sbot, recipients) + //addExampleData(sbot) wallets = readDbLocally() @@ -317,28 +318,29 @@ ssbClient(function (err, sbot) { // drain lets us process stuff as it comes pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { try { - if (message.value.content) { - // attempt to decrypt message - try { - console.log(JSON.stringify(message,null,4)) - // todo: we also need to pass the recipients and validate them - sbot.private.unbox(message.value.content, function(err, msg) { - processDecryptedMessage(err, msg, message.value.author, message.key) - }) - } catch(e) { - console.error('error while decrypting',e) - } + if (message.value) + if (message.value.content) { + // attempt to decrypt message + try { + //console.log(JSON.stringify(message,null,4)) + // todo: we also need to pass the recipients and validate them + sbot.private.unbox(message.value.content, function(err, msg) { + processDecryptedMessage(err, msg, message.value.author, message.key) + }) + } catch(e) { + console.error('error while decrypting',e) + } - } + } } catch(e) { - //displayPayments() - //writeDbLocally() + console.error(e) - // $("#putStuffHere").append("

finished

") - //sbot.close() - // why? - return false } + }, function(err) { + if (err) console.error(err) + // this will only be reached if live = false. which gives us a chance to tidy + // things up but then we dont find new messages + //sbot.close() })) } ) }) From 79cc4eda83f3972e968e5a14188c350c6dd476ac Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 3 May 2018 13:53:06 +0200 Subject: [PATCH 33/72] fixed whoami --- mmt-metadata.js | 105 +++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 5ca9f62..04b6ef1 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -186,20 +186,17 @@ function addPaymentComment(msg, author,walletId) { wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } -function addExampleData(sbot) { +function addExampleData(sbot,me) { - var cosigners = { - - // this is my own public key (which one could get using sbot.whoami) - // or create new a new one with ssb-keys - // you wont be able to decrypt messages made using this script without - // changing this to your own public key - - '@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519': { - name: 'alice' - } + // todo: could we get the name from ssb about message? + var cosigners = {} + cosigners[me] = { + name: 'alice' } - + + // In order for messages to be encrypted we need to specify recipients + // there can be a maximum of 7, which means if we wanted more we need multiple + // messages (todo: implement this of verify recipients.length < 8) var recipients = Object.keys(cosigners) // an example to initiate a wallet. Note that the recipients for this message @@ -296,51 +293,51 @@ function displayPayments(walletId) { ssbClient(function (err, sbot) { if (verbose) console.log('ssb ready.') - // In order for messages to be encrypted we need to specify recipients - // there can be a maximum of 7, which means if we wanted more we need multiple - // messages - - // todo: sort out this callback function - //sbot.whoami( function(err,msg) { - //console.log('whoami',msg) - // recipients = [ msg.id ] - //}) + // this assumes we already have an ssb identity. + // if not we need to create one wiht ssb-keys (todo) + sbot.whoami( function(err,msg) { + if (err) console.error('Error running whoami.', err) - - // uncomment this line to add example data to scuttlebutt - // note that if this is run multiple times it will create multiply identical entries - //addExampleData(sbot) + var me = msg.id - wallets = readDbLocally() - - messageTypes.forEach(function (messageType) { - // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { - try { - if (message.value) - if (message.value.content) { - // attempt to decrypt message - try { - //console.log(JSON.stringify(message,null,4)) - // todo: we also need to pass the recipients and validate them - sbot.private.unbox(message.value.content, function(err, msg) { - processDecryptedMessage(err, msg, message.value.author, message.key) - }) - } catch(e) { - console.error('error while decrypting',e) - } - - } - } catch(e) { - console.error(e) + if (verbose) console.log('whoami: ',me) - } - }, function(err) { - if (err) console.error(err) - // this will only be reached if live = false. which gives us a chance to tidy - // things up but then we dont find new messages - //sbot.close() - })) + + // uncomment this line to add example data to scuttlebutt + // note that if this is run multiple times it will create multiply identical entries + //addExampleData(sbot, me) + + wallets = readDbLocally() + + messageTypes.forEach(function (messageType) { + // drain lets us process stuff as it comes + pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { + try { + if (message.value) + if (message.value.content) { + // attempt to decrypt message + try { + //console.log(JSON.stringify(message,null,4)) + // todo: we also need to pass the recipients and validate them + sbot.private.unbox(message.value.content, function(err, msg) { + processDecryptedMessage(err, msg, message.value.author, message.key) + }) + } catch(e) { + console.error('error while decrypting',e) + } + + } + } catch(e) { + console.error(e) + + } + }, function(err) { + if (err) console.error(err) + // this will only be reached if live = false. which gives us a chance to tidy + // things up but then we dont find new messages + //sbot.close() + })) + } ) } ) }) From 19af3ab486b8a378137a05365cdd486bf4537522 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 4 May 2018 12:20:06 +0200 Subject: [PATCH 34/72] readme --- mmt-metadata.js | 19 ++++++++++++++++--- readme.md | 11 +++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 04b6ef1..30126ff 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -114,7 +114,13 @@ function processDecryptedMessage(err, msg,author, ssbKey) { case 'initiateMmtMultisigTest': - if (typeof wallets[ssbKey] === 'undefined') wallets[ssbKey] = {} + if (typeof wallets[ssbKey] === 'undefined') { + // TODO: + // this wallet we dont yet know of, but we are invited to join + // since we are a recipient. so this is the place do choose to + // accept the inivitation, generate a public key and publish it + wallets[ssbKey] = {} + } wallets[ssbKey].name = msg.content.walletName wallets[ssbKey].cosigners = msg.recipients @@ -127,7 +133,11 @@ function processDecryptedMessage(err, msg,author, ssbKey) { case 'shareMmtPublicKeyTest': if (typeof wallets[msg.content.walletId] === 'undefined') wallets[walletId] = {} addXpub(msg, author, msg.content.walletId,false) - + // TODO: + // check if the wallet is now 'complete', that is + // if (wallets[walletId].publicKeys.length === msg.recipients.length) + // and if it is do something like wallets[walletId].isActive = true + // but why are these stored separetly? fix this } displayPayments(walletId) // actually we should only do this once we've parse all entries @@ -137,7 +147,7 @@ function processDecryptedMessage(err, msg,author, ssbKey) { function addXpub(msg,author,walletId,initiator) { - // todo: if this is the initiator, make it the first item in the array + var xpubToAdd = { owner: author, xpub: msg.content.xpub @@ -310,6 +320,9 @@ ssbClient(function (err, sbot) { wallets = readDbLocally() + // todo: run once with live:false, to find wallets. then present choice of found + // wallets or 'create new' + messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { diff --git a/readme.md b/readme.md index 27210e7..f27dddc 100644 --- a/readme.md +++ b/readme.md @@ -81,9 +81,20 @@ content: { } ``` +### Installation and dependencies +``` +npm install +``` +sbot must be running. Either you will need to be running an ssb client with sbot embedded such as Patchwork, or install sbot and run `sbot server` + +To run: +``` +npm start +``` ### Relevant resources * [scuttlebot api docs](https://github.com/ssbc/scuttlebot/blob/master/api.md) * [pull-stream docs](https://pull-stream.github.io/) +* [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) From 52964116c6a26af5cfab4d506cf82663fe7836f5 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 7 May 2018 12:00:53 +0200 Subject: [PATCH 35/72] display html table using clone --- index.html | 22 +++++++++++-- mmt-metadata.js | 82 ++++++++++++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/index.html b/index.html index 1765f13..007944b 100644 --- a/index.html +++ b/index.html @@ -12,12 +12,30 @@ -

mmt payment metadata app

-
+ + + + + + + + + + + + + + + + + + + +
Date Description and comments Rate Amount Recipient(s)
diff --git a/mmt-metadata.js b/mmt-metadata.js index 30126ff..ee67a6b 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -29,7 +29,8 @@ function publishMessage(sbot, messageType, content, recipients) { // publish an encrypted message // should recipients be embedded in 'content'? - sbot.private.publish({ type: messageType, content: content, recipients: recipients }, recipients, function (err, msg) { + sbot.private.publish({ type: messageType, content: content, recipients: recipients } + , recipients, function (err, msg) { if (verbose) { console.log('Published: ', messageType) console.log(JSON.stringify(msg, null, 4)) @@ -99,16 +100,20 @@ function processDecryptedMessage(err, msg,author, ssbKey) { // then if there are still more required cosigners, re-publish the // transaction to ssb, if not broadcast transaction. - if (typeof wallets[walletId].payments === 'undefined') wallets[walletId].payments = {} - if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') wallets[walletId].payments[msg.content.key] = {} + if (typeof wallets[walletId].payments === 'undefined') + wallets[walletId].payments = {} + if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') + wallets[walletId].payments[msg.content.key] = {} if (msg.content.comment) addPaymentComment(msg, author, walletId) - if (msg.content.rate) wallets[walletId].payments[msg.content.key].rate = msg.content.rate + if (msg.content.rate) + wallets[walletId].payments[msg.content.key].rate = msg.content.rate break case 'addMmtPaymentCommentTest': - if (typeof wallets[walletId].payments === 'undefined') wallets[walletId].payments = {} + if (typeof wallets[walletId].payments === 'undefined') + wallets[walletId].payments = {} addPaymentComment(msg,author,walletId) break @@ -131,7 +136,8 @@ function processDecryptedMessage(err, msg,author, ssbKey) { break case 'shareMmtPublicKeyTest': - if (typeof wallets[msg.content.walletId] === 'undefined') wallets[walletId] = {} + if (typeof wallets[msg.content.walletId] === 'undefined') + wallets[walletId] = {} addXpub(msg, author, msg.content.walletId,false) // TODO: // check if the wallet is now 'complete', that is @@ -139,9 +145,9 @@ function processDecryptedMessage(err, msg,author, ssbKey) { // and if it is do something like wallets[walletId].isActive = true // but why are these stored separetly? fix this } + displayPayments(walletId) - // actually we should only do this once we've parse all entries - writeDbLocally() + writeDbLocally() } } @@ -153,7 +159,8 @@ function addXpub(msg,author,walletId,initiator) { xpub: msg.content.xpub } - if (typeof wallets[walletId].publicKeys === 'undefined') wallets[walletId].publicKeys = [] + if (typeof wallets[walletId].publicKeys === 'undefined') + wallets[walletId].publicKeys = [] var alreadyExists = false // only add if unique @@ -175,8 +182,10 @@ function addXpub(msg,author,walletId,initiator) { function addPaymentComment(msg, author,walletId) { // if we dont yet have this entry, define it - if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') wallets[walletId].payments[msg.content.key] = {} - if (typeof wallets[walletId].payments[msg.content.key].comments === 'undefined') wallets[walletId].payments[msg.content.key].comments = [] + if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') + wallets[walletId].payments[msg.content.key] = {} + if (typeof wallets[walletId].payments[msg.content.key].comments === 'undefined') + wallets[walletId].payments[msg.content.key].comments = [] var commentToAdd = { author: author, @@ -189,7 +198,8 @@ function addPaymentComment(msg, author,walletId) { // or using one from a library like deep compare // ---only add if unique wallets[walletId].payments[msg.content.key].comments.forEach(function (item) { - if ((item.author === commentToAdd.author) && (item.comment === commentToAdd.comment )) alreadyExists = true + if ((item.author === commentToAdd.author) && (item.comment === commentToAdd.comment )) + alreadyExists = true } ) //if (wallets[walletId].payments[msg.content.key].comments.indexOf(commentToAdd) === -1) if (!alreadyExists) @@ -199,6 +209,7 @@ function addPaymentComment(msg, author,walletId) { function addExampleData(sbot,me) { // todo: could we get the name from ssb about message? + // using ssb-about? and maybe avatar,etc var cosigners = {} cosigners[me] = { name: 'alice' @@ -266,29 +277,29 @@ function displayPayments(walletId) { // this would be the place to create a snazzy html table if (wallets[walletId].payments) { var payments = wallets[walletId].payments - // theres gotta be a better way to do this - // this is really ugly and doesnt work properly - $("#putStuffHere").html('\n\n\n\n\n\n\n\n') - Object.keys(payments).forEach(function( index) { - - $("#putStuffHere").append("") - $("#putStuffHere").append("") - - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") - $("#putStuffHere").append("") + $(".unfilled").clone() + .find(".date").text("dateFromBlockchain").end() + .find(".comment").html(commentList).end() + .find(".rate").text(payments[index].rate).end() + .find(".amount").text("amountFromBlockchain").end() + .find(".recipients").text("recipeintsFromBlockchain").end() + .attr("class","index") + .insertAfter(".unfilled") } ) - $("#putStuffHere").append("
Date Description and comments Rate Amount Recipient(s)
somedate") - payments[index].comments.forEach(function(comment){ + $("#paymentsTbody").html($(".unfilled").clone()) - $("#putStuffHere").append(comment.comment) + Object.keys(payments).forEach(function( index) { + + var commentList = "" + payments[index].comments.forEach(function(comment){ + // todo: resolve alias for comment.author and add it here + commentList += "

" + commentList += comment.comment + commentList += "

" }) - $("#putStuffHere").append("
" + payments[index].rate + "someamountsomerecipients
") if (verbose) { console.log('payments now looks like this:') @@ -322,10 +333,12 @@ ssbClient(function (err, sbot) { // todo: run once with live:false, to find wallets. then present choice of found // wallets or 'create new' - + var count = 0 messageTypes.forEach(function (messageType) { // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: true, type: messageType }), pull.drain(function (message) { + pull(sbot.messagesByType({ live: false, type: messageType }) + , pull.drain(function (message) { + try { if (message.value) if (message.value.content) { @@ -349,6 +362,13 @@ ssbClient(function (err, sbot) { if (err) console.error(err) // this will only be reached if live = false. which gives us a chance to tidy // things up but then we dont find new messages + // count++ + // if (count === messageTypes.length) { + // writeDbLocally() + // // for now just use the first wallet + // var walletId = Object.keys(wallets)[0] + // if (walletId) displayPayments(walletId) + // } //sbot.close() })) } ) From 5734a4ef60665e50b3f8e3477435e434ee495dd0 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 7 May 2018 12:27:03 +0200 Subject: [PATCH 36/72] add example localdb.json --- localdb.json.example | 39 +++++++++++++++++++++++++++++++++++++++ mmt-metadata.js | 5 +++-- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 localdb.json.example diff --git a/localdb.json.example b/localdb.json.example new file mode 100644 index 0000000..c7434d8 --- /dev/null +++ b/localdb.json.example @@ -0,0 +1,39 @@ +{ + "%2idi0F1cCzjhHKSh8gymzvP+LDiXbB/dv2x7mt47n5Q=.sha256": { + "name": "the groovy gang wallet", + "requiredCosigners": 2, + "publicKeys": [ + { + "owner": "@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519", + "xpub": "xpubblahblah...." + } + ], + "payments": { + "d5f2a6a8cd1e8c35466cfec16551": { + "comments": [ + { + "author": "@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519", + "comment": "bought a new pencil sharpener" + }, + { + "author": "@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519", + "comment": "this payment was a mistake" + } + ], + "rate": 5000 + }, + "d5fsdffd1e8c35466cfe45dg": { + "comments": [ + { + "author": "@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519", + "comment": "bought a cheese grater" + } + ], + "rate": 5560 + } + }, + "cosigners": [ + "@vEJe4hdnbHJl549200IytOeA3THbnP0oM+JQtS1u+8o=.ed25519" + ] + } +} diff --git a/mmt-metadata.js b/mmt-metadata.js index ee67a6b..6ffe67d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -28,7 +28,7 @@ function publishMessage(sbot, messageType, content, recipients) { // publish an encrypted message - // should recipients be embedded in 'content'? + // recipients are embedded in 'content' sbot.private.publish({ type: messageType, content: content, recipients: recipients } , recipients, function (err, msg) { if (verbose) { @@ -78,7 +78,8 @@ function processDecryptedMessage(err, msg,author, ssbKey) { if (verbose) console.log('Found a ', msg.type, ' with key:', ssbKey) //if (verbose) console.log(JSON.stringify(msg,null,4)) - + + // determine id for wallet var walletId = '' if (msg.type === 'initiateMmtMultisigTest') { walletId = ssbKey From 9f2f12f17cc72dfc8add166cd6978f71a653b7dd Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 8 May 2018 09:48:10 +0200 Subject: [PATCH 37/72] begin making electrum-client --- electrum-client.js | 33 +++++++++++++++++++++++++++++++++ package-lock.json | 8 ++++---- package.json | 1 + 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 electrum-client.js diff --git a/electrum-client.js b/electrum-client.js new file mode 100644 index 0000000..07b935b --- /dev/null +++ b/electrum-client.js @@ -0,0 +1,33 @@ + +// functions for talking to electrum via http + +const request = require('request'); + + +function electrumRequest (method, params, callback) { + + // username and pw should be read from config file + // note: this is not the actual password which the wallet is encrypted + // with, its just for basic http authentication on a local machine + // TODO: 8888 is not the default port + var options = { + method: 'POST', + json: {"id":"curltext","method":method,"params": params}, + url: 'http://127.0.0.1:8888', + auth: { + username: 'spinach', + password: 'test' + } + } + + request(options, function(err,response,body) { + if (err) console.error(err) + callback(body) + }) + +} + +// an example request for history with no parameters +electrumRequest("history",[], function (output) { + console.log(JSON.stringify(output,null,4)) +}) diff --git a/package-lock.json b/package-lock.json index e4b810b..a62a81e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1070,9 +1070,9 @@ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "rc": { "version": "1.2.6", @@ -1158,7 +1158,7 @@ "mime-types": "2.1.18", "oauth-sign": "0.8.2", "performance-now": "2.1.0", - "qs": "6.5.1", + "qs": "6.5.2", "safe-buffer": "5.1.1", "stringstream": "0.0.5", "tough-cookie": "2.3.4", diff --git a/package.json b/package.json index 4aeb57a..adff158 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "electron": "^1.4.6", "fs": "0.0.1-security", "pull-stream": "^3.6.7", + "request": "^2.85.0", "sbot": "0.0.3", "ssb-client": "^4.5.7", "ssb-keys": "^7.0.14" From 0a030e0e0b528109fecb5b6c9ca5badd441ed1aa Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 8 May 2018 09:55:50 +0200 Subject: [PATCH 38/72] comments... --- electrum-client.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/electrum-client.js b/electrum-client.js index 07b935b..a371c19 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -3,6 +3,39 @@ const request = require('request'); +// things we probably need: (theres more but this is the basics) +// addrequest Create a payment request, using the first unused +// address of the wallet +// addtransaction Add a transaction to the wallet history +// broadcast Broadcast a transaction to the network +// createmultisig Create multisig address +// createnewaddress Create a new receiving address, beyond the gap limit +// of the wallet +// deserialize Deserialize a serialized transaction +// getbalance Return the balance of your wallet +// getconfig Return a configuration variable +// getfeerate Return current optimal fee rate per kilobyte, +// according to config settings (static/dynamic) +// getmpk Get master public key +// getrequest Return a payment request +// gettransaction Retrieve a transaction +// getunusedaddress Returns the first unused address of the wallet, or +// None if all addresses are used +// history Wallet history +// is_synchronized return wallet synchronization status +// ismine Check if address is in wallet +// listaddresses List wallet addresses +// listrequests List the payment requests you made +// notify Watch an address +// payto Create a transaction +// paytomany Create a multi-output transaction +// setconfig Set a configuration variable +// setlabel Assign a label to an item +// signtransaction Sign a transaction +// version Return the version of electrum + + + function electrumRequest (method, params, callback) { From 8d77ec49cde705a3b1d45af86df77b5ea86be8dd Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 8 May 2018 10:21:00 +0200 Subject: [PATCH 39/72] deserialize a tx --- electrum-client.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index a371c19..600822a 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -54,13 +54,31 @@ function electrumRequest (method, params, callback) { } request(options, function(err,response,body) { - if (err) console.error(err) - callback(body) + callback(err,body) }) } +function getTransaction (txid, callback) { + // get a tx and deserialize it + electrumRequest("gettransaction",{ "txid":txid }, function (err,output) { + electrumRequest("deserialize", { "tx":output.result.hex }, function (err,output) { + callback(err,output) + }) + }) +} + + + // an example request for history with no parameters -electrumRequest("history",[], function (output) { +electrumRequest("history",[], function (err,output) { + if (err) console.error(err) console.log(JSON.stringify(output,null,4)) }) + +// deserialize a tx +getTransaction('dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647',function (err,output) { + if (err) console.error(err) + console.log(JSON.stringify(output,null,4)) +} ) + From 5086fdf71c991648f661bc4b790e21264649fa77 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 8 May 2018 10:54:11 +0200 Subject: [PATCH 40/72] payto function --- electrum-client.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index 600822a..408ef2c 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -68,17 +68,35 @@ function getTransaction (txid, callback) { }) } +function getFeeRate (callback) { + electrumRequest("getfeerate", [], function (err,output) { + callback(err,output.result) + }) +} + + +function payTo (desination, amount, callback) { + electrumRequest("payto", { "destination":destination, "amount":amount }, function (err,output) { + callback(err,output) + }) +} +function payToMany (outputs, callback) { + // TODO: ouputs must be list of ["address", amount] --test this + electrumRequest("payto", { "outputs": outputs }, function (err,output) { + callback(err,output) + }) +} // an example request for history with no parameters -electrumRequest("history",[], function (err,output) { +electrumRequest("getfeerate",[], function (err,output) { if (err) console.error(err) console.log(JSON.stringify(output,null,4)) }) // deserialize a tx -getTransaction('dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647',function (err,output) { - if (err) console.error(err) - console.log(JSON.stringify(output,null,4)) -} ) +//getTransaction('dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647',function (err,output) { +// if (err) console.error(err) +// console.log(JSON.stringify(output,null,4)) +//} ) From 8811520b394b97463a3ce70cc42e1621986b5163 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 8 May 2018 14:24:22 +0200 Subject: [PATCH 41/72] readme, createmultisig --- electrum-client.js | 52 ++++++++++++++++++++++++++++++++++++++++++---- readme.md | 17 +++++++++++++++ testmeta | 43 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 testmeta diff --git a/electrum-client.js b/electrum-client.js index 408ef2c..979f7fd 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -36,13 +36,17 @@ const request = require('request'); - function electrumRequest (method, params, callback) { // username and pw should be read from config file // note: this is not the actual password which the wallet is encrypted // with, its just for basic http authentication on a local machine + // // TODO: 8888 is not the default port + // by default electrum uses a random port, so we must set it with + // electrum setconfig rpcport 8888 + // This needs to be automated. + var options = { method: 'POST', json: {"id":"curltext","method":method,"params": params}, @@ -59,6 +63,26 @@ function electrumRequest (method, params, callback) { } + +function checkVersion (requiredVersion, callback) { + electrumRequest("version", [], function (err,output) { + callback(err, (output.result === requiredVersion)) + }) +} + + +function getMpk (callback) { + electrumRequest("getmpk", [], function (err,output) { + callback(err, output.result) + }) +} + +function createMultisig (num,pubKeys,callback) { + electrumRequest("createmultisig", { "num": num, "pubkeys": pubKeys }, function (err,output) { + callback(err, output.result) + }) +} + function getTransaction (txid, callback) { // get a tx and deserialize it electrumRequest("gettransaction",{ "txid":txid }, function (err,output) { @@ -68,6 +92,8 @@ function getTransaction (txid, callback) { }) } + +// note this wont work with older electrum versions function getFeeRate (callback) { electrumRequest("getfeerate", [], function (err,output) { callback(err,output.result) @@ -88,12 +114,30 @@ function payToMany (outputs, callback) { }) } -// an example request for history with no parameters -electrumRequest("getfeerate",[], function (err,output) { - if (err) console.error(err) +function history (callback) { + electrumRequest("history", [], function (err,output) { + callback(err,output.result) + }) +} + +checkVersion("3.1.3", function(err, output) { + if (output) { + console.log("electrum version ok") + } else { + console.log("electrum version 3.1.3 required") + } +}) + + +// this doesnt work (yet) +var pubKeys = ["xpub661MyMwAqRbcFBNdNnwvkwHQqrnxN3BTEasFqixmS4qoNcxbjvqn4gN8tQNZd3sDTwht6Tuc6gPHnKBTxFxF6RDPF2kiY444nBoSaCYXURG", + "xpub661MyMwAqRbcF9Pn7tzxeXVFYgbe5ASGZUWD7HjwBvmQXtKzGPT58eiCdUKFo8oHpLe3mR3NoTs9EnB6B5UqjasnuPBeeFZGCyvAVFBMPMn"] +createMultisig(1, pubKeys, function(err,output) { + console.log(JSON.stringify(output,null,4)) }) + // deserialize a tx //getTransaction('dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647',function (err,output) { // if (err) console.error(err) diff --git a/readme.md b/readme.md index f27dddc..35884f7 100644 --- a/readme.md +++ b/readme.md @@ -93,8 +93,25 @@ To run: npm start ``` +### Integration with electrum + +Setting up electrum is not yet automated, we will need to do: + +``` +electrum --testnet setconfig rpcport 8888 +electrum --testnet setconfig rpcuser spinach +electrum --testnet setconfig rpcpassword test +electrum --testnet daemon start +electrum --testnet -w ~/.electrum/testnet/wallets/walletfile daemon load_wallet +``` +and not to forget afterwards +``` +electrum --testnet daemon stop +``` + ### Relevant resources * [scuttlebot api docs](https://github.com/ssbc/scuttlebot/blob/master/api.md) * [pull-stream docs](https://pull-stream.github.io/) * [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) +* [electrum json rpc interface](http://docs.electrum.org/en/latest/merchant.html#jsonrpc-interface) diff --git a/testmeta b/testmeta new file mode 100644 index 0000000..fa46df8 --- /dev/null +++ b/testmeta @@ -0,0 +1,43 @@ +{ + "addresses": { + "change": [ + "n2aRLeJJpdmCXa8Ew9fcRuEoDDAZhRs5Ch", + "mx8aMtE5peoy8D7Vw4C1EKRL9Lgt5g4nqw", + "mxAVGPQ3UxecEGadsARCFAsk1SMeigbk5K", + "mixyAwLvpVZUrzYxufHED6XXWDCHfnX5Sw", + "mkMxkkFarTEoayW3d1Ua3JrxcQAr5mqLSp", + "mrCZbxGhNqfRLeqWzrzN3WB9bojT8dyVYo" + ], + "receiving": [ + "mtw5EMHPVkawfSZsW8N1MFhan1i39f2TgK", + "moF44t7ydEJibCxNpnkYyPwKwWYZ88iMzU", + "n4j2bLsHnHosfKLt1j76kiefsPW52prHBx", + "mnLUeqadsLYExawpMmQj9fcxMCkZnQTfBw", + "mndi5N5xTcwumR2NJvxkPQu2CkrSxK9hZP", + "mtAWiRyimUU5e81XpfgdwiSZ6gHoGYKVpi", + "mizfyRFaKSoPEp3Kpv5iyUWemHHgcu8Jv5", + "mu1fsqfCzKARKi5a9hXpnz5kQDx23xVkjr", + "n3gsaGPphagnYHQMg7Waj5UqssuSZPXX1B", + "mztV1SxXTMhBnf5Yz7RELw77hn86To1qqL", + "mttAY8KLCB15bGmZSpQo9Vb37HGDre1Zzn", + "mxXdcmqYCbf41sJYtaMXJ69cjzVS6UjfZt", + "msnyEBkkyLTZuQZ5v6JmJTJF3ZFqbYSVJb", + "mxv93QCA1qbS4Apv73y8VCHGorjEGbQFUj", + "mw5UuhLDaHKwqY3sE5RshXVJJdC1GFd4UW", + "moN8i61zUChNWCFMRDdqqBDTLawr1Q9iR7", + "mwiUtzyofckPRExVsZikRQPUi4mCpy2998", + "n2kh94qoBwZTYY53w2QRN3DS4YzPk8xJoR", + "mxd58JMYUDF7wGaCJAV5dervbQKMRauf33", + "mzNYt4yZN5RXmCV1N9a52JTAxhisgwdpi9" + ] + }, + "keystore": { + "seed": "tornado useful festival arrange lemon crazy hope raw wealth skate slow ribbon", + "type": "bip32", + "xprv": "xprv9s21ZrQH143K3D36scAjt3QXctLrXRFfWErhhz46MNJhy72DYxybGmgX4FyVy4eW3ViK48vPRJG1hqDBhyGuZJvWftYovfEkzTVVJMdQaAf", + "xpub": "xpub661MyMwAqRbcFh7ZydhkFBMGAvBLvsyWsTnJWNThuhqgquMN6WHqpZzzuZSmKmfWxJAGajfhQEhnDQr36j9VUuNsjrgq5EKXYQC6dWurkRL" + }, + "seed_version": 16, + "use_encryption": false, + "wallet_type": "standard" +} \ No newline at end of file From 3a5a0f60e555f7e305fc77e2c5cbf965ebdfb91c Mon Sep 17 00:00:00 2001 From: ameba23 Date: Wed, 9 May 2018 18:00:21 +0200 Subject: [PATCH 42/72] more electrum functions --- electrum-client.js | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index 979f7fd..7facc19 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -66,10 +66,18 @@ function electrumRequest (method, params, callback) { function checkVersion (requiredVersion, callback) { electrumRequest("version", [], function (err,output) { - callback(err, (output.result === requiredVersion)) + var check = false + // are we actually connected to electrum? + if (output) if (output.result) check = (output.result === requiredVersion) + callback(err, check) }) } +function signTransaction(tx,password,callback { + electrumRequest("getmpk", {"tx": tx, "password": password }, function (err,output) { + callback(err, output.result) + }) +}) function getMpk (callback) { electrumRequest("getmpk", [], function (err,output) { @@ -77,6 +85,8 @@ function getMpk (callback) { }) } +// this can create a one-off multisig address, not a multisig wallet +// see https://gist.github.com/atweiden/7272732#file-2of3-md function createMultisig (num,pubKeys,callback) { electrumRequest("createmultisig", { "num": num, "pubkeys": pubKeys }, function (err,output) { callback(err, output.result) @@ -100,6 +110,14 @@ function getFeeRate (callback) { }) } +function addRequest (amount,memo,expiration, callback) { + var p = { "amount": amount } + if (memo) p["memo"] = memo + if (expiration) p["expiration"] = expiration + electrumRequest("addrequest", p, function (err,output) { + callback(err,output.result) + }) +} function payTo (desination, amount, callback) { electrumRequest("payto", { "destination":destination, "amount":amount }, function (err,output) { @@ -121,18 +139,18 @@ function history (callback) { } checkVersion("3.1.3", function(err, output) { - if (output) { - console.log("electrum version ok") + if (err) { + console.log("Error connecting to electrum") } else { - console.log("electrum version 3.1.3 required") + if (output) { + console.log("electrum version ok") + } else { + console.log("electrum version 3.1.3 required") + } } }) - -// this doesnt work (yet) -var pubKeys = ["xpub661MyMwAqRbcFBNdNnwvkwHQqrnxN3BTEasFqixmS4qoNcxbjvqn4gN8tQNZd3sDTwht6Tuc6gPHnKBTxFxF6RDPF2kiY444nBoSaCYXURG", - "xpub661MyMwAqRbcF9Pn7tzxeXVFYgbe5ASGZUWD7HjwBvmQXtKzGPT58eiCdUKFo8oHpLe3mR3NoTs9EnB6B5UqjasnuPBeeFZGCyvAVFBMPMn"] -createMultisig(1, pubKeys, function(err,output) { +addRequest(0, '', 0, function(err,output) { console.log(JSON.stringify(output,null,4)) }) From 3b9cef074cff2b4ddde6f374d6885ca62c839a8b Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 10:15:27 +0200 Subject: [PATCH 43/72] parse electrum history into our data structure --- electrum-client.js | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index 7facc19..da7d4aa 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -73,11 +73,11 @@ function checkVersion (requiredVersion, callback) { }) } -function signTransaction(tx,password,callback { +function signTransaction(tx,password,callback) { electrumRequest("getmpk", {"tx": tx, "password": password }, function (err,output) { callback(err, output.result) }) -}) +} function getMpk (callback) { electrumRequest("getmpk", [], function (err,output) { @@ -138,6 +138,30 @@ function history (callback) { }) } +function parseHistory (wallet, callback) { + history( function(err,output) { + if (output.transactions) + output.transactions.forEach(function(transaction) { + if (typeof wallet.payments === 'undefined') + wallet.payments = {} + if (typeof wallet.payments[transaction.txid] === 'undefined') + wallet.payments[transaction.txid] = {} + wallet.payments[transaction.txid].amount = transaction.value.value + wallet.payments[transaction.txid].confirmations = transaction.confirmations + + // convert timestamp to seconds to use as javascript date + wallet.payments[transaction.txid].timestamp = transaction.timestamp * 1000 + + // copy transaction.label as comment? + + }) + // could store balance as + //output.summary.end_balance.value + // or get it from getBalance + callback(err,wallet) + }) +} + checkVersion("3.1.3", function(err, output) { if (err) { console.log("Error connecting to electrum") @@ -150,12 +174,13 @@ checkVersion("3.1.3", function(err, output) { } }) -addRequest(0, '', 0, function(err,output) { +parseHistory({}, function(err,output) { console.log(JSON.stringify(output,null,4)) }) + // deserialize a tx //getTransaction('dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647',function (err,output) { // if (err) console.error(err) From c3e1b90af5bfc1a6dfc930cf24ae559eb3ce5616 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 10:34:34 +0200 Subject: [PATCH 44/72] module exports --- electrum-client.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index da7d4aa..d85ed60 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -34,9 +34,9 @@ const request = require('request'); // signtransaction Sign a transaction // version Return the version of electrum +var ec = module.exports = {} - -function electrumRequest (method, params, callback) { +electrumRequest = function (method, params, callback) { // username and pw should be read from config file // note: this is not the actual password which the wallet is encrypted @@ -64,7 +64,8 @@ function electrumRequest (method, params, callback) { } -function checkVersion (requiredVersion, callback) { +ec.checkVersion = function (requiredVersion, callback) { + // todo: remove dots from version number, convert to int and compare electrumRequest("version", [], function (err,output) { var check = false // are we actually connected to electrum? @@ -73,13 +74,13 @@ function checkVersion (requiredVersion, callback) { }) } -function signTransaction(tx,password,callback) { +ec.signTransaction = function (tx,password,callback) { electrumRequest("getmpk", {"tx": tx, "password": password }, function (err,output) { callback(err, output.result) }) } -function getMpk (callback) { +ec.getMpk = function (callback) { electrumRequest("getmpk", [], function (err,output) { callback(err, output.result) }) @@ -87,13 +88,13 @@ function getMpk (callback) { // this can create a one-off multisig address, not a multisig wallet // see https://gist.github.com/atweiden/7272732#file-2of3-md -function createMultisig (num,pubKeys,callback) { +ec.createMultisig = function (num,pubKeys,callback) { electrumRequest("createmultisig", { "num": num, "pubkeys": pubKeys }, function (err,output) { callback(err, output.result) }) } -function getTransaction (txid, callback) { +ec.getTransaction = function (txid, callback) { // get a tx and deserialize it electrumRequest("gettransaction",{ "txid":txid }, function (err,output) { electrumRequest("deserialize", { "tx":output.result.hex }, function (err,output) { @@ -103,14 +104,15 @@ function getTransaction (txid, callback) { } -// note this wont work with older electrum versions -function getFeeRate (callback) { +// note this wont work with older electrum versions, but we kind of need it for building +// transactions +ec.getFeeRate = function (callback) { electrumRequest("getfeerate", [], function (err,output) { callback(err,output.result) }) } -function addRequest (amount,memo,expiration, callback) { +ec.addRequest = function (amount,memo,expiration, callback) { var p = { "amount": amount } if (memo) p["memo"] = memo if (expiration) p["expiration"] = expiration @@ -119,27 +121,27 @@ function addRequest (amount,memo,expiration, callback) { }) } -function payTo (desination, amount, callback) { +ec.payTo = function (desination, amount, callback) { electrumRequest("payto", { "destination":destination, "amount":amount }, function (err,output) { callback(err,output) }) } -function payToMany (outputs, callback) { +ec.payToMany = function (outputs, callback) { // TODO: ouputs must be list of ["address", amount] --test this electrumRequest("payto", { "outputs": outputs }, function (err,output) { callback(err,output) }) } -function history (callback) { +ec.history = function (callback) { electrumRequest("history", [], function (err,output) { callback(err,output.result) }) } -function parseHistory (wallet, callback) { - history( function(err,output) { +ec.parseHistory = function (wallet, callback) { + ec.history( function(err,output) { if (output.transactions) output.transactions.forEach(function(transaction) { if (typeof wallet.payments === 'undefined') @@ -162,7 +164,9 @@ function parseHistory (wallet, callback) { }) } -checkVersion("3.1.3", function(err, output) { + +// test +ec.checkVersion("3.1.3", function(err, output) { if (err) { console.log("Error connecting to electrum") } else { @@ -174,7 +178,8 @@ checkVersion("3.1.3", function(err, output) { } }) -parseHistory({}, function(err,output) { + +ec.parseHistory({}, function(err,output) { console.log(JSON.stringify(output,null,4)) }) From 486cdb29335599c6e52901bb4dc091dd8c291d02 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 10:45:31 +0200 Subject: [PATCH 45/72] reformat function names --- electrum-client.js | 26 +++++++++++--------------- mmt-metadata.js | 22 ++++++++++++++-------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index d85ed60..78b7889 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -166,23 +166,19 @@ ec.parseHistory = function (wallet, callback) { // test -ec.checkVersion("3.1.3", function(err, output) { - if (err) { - console.log("Error connecting to electrum") - } else { - if (output) { - console.log("electrum version ok") - } else { - console.log("electrum version 3.1.3 required") - } - } -}) - +// ec.checkVersion("3.1.3", function(err, output) { +// if (err) { +// console.log("Error connecting to electrum") +// } else { +// if (output) { +// console.log("electrum version ok") +// } else { +// console.log("electrum version 3.1.3 required") +// } +// } +// }) -ec.parseHistory({}, function(err,output) { - console.log(JSON.stringify(output,null,4)) -}) diff --git a/mmt-metadata.js b/mmt-metadata.js index 6ffe67d..8fff8bf 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -12,6 +12,8 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') var fs = require('fs') +var ec = require("./electrum-client.js") + var localDbFile = './localdb.json' const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', @@ -24,7 +26,7 @@ var verbose = true var wallets = {} -function publishMessage(sbot, messageType, content, recipients) { +publishMessage = function (sbot, messageType, content, recipients) { // publish an encrypted message @@ -42,7 +44,7 @@ function publishMessage(sbot, messageType, content, recipients) { -function readDbLocally() { +readDbLocally = function() { if (verbose) console.log('reading from local file.') // for now just use a file as db is not likely to get big @@ -64,7 +66,7 @@ function readDbLocally() { return dataFromFile } -function writeDbLocally() { +writeDbLocally = function() { if (verbose) console.log('writing to local file') // should use deepmerge @@ -72,7 +74,7 @@ function writeDbLocally() { } -function processDecryptedMessage(err, msg,author, ssbKey) { +processDecryptedMessage = function(err, msg,author, ssbKey) { if (msg) { @@ -153,7 +155,7 @@ function processDecryptedMessage(err, msg,author, ssbKey) { } -function addXpub(msg,author,walletId,initiator) { +addXpub = function(msg,author,walletId,initiator) { var xpubToAdd = { owner: author, @@ -180,7 +182,7 @@ function addXpub(msg,author,walletId,initiator) { } } -function addPaymentComment(msg, author,walletId) { +addPaymentComment = function(msg, author,walletId) { // if we dont yet have this entry, define it if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') @@ -207,7 +209,7 @@ function addPaymentComment(msg, author,walletId) { wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } -function addExampleData(sbot,me) { +addExampleData = function(sbot,me) { // todo: could we get the name from ssb about message? // using ssb-about? and maybe avatar,etc @@ -274,7 +276,7 @@ function addExampleData(sbot,me) { } -function displayPayments(walletId) { +displayPayments = function(walletId) { // this would be the place to create a snazzy html table if (wallets[walletId].payments) { var payments = wallets[walletId].payments @@ -332,6 +334,10 @@ ssbClient(function (err, sbot) { wallets = readDbLocally() + //ec.parseHistory(wallets[walletId], function(err,output) { + // console.log(JSON.stringify(output,null,4)) + //}) + // todo: run once with live:false, to find wallets. then present choice of found // wallets or 'create new' var count = 0 From f3a06b7c4c8ad822c2c5a6c1202e86cf1d6aa614 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 10:56:50 +0200 Subject: [PATCH 46/72] separate file for front end --- electron-interface.js | 39 +++++++++++++++++++++++++++++++++++++++ mmt-metadata.js | 42 ++++-------------------------------------- testmeta | 43 ------------------------------------------- 3 files changed, 43 insertions(+), 81 deletions(-) create mode 100644 electron-interface.js delete mode 100644 testmeta diff --git a/electron-interface.js b/electron-interface.js new file mode 100644 index 0000000..c2d6179 --- /dev/null +++ b/electron-interface.js @@ -0,0 +1,39 @@ + +var electronInterface = module.exports = {} + +electronInterface.displayPayments = function(wallet) { + // this would be the place to create a snazzy html table + if (wallet.payments) { + var payments = wallet.payments + + $("#paymentsTbody").html($(".unfilled").clone()) + + Object.keys(payments).forEach(function( index) { + + var commentList = "" + payments[index].comments.forEach(function(comment){ + // todo: resolve alias for comment.author and add it here + commentList += "

" + commentList += comment.comment + commentList += "

" + }) + + $(".unfilled").clone() + .find(".date").text("dateFromBlockchain").end() + .find(".comment").html(commentList).end() + .find(".rate").text(payments[index].rate).end() + .find(".amount").text("amountFromBlockchain").end() + .find(".recipients").text("recipeintsFromBlockchain").end() + .attr("class","index") + .insertAfter(".unfilled") + } ) + + + if (verbose) { + console.log('payments now looks like this:') + console.log(JSON.stringify(payments, null, 4)) + } + } else { + console.error('cant display payments as no payments associated with wallet') + } +} diff --git a/mmt-metadata.js b/mmt-metadata.js index 8fff8bf..65f01e7 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -12,7 +12,9 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') var fs = require('fs') + var ec = require("./electrum-client.js") +var electronInterface = require("./electron-interface.js") var localDbFile = './localdb.json' @@ -149,7 +151,7 @@ processDecryptedMessage = function(err, msg,author, ssbKey) { // but why are these stored separetly? fix this } - displayPayments(walletId) + electronInterface.displayPayments(wallets[walletId]) writeDbLocally() } } @@ -276,42 +278,6 @@ addExampleData = function(sbot,me) { } -displayPayments = function(walletId) { - // this would be the place to create a snazzy html table - if (wallets[walletId].payments) { - var payments = wallets[walletId].payments - - $("#paymentsTbody").html($(".unfilled").clone()) - - Object.keys(payments).forEach(function( index) { - - var commentList = "" - payments[index].comments.forEach(function(comment){ - // todo: resolve alias for comment.author and add it here - commentList += "

" - commentList += comment.comment - commentList += "

" - }) - - $(".unfilled").clone() - .find(".date").text("dateFromBlockchain").end() - .find(".comment").html(commentList).end() - .find(".rate").text(payments[index].rate).end() - .find(".amount").text("amountFromBlockchain").end() - .find(".recipients").text("recipeintsFromBlockchain").end() - .attr("class","index") - .insertAfter(".unfilled") - } ) - - - if (verbose) { - console.log('payments now looks like this:') - console.log(JSON.stringify(payments, null, 4)) - } - } else { - console.error('cant display payments as no payments associated with wallet') - } -} ssbClient(function (err, sbot) { @@ -374,7 +340,7 @@ ssbClient(function (err, sbot) { // writeDbLocally() // // for now just use the first wallet // var walletId = Object.keys(wallets)[0] - // if (walletId) displayPayments(walletId) + // if (walletId) electronInterface.displayPayments(wallets[walletId]) // } //sbot.close() })) diff --git a/testmeta b/testmeta deleted file mode 100644 index fa46df8..0000000 --- a/testmeta +++ /dev/null @@ -1,43 +0,0 @@ -{ - "addresses": { - "change": [ - "n2aRLeJJpdmCXa8Ew9fcRuEoDDAZhRs5Ch", - "mx8aMtE5peoy8D7Vw4C1EKRL9Lgt5g4nqw", - "mxAVGPQ3UxecEGadsARCFAsk1SMeigbk5K", - "mixyAwLvpVZUrzYxufHED6XXWDCHfnX5Sw", - "mkMxkkFarTEoayW3d1Ua3JrxcQAr5mqLSp", - "mrCZbxGhNqfRLeqWzrzN3WB9bojT8dyVYo" - ], - "receiving": [ - "mtw5EMHPVkawfSZsW8N1MFhan1i39f2TgK", - "moF44t7ydEJibCxNpnkYyPwKwWYZ88iMzU", - "n4j2bLsHnHosfKLt1j76kiefsPW52prHBx", - "mnLUeqadsLYExawpMmQj9fcxMCkZnQTfBw", - "mndi5N5xTcwumR2NJvxkPQu2CkrSxK9hZP", - "mtAWiRyimUU5e81XpfgdwiSZ6gHoGYKVpi", - "mizfyRFaKSoPEp3Kpv5iyUWemHHgcu8Jv5", - "mu1fsqfCzKARKi5a9hXpnz5kQDx23xVkjr", - "n3gsaGPphagnYHQMg7Waj5UqssuSZPXX1B", - "mztV1SxXTMhBnf5Yz7RELw77hn86To1qqL", - "mttAY8KLCB15bGmZSpQo9Vb37HGDre1Zzn", - "mxXdcmqYCbf41sJYtaMXJ69cjzVS6UjfZt", - "msnyEBkkyLTZuQZ5v6JmJTJF3ZFqbYSVJb", - "mxv93QCA1qbS4Apv73y8VCHGorjEGbQFUj", - "mw5UuhLDaHKwqY3sE5RshXVJJdC1GFd4UW", - "moN8i61zUChNWCFMRDdqqBDTLawr1Q9iR7", - "mwiUtzyofckPRExVsZikRQPUi4mCpy2998", - "n2kh94qoBwZTYY53w2QRN3DS4YzPk8xJoR", - "mxd58JMYUDF7wGaCJAV5dervbQKMRauf33", - "mzNYt4yZN5RXmCV1N9a52JTAxhisgwdpi9" - ] - }, - "keystore": { - "seed": "tornado useful festival arrange lemon crazy hope raw wealth skate slow ribbon", - "type": "bip32", - "xprv": "xprv9s21ZrQH143K3D36scAjt3QXctLrXRFfWErhhz46MNJhy72DYxybGmgX4FyVy4eW3ViK48vPRJG1hqDBhyGuZJvWftYovfEkzTVVJMdQaAf", - "xpub": "xpub661MyMwAqRbcFh7ZydhkFBMGAvBLvsyWsTnJWNThuhqgquMN6WHqpZzzuZSmKmfWxJAGajfhQEhnDQr36j9VUuNsjrgq5EKXYQC6dWurkRL" - }, - "seed_version": 16, - "use_encryption": false, - "wallet_type": "standard" -} \ No newline at end of file From 09ccaa0f08d20c130d9a340ce786f96b2960f347 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 11:00:16 +0200 Subject: [PATCH 47/72] readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 35884f7..1ef4d13 100644 --- a/readme.md +++ b/readme.md @@ -115,3 +115,4 @@ electrum --testnet daemon stop * [pull-stream docs](https://pull-stream.github.io/) * [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) * [electrum json rpc interface](http://docs.electrum.org/en/latest/merchant.html#jsonrpc-interface) +* [live.blockcypher.com/btc-testnet](https://live.blockcypher.com/btc-testnet/) - this is the testnet explorer im using. If you know a better one, post it here From 1378824da9e7d12a6fdef7d3a843032274b6241a Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 10 May 2018 13:10:34 +0200 Subject: [PATCH 48/72] automate starting daemon and loading unencrypted wallet --- electrum-client.js | 56 +++++++++++++++++++++++++++- mmt-metadata.js | 93 ++++++++++++++++++++++++---------------------- 2 files changed, 103 insertions(+), 46 deletions(-) diff --git a/electrum-client.js b/electrum-client.js index 78b7889..4548da9 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -3,6 +3,14 @@ const request = require('request'); +var exec = require('child_process').exec + +const testnet = true + +var baseCommand = 'electrum ' +if (testnet) baseCommand += '--testnet ' + + // things we probably need: (theres more but this is the basics) // addrequest Create a payment request, using the first unused // address of the wallet @@ -63,9 +71,55 @@ electrumRequest = function (method, params, callback) { } +ec.setupElectrum = function (walletFile,callback) { + // could split this into separate function so we can switch + // wallets without restarting the daemon but this will do + // for now. + + // TODO: either just run these commands or check if they were + // allready run with getconfig + //electrum --testnet setconfig rpcport 8888 + //electrum --testnet setconfig rpcuser spinach + //electrum --testnet setconfig rpcpassword test + + + console.log('Starting electrum daemon') + var child = exec(baseCommand + 'daemon start', function(err, stdout, stderr) { + if (err) throw err + else { + console.log(stdout) + console.log('Electrum daemon stopped') + } + }) + + // '~/.electrum/testnet/wallets/testnetw daemon' + + var child = exec(baseCommand + '-w '+walletFile+' daemon load_wallet', function(err, stdout, stderr) { + if (err) throw err + else { + console.log(stdout) + console.log('Wallet '+walletFile+' loaded successfully') + callback(err,stdout) + } + }) +} + + +ec.stopElectrum = function (walletFile,callback) { + console.log('Stopping electrum daemon') + var child = exec(baseCommand + 'daemon stop', function(err, stdout, stderr) { + if (err) throw err + else { + console.log(stdout) + console.log('Electrum daemon stopped successfully') + } + }) +} +// should this be run as an external command so that we know even before +// starting daemon? ec.checkVersion = function (requiredVersion, callback) { - // todo: remove dots from version number, convert to int and compare + // todo: remove dots from version number, convert to int and do > electrumRequest("version", [], function (err,output) { var check = false // are we actually connected to electrum? diff --git a/mmt-metadata.js b/mmt-metadata.js index 65f01e7..ec7089d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -23,7 +23,8 @@ const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', var verbose = true - +// this is temporary +var walletFile = '~/.electrum/testnet/wallets/default_wallet' var wallets = {} @@ -300,50 +301,52 @@ ssbClient(function (err, sbot) { wallets = readDbLocally() - //ec.parseHistory(wallets[walletId], function(err,output) { - // console.log(JSON.stringify(output,null,4)) - //}) - - // todo: run once with live:false, to find wallets. then present choice of found - // wallets or 'create new' - var count = 0 - messageTypes.forEach(function (messageType) { - // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: false, type: messageType }) - , pull.drain(function (message) { - - try { - if (message.value) - if (message.value.content) { - // attempt to decrypt message - try { - //console.log(JSON.stringify(message,null,4)) - // todo: we also need to pass the recipients and validate them - sbot.private.unbox(message.value.content, function(err, msg) { - processDecryptedMessage(err, msg, message.value.author, message.key) - }) - } catch(e) { - console.error('error while decrypting',e) - } - - } - } catch(e) { - console.error(e) - - } - }, function(err) { - if (err) console.error(err) - // this will only be reached if live = false. which gives us a chance to tidy - // things up but then we dont find new messages - // count++ - // if (count === messageTypes.length) { - // writeDbLocally() - // // for now just use the first wallet - // var walletId = Object.keys(wallets)[0] - // if (walletId) electronInterface.displayPayments(wallets[walletId]) - // } - //sbot.close() - })) + ec.setupElectrum(walletFile, function (err,output) { + //ec.parseHistory(wallets[walletId], function(err,output) { + // console.log(JSON.stringify(output,null,4)) + //}) + + // todo: run once with live:false, to find wallets. then present choice of found + // wallets or 'create new' + var count = 0 + messageTypes.forEach(function (messageType) { + // drain lets us process stuff as it comes + pull(sbot.messagesByType({ live: false, type: messageType }) + , pull.drain(function (message) { + + try { + if (message.value) + if (message.value.content) { + // attempt to decrypt message + try { + //console.log(JSON.stringify(message,null,4)) + // todo: we also need to pass the recipients and validate them + sbot.private.unbox(message.value.content, function(err, msg) { + processDecryptedMessage(err, msg, message.value.author, message.key) + }) + } catch(e) { + console.error('error while decrypting',e) + } + + } + } catch(e) { + console.error(e) + + } + }, function(err) { + if (err) console.error(err) + // this will only be reached if live = false. which gives us a chance to tidy + // things up but then we dont find new messages + // count++ + // if (count === messageTypes.length) { + // writeDbLocally() + // // for now just use the first wallet + // var walletId = Object.keys(wallets)[0] + // if (walletId) electronInterface.displayPayments(wallets[walletId]) + // } + //sbot.close() + })) + } ) } ) } ) }) From 987023eb72af65a7635ba0669f517c5ed1fa54b0 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 11:29:50 +0200 Subject: [PATCH 49/72] buttons, deepmerge and other bits --- electron-interface.js | 21 ++++++++++++++++++--- electrum-client.js | 42 ++++++++++++++++++++++-------------------- index.html | 15 +++++++++++++++ localdb.json.example | 16 ++++++++++++++-- mmt-metadata.js | 24 +++++++++++++++--------- package-lock.json | 5 +++++ package.json | 1 + 7 files changed, 90 insertions(+), 34 deletions(-) diff --git a/electron-interface.js b/electron-interface.js index c2d6179..c0afa6f 100644 --- a/electron-interface.js +++ b/electron-interface.js @@ -10,20 +10,35 @@ electronInterface.displayPayments = function(wallet) { Object.keys(payments).forEach(function( index) { - var commentList = "" + var commentList = "" + + if (typeof payments[index].comments === 'undefined') payments[index].comments = [] + if (typeof payments[index].amount === 'undefined') payments[index].amount = 'unknown' + if (typeof payments[index].confirmations === 'undefined') payments[index].confirmations = 'unknown' + if (typeof payments[index].timestamp === 'undefined') + var dateDisplay = payments[index].timestamp = 'unknown' + else { + var dateDisplay = new Date(payments[index].timestamp) + dateDisplay = dateDisplay.toUTCString() + } payments[index].comments.forEach(function(comment){ // todo: resolve alias for comment.author and add it here + // possibly with avatar image commentList += "

" commentList += comment.comment commentList += "

" }) $(".unfilled").clone() - .find(".date").text("dateFromBlockchain").end() + .find(".date").text(dateDisplay).end() + .find(".cosigners").text("").end() .find(".comment").html(commentList).end() .find(".rate").text(payments[index].rate).end() - .find(".amount").text("amountFromBlockchain").end() + .find(".amount").text(payments[index].amount).end() + // TODO: make a thingy that goes from red to green with under 6 confimations + .find(".confirmations").text(payments[index].confirmations).end() .find(".recipients").text("recipeintsFromBlockchain").end() + //.find(".options").find(".details") .end() //change onclick attribute .attr("class","index") .insertAfter(".unfilled") } ) diff --git a/electrum-client.js b/electrum-client.js index 4548da9..5f9c88f 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -64,8 +64,8 @@ electrumRequest = function (method, params, callback) { password: 'test' } } - request(options, function(err,response,body) { + if (err) console.error(err) callback(err,body) }) @@ -190,35 +190,37 @@ ec.payToMany = function (outputs, callback) { ec.history = function (callback) { electrumRequest("history", [], function (err,output) { - callback(err,output.result) + if (typeof output.result !== 'undefined') output = output.result + callback(err,output) }) } ec.parseHistory = function (wallet, callback) { ec.history( function(err,output) { - if (output.transactions) - output.transactions.forEach(function(transaction) { - if (typeof wallet.payments === 'undefined') - wallet.payments = {} - if (typeof wallet.payments[transaction.txid] === 'undefined') - wallet.payments[transaction.txid] = {} - wallet.payments[transaction.txid].amount = transaction.value.value - wallet.payments[transaction.txid].confirmations = transaction.confirmations - - // convert timestamp to seconds to use as javascript date - wallet.payments[transaction.txid].timestamp = transaction.timestamp * 1000 + if (output.transactions) + output.transactions.forEach(function(transaction) { + if (typeof wallet.payments === 'undefined') + wallet.payments = {} + if (typeof wallet.payments[transaction.txid] === 'undefined') + wallet.payments[transaction.txid] = {} + wallet.payments[transaction.txid].amount = transaction.value.value + wallet.payments[transaction.txid].confirmations = transaction.confirmations - // copy transaction.label as comment? - - }) - // could store balance as - //output.summary.end_balance.value - // or get it from getBalance + // convert timestamp to seconds to use as javascript date + wallet.payments[transaction.txid].timestamp = transaction.timestamp * 1000 + + // copy transaction.label as comment? + + }) + // could store balance as + //output.summary.end_balance.value + // or get it from getBalance callback(err,wallet) - }) + }) } + // test // ec.checkVersion("3.1.3", function(err, output) { // if (err) { diff --git a/index.html b/index.html index 007944b..659dfa7 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,12 @@ + +
@@ -20,19 +26,28 @@

mmt payment metadata app

Date + Cosigners Description and comments Rate Amount + Confirmations Recipient(s) + Options + + + + + + diff --git a/localdb.json.example b/localdb.json.example index c7434d8..55c4dd7 100644 --- a/localdb.json.example +++ b/localdb.json.example @@ -20,7 +20,10 @@ "comment": "this payment was a mistake" } ], - "rate": 5000 + "rate": 5000, + "amount": 59300, + "confirmations": 5443, + "timestamp": "unknown" }, "d5fsdffd1e8c35466cfe45dg": { "comments": [ @@ -29,7 +32,16 @@ "comment": "bought a cheese grater" } ], - "rate": 5560 + "rate": 5560, + "amount": 500, + "confirmations": 4, + "timestamp": "unknown" + }, + "dc4c9bf17b2dff0fff82e2b7cc98b343c14479586a4b8099dc0c52c825176647": { + "amount": 88000, + "confirmations": 3500, + "timestamp": 1524336989000, + "comments": [] } }, "cosigners": [ diff --git a/mmt-metadata.js b/mmt-metadata.js index ec7089d..b7a2c56 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -11,7 +11,8 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') var fs = require('fs') - +var merge = require('deepmerge') +const dontMerge = (destination, source) => source var ec = require("./electrum-client.js") var electronInterface = require("./electron-interface.js") @@ -77,7 +78,7 @@ writeDbLocally = function() { } -processDecryptedMessage = function(err, msg,author, ssbKey) { +processDecryptedMessage = function(err, msg,author, ssbKey,currentWallet) { if (msg) { @@ -152,7 +153,7 @@ processDecryptedMessage = function(err, msg,author, ssbKey) { // but why are these stored separetly? fix this } - electronInterface.displayPayments(wallets[walletId]) + electronInterface.displayPayments(wallets[currentWallet]) writeDbLocally() } } @@ -301,10 +302,15 @@ ssbClient(function (err, sbot) { wallets = readDbLocally() - ec.setupElectrum(walletFile, function (err,output) { - //ec.parseHistory(wallets[walletId], function(err,output) { - // console.log(JSON.stringify(output,null,4)) - //}) + // for now just use the first wallet (we need to let the user choose) + currentWallet = Object.keys(wallets)[0] + + //ec.setupElectrum(walletFile, function (err,output) { + + ec.parseHistory(wallets[currentWallet], function(err,output) { + if (err) console.error(err) + wallets[currentWallet] = merge(wallets[currentWallet], output, { arrayMerge: dontMerge }) + }) // todo: run once with live:false, to find wallets. then present choice of found // wallets or 'create new' @@ -322,7 +328,7 @@ ssbClient(function (err, sbot) { //console.log(JSON.stringify(message,null,4)) // todo: we also need to pass the recipients and validate them sbot.private.unbox(message.value.content, function(err, msg) { - processDecryptedMessage(err, msg, message.value.author, message.key) + processDecryptedMessage(err, msg, message.value.author, message.key,currentWallet) }) } catch(e) { console.error('error while decrypting',e) @@ -347,6 +353,6 @@ ssbClient(function (err, sbot) { //sbot.close() })) } ) - } ) + // } ) } ) }) diff --git a/package-lock.json b/package-lock.json index a62a81e..8711484 100644 --- a/package-lock.json +++ b/package-lock.json @@ -254,6 +254,11 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" }, + "deepmerge": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.0.tgz", + "integrity": "sha512-Q89Z26KAfA3lpPGhbF6XMfYAm3jIV3avViy6KOJ2JLzFbeWHOvPQUu5aSJIWXap3gDZC2y1eF5HXEPI2wGqgvw==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", diff --git a/package.json b/package.json index adff158..e1165d2 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ }, "license": "ISC", "dependencies": { + "deepmerge": "^2.1.0", "electron": "^1.4.6", "fs": "0.0.1-security", "pull-stream": "^3.6.7", From fe13718c5d0b0a249dc941ea6e3f0c97359332df Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 11:38:25 +0200 Subject: [PATCH 50/72] buttons that dont do anything --- index.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 659dfa7..8efb80f 100644 --- a/index.html +++ b/index.html @@ -22,7 +22,16 @@

mmt payment metadata app

- + +
+ + + + + + +
+
From eaa3aff3243ca18619e91584b18164870519fd69 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 12:07:29 +0200 Subject: [PATCH 51/72] jquery UI tabs --- index.html | 132 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 50 deletions(-) diff --git a/index.html b/index.html index 8efb80f..b10abee 100644 --- a/index.html +++ b/index.html @@ -3,63 +3,95 @@ mmt payment metadata app - - - - + - - + + + + + + + + + - + + + + + +

mmt payment metadata app

- -
- - - - - - +
+ +
+
Date
+ + + + + + + + + + + + + + + + + + + + + + + + +
Date Cosigners Description and comments Rate Amount Confirmations Recipient(s) Options
+ + +
- - - - - - - - - - - - - - - - - - - - - - - - - -
Date Cosigners Description and comments Rate Amount Confirmations Recipient(s) Options
- - -
+
+

coming soon

+
+
+

coming soon

+
+
+

coming soon

+
+
+

coming soon

+
+
+

coming soon

+
+
From fe264857a1e7834e13350755fd96ff6147589abd Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 12:30:52 +0200 Subject: [PATCH 52/72] keep css and js local --- css/bootstrap.min.css | 7 +++ css/jquery-ui.min.css | 7 +++ index.html | 122 +++++++++++++++++++++------------------ scripts/jquery-ui.min.js | 13 +++++ 4 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 css/bootstrap.min.css create mode 100644 css/jquery-ui.min.css create mode 100644 scripts/jquery-ui.min.js diff --git a/css/bootstrap.min.css b/css/bootstrap.min.css new file mode 100644 index 0000000..6561b6f --- /dev/null +++ b/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-check{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-webkit-box;display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-webkit-box;display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.media-body{-webkit-box-flex:1;-ms-flex:1;flex:1}.list-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#6c757d!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/css/jquery-ui.min.css b/css/jquery-ui.min.css new file mode 100644 index 0000000..776e259 --- /dev/null +++ b/css/jquery-ui.min.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.12.1 - 2016-09-14 +* http://jqueryui.com +* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/index.html b/index.html index b10abee..a6c0dab 100644 --- a/index.html +++ b/index.html @@ -5,9 +5,10 @@ mmt payment metadata app - - + + ").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],h=[],l=this._connectWith();if(l&&e)for(s=l.length-1;s>=0;s--)for(o=t(l[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&h.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(h.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t(" ",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,h,l,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[a],l=!1,e[u]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(e[u]-h)&&(n=Math.abs(e[u]-h),o=this.items[s],this.direction=l?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter; +this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}}),t.widget("ui.spinner",{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
").attr("role","tooltip"),s=t("
").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file From def61302db549c2bfc37f4caec656521290b9866 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 22:10:21 +0200 Subject: [PATCH 53/72] more html --- index.html | 10 +++- mmt-metadata.js | 123 +++++++++++++++++++++++++----------------------- 2 files changed, 71 insertions(+), 62 deletions(-) diff --git a/index.html b/index.html index a6c0dab..c291b71 100644 --- a/index.html +++ b/index.html @@ -80,11 +80,17 @@

mmt payment metadata app

-

coming soon

+

Balance available: BTC

+

Pay to:

+

Amount:

+
-

coming soon

+ + Memo + +
diff --git a/mmt-metadata.js b/mmt-metadata.js index b7a2c56..49b9c1c 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -288,71 +288,74 @@ ssbClient(function (err, sbot) { // this assumes we already have an ssb identity. // if not we need to create one wiht ssb-keys (todo) - sbot.whoami( function(err,msg) { - if (err) console.error('Error running whoami.', err) + if (sbot) + sbot.whoami( function(err,msg) { + if (err) console.error('Error running whoami.', err) - var me = msg.id - - if (verbose) console.log('whoami: ',me) - - - // uncomment this line to add example data to scuttlebutt - // note that if this is run multiple times it will create multiply identical entries - //addExampleData(sbot, me) + var me = msg.id - wallets = readDbLocally() + if (verbose) console.log('whoami: ',me) - // for now just use the first wallet (we need to let the user choose) - currentWallet = Object.keys(wallets)[0] - //ec.setupElectrum(walletFile, function (err,output) { - - ec.parseHistory(wallets[currentWallet], function(err,output) { - if (err) console.error(err) - wallets[currentWallet] = merge(wallets[currentWallet], output, { arrayMerge: dontMerge }) - }) + // uncomment this line to add example data to scuttlebutt + // note that if this is run multiple times it will create multiply identical entries + //addExampleData(sbot, me) - // todo: run once with live:false, to find wallets. then present choice of found - // wallets or 'create new' - var count = 0 - messageTypes.forEach(function (messageType) { - // drain lets us process stuff as it comes - pull(sbot.messagesByType({ live: false, type: messageType }) - , pull.drain(function (message) { - - try { - if (message.value) - if (message.value.content) { - // attempt to decrypt message - try { - //console.log(JSON.stringify(message,null,4)) - // todo: we also need to pass the recipients and validate them - sbot.private.unbox(message.value.content, function(err, msg) { - processDecryptedMessage(err, msg, message.value.author, message.key,currentWallet) - }) - } catch(e) { - console.error('error while decrypting',e) - } - - } - } catch(e) { - console.error(e) + wallets = readDbLocally() - } - }, function(err) { + // for now just use the first wallet (we need to let the user choose) + currentWallet = Object.keys(wallets)[0] + + //ec.setupElectrum(walletFile, function (err,output) { + + ec.parseHistory(wallets[currentWallet], function(err,output) { if (err) console.error(err) - // this will only be reached if live = false. which gives us a chance to tidy - // things up but then we dont find new messages - // count++ - // if (count === messageTypes.length) { - // writeDbLocally() - // // for now just use the first wallet - // var walletId = Object.keys(wallets)[0] - // if (walletId) electronInterface.displayPayments(wallets[walletId]) - // } - //sbot.close() - })) - } ) - // } ) - } ) + wallets[currentWallet] = merge(wallets[currentWallet], output, { arrayMerge: dontMerge }) + }) + + // todo: run once with live:false, to find wallets. then present choice of found + // wallets or 'create new' + var count = 0 + messageTypes.forEach(function (messageType) { + // drain lets us process stuff as it comes + pull(sbot.messagesByType({ live: false, type: messageType }) + , pull.drain(function (message) { + + try { + if (message.value) + if (message.value.content) { + // attempt to decrypt message + try { + //console.log(JSON.stringify(message,null,4)) + // todo: we also need to pass the recipients and validate them + sbot.private.unbox(message.value.content, function(err, msg) { + processDecryptedMessage(err, msg, message.value.author, message.key,currentWallet) + }) + } catch(e) { + console.error('error while decrypting',e) + } + + } + } catch(e) { + console.error(e) + + } + }, function(err) { + if (err) console.error(err) + // this will only be reached if live = false. which gives us a chance to tidy + // things up but then we dont find new messages + // count++ + // if (count === messageTypes.length) { + // writeDbLocally() + // // for now just use the first wallet + // var walletId = Object.keys(wallets)[0] + // if (walletId) electronInterface.displayPayments(wallets[walletId]) + // } + //sbot.close() + })) + } ) + // } ) + } ) + else + console.error('Unable to connect to sbot. Is sbot running?') }) From 80d2a29e6b4f0dfd43e18feb85b7bf523ab662f1 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 11 May 2018 22:51:22 +0200 Subject: [PATCH 54/72] display wallet info --- electron-interface.js | 11 +++++++++++ electrum-client.js | 6 ++++++ index.html | 7 ++++++- mmt-metadata.js | 9 ++++++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/electron-interface.js b/electron-interface.js index c0afa6f..2d7a4a5 100644 --- a/electron-interface.js +++ b/electron-interface.js @@ -1,6 +1,17 @@ var electronInterface = module.exports = {} + +electronInterface.displayWalletInfo = function(wallet) { + if (wallet.name) $("#walletName").text(wallet.name) + if (wallet.requiredCosigners) $("#requiredCosigners").text(wallet.requiredCosigners) + if (wallet.publicKeys) $("#numberCosigners").text(wallet.publicKeys.length) + if (wallet.balance) $(".balance").text(wallet.balance) + + // TODO: names and avatars of cosigners + +} + electronInterface.displayPayments = function(wallet) { // this would be the place to create a snazzy html table if (wallet.payments) { diff --git a/electrum-client.js b/electrum-client.js index 5f9c88f..867338a 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -188,6 +188,12 @@ ec.payToMany = function (outputs, callback) { }) } +ec.getBalance = function (callback) { + electrumRequest("getbalance", [], function (err,output) { + callback(err,output.result) + }) +} + ec.history = function (callback) { electrumRequest("history", [], function (err,output) { if (typeof output.result !== 'undefined') output = output.result diff --git a/index.html b/index.html index c291b71..858be40 100644 --- a/index.html +++ b/index.html @@ -37,6 +37,11 @@

mmt payment metadata app

+
+ - + of multisig. - + Confirmed balance: BTC +
-

Balance available: BTC

+

Balance available: BTC

Pay to:

Amount:

diff --git a/mmt-metadata.js b/mmt-metadata.js index 49b9c1c..45c7f1d 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -307,12 +307,19 @@ ssbClient(function (err, sbot) { currentWallet = Object.keys(wallets)[0] //ec.setupElectrum(walletFile, function (err,output) { + ec.getBalance(function(err,output) { + if (err) console.error(err) + wallets[currentWallet].balance = output.confirmed + electronInterface.displayWalletInfo(wallets[currentWallet]) + }) + + electronInterface.displayWalletInfo(wallets[currentWallet]) ec.parseHistory(wallets[currentWallet], function(err,output) { if (err) console.error(err) wallets[currentWallet] = merge(wallets[currentWallet], output, { arrayMerge: dontMerge }) }) - + // todo: run once with live:false, to find wallets. then present choice of found // wallets or 'create new' var count = 0 From 55aaf63ff721fa1ce81b9852bf629f704deea693 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Sat, 12 May 2018 15:03:30 +0200 Subject: [PATCH 55/72] recieve addresses --- electron-interface.js | 22 ++++++++++++++++---- electrum-client.js | 12 +++++++++++ index.html | 21 ++++++++++++++++--- mmt-metadata.js | 47 +++++++++++++++---------------------------- 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/electron-interface.js b/electron-interface.js index 2d7a4a5..3016d7c 100644 --- a/electron-interface.js +++ b/electron-interface.js @@ -10,6 +10,20 @@ electronInterface.displayWalletInfo = function(wallet) { // TODO: names and avatars of cosigners + + if (wallet.addresses) { + $("#addressesTbody").html($(".addressesUnfilled").clone()) + wallet.addresses.forEach( function(address) { + $(".addressesUnfilled").clone() + .find(".address").text(address).end() + .find(".amount").text("-").end() + .attr("class","filled") + .insertAfter(".addressesUnfilled") + } ) + } + + if (wallet.firstUnusedAddress) + $("#recieveAddress").text(wallet.firstUnusedAddress) } electronInterface.displayPayments = function(wallet) { @@ -17,7 +31,7 @@ electronInterface.displayPayments = function(wallet) { if (wallet.payments) { var payments = wallet.payments - $("#paymentsTbody").html($(".unfilled").clone()) + $("#paymentsTbody").html($(".paymentsUnfilled").clone()) Object.keys(payments).forEach(function( index) { @@ -40,7 +54,7 @@ electronInterface.displayPayments = function(wallet) { commentList += "

" }) - $(".unfilled").clone() + $(".paymentsUnfilled").clone() .find(".date").text(dateDisplay).end() .find(".cosigners").text("").end() .find(".comment").html(commentList).end() @@ -50,8 +64,8 @@ electronInterface.displayPayments = function(wallet) { .find(".confirmations").text(payments[index].confirmations).end() .find(".recipients").text("recipeintsFromBlockchain").end() //.find(".options").find(".details") .end() //change onclick attribute - .attr("class","index") - .insertAfter(".unfilled") + .attr("class","filled") + .insertAfter(".paymentsUnfilled") } ) diff --git a/electrum-client.js b/electrum-client.js index 867338a..f021409 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -128,6 +128,18 @@ ec.checkVersion = function (requiredVersion, callback) { }) } +ec.getUnusedAddress = function (callback) { + electrumRequest("getunusedaddress", [], function (err,output) { + callback(err, output.result) + }) +} + +ec.listAddresses = function (callback) { + electrumRequest("listaddresses", [], function (err,output) { + callback(err, output.result) + }) +} + ec.signTransaction = function (tx,password,callback) { electrumRequest("getmpk", {"tx": tx, "password": password }, function (err,output) { callback(err, output.result) diff --git a/index.html b/index.html index 858be40..ad2b913 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ @@ -67,7 +67,7 @@

mmt payment metadata app

- + @@ -92,13 +92,28 @@

mmt payment metadata app

- +

Recieve address:

Memo
+ + + + + + + + + + + + + + +
Address Amount

coming soon

diff --git a/mmt-metadata.js b/mmt-metadata.js index 45c7f1d..9aad90b 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -17,7 +17,8 @@ const dontMerge = (destination, source) => source var ec = require("./electrum-client.js") var electronInterface = require("./electron-interface.js") -var localDbFile = './localdb.json' +const localDbFile = './localdb.json' +var wallets = require(localDbFile) const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', 'unsignedMmtPaymentTest','addMmtPaymentCommentTest'] @@ -27,10 +28,10 @@ var verbose = true // this is temporary var walletFile = '~/.electrum/testnet/wallets/default_wallet' -var wallets = {} +//var wallets = {} -publishMessage = function (sbot, messageType, content, recipients) { +function publishMessage (sbot, messageType, content, recipients) { // publish an encrypted message @@ -46,31 +47,7 @@ publishMessage = function (sbot, messageType, content, recipients) { // todo: should we also update db in memory and write to file when doing this? } - - -readDbLocally = function() { - if (verbose) console.log('reading from local file.') - // for now just use a file as db is not likely to get big - - var dataFromFile = {} - - if (fs.existsSync(localDbFile)) { - - dataFromFile = JSON.parse(fs.readFileSync(localDbFile)) - - // todo: this wont work, it will clobber arrays of cosigners and comments. - // this information will need to be parsed the same as the stuff coming from ssb - //Object.keys(paymentsFromFile).forEach(function(key) { - // payments[key] = paymentsFromFile[key] - //} ) - - //Object.keys(payments).forEach(key => result[key] = payments[key]); - - } - return dataFromFile -} - -writeDbLocally = function() { +function writeDbLocally() { if (verbose) console.log('writing to local file') // should use deepmerge @@ -301,7 +278,7 @@ ssbClient(function (err, sbot) { // note that if this is run multiple times it will create multiply identical entries //addExampleData(sbot, me) - wallets = readDbLocally() + //wallets = readDbLocally() // for now just use the first wallet (we need to let the user choose) currentWallet = Object.keys(wallets)[0] @@ -312,8 +289,16 @@ ssbClient(function (err, sbot) { wallets[currentWallet].balance = output.confirmed electronInterface.displayWalletInfo(wallets[currentWallet]) }) - - electronInterface.displayWalletInfo(wallets[currentWallet]) + ec.listAddresses(function(err,output){ + if (err) console.error(err) + //console.log('addresses ', JSON.stringify(output,null,4)) + wallets[currentWallet].addresses = output + }) + ec.getUnusedAddress(function(err,output) { + wallets[currentWallet].firstUnusedAddress = output + // TODO: qr code + }) + electronInterface.displayWalletInfo(wallets[currentWallet]) ec.parseHistory(wallets[currentWallet], function(err,output) { if (err) console.error(err) From b2df314913242f5ca59994f663da38d65419fe16 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 14 May 2018 11:42:26 +0200 Subject: [PATCH 56/72] minor changes from mixs refactoring --- mmt-metadata.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/mmt-metadata.js b/mmt-metadata.js index 9aad90b..ed29c31 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -14,21 +14,24 @@ var fs = require('fs') var merge = require('deepmerge') const dontMerge = (destination, source) => source -var ec = require("./electrum-client.js") -var electronInterface = require("./electron-interface.js") +var ec = require("./electrum-client") +var electronInterface = require("./electron-interface") const localDbFile = './localdb.json' var wallets = require(localDbFile) -const messageTypes = ['initiateMmtMultisigTest','shareMmtPublicKeyTest', - 'unsignedMmtPaymentTest','addMmtPaymentCommentTest'] +const messageTypes = [ + 'initiateMmtMultisigTest', + 'shareMmtPublicKeyTest', + 'unsignedMmtPaymentTest', + 'addMmtPaymentCommentTest' +] var verbose = true // this is temporary var walletFile = '~/.electrum/testnet/wallets/default_wallet' -//var wallets = {} function publishMessage (sbot, messageType, content, recipients) { @@ -55,7 +58,7 @@ function writeDbLocally() { } -processDecryptedMessage = function(err, msg,author, ssbKey,currentWallet) { +function processDecryptedMessage(err, msg,author, ssbKey,currentWallet) { if (msg) { @@ -136,7 +139,7 @@ processDecryptedMessage = function(err, msg,author, ssbKey,currentWallet) { } -addXpub = function(msg,author,walletId,initiator) { +function addXpub(msg,author,walletId,initiator) { var xpubToAdd = { owner: author, @@ -163,7 +166,7 @@ addXpub = function(msg,author,walletId,initiator) { } } -addPaymentComment = function(msg, author,walletId) { +function addPaymentComment (msg, author,walletId) { // if we dont yet have this entry, define it if (typeof wallets[walletId].payments[msg.content.key] === 'undefined') @@ -190,7 +193,7 @@ addPaymentComment = function(msg, author,walletId) { wallets[walletId].payments[msg.content.key].comments.push(commentToAdd) } -addExampleData = function(sbot,me) { +function addExampleData(sbot,me) { // todo: could we get the name from ssb about message? // using ssb-about? and maybe avatar,etc From 5aa2831ea97a4c55ec927fcce83e399d0e92ac36 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 14 May 2018 12:46:32 +0200 Subject: [PATCH 57/72] send button --- electron-interface.js | 8 ++++++++ electrum-client.js | 7 +++++-- index.html | 5 +++-- mmt-metadata.js | 5 ++--- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/electron-interface.js b/electron-interface.js index 3016d7c..798851f 100644 --- a/electron-interface.js +++ b/electron-interface.js @@ -77,3 +77,11 @@ electronInterface.displayPayments = function(wallet) { console.error('cant display payments as no payments associated with wallet') } } + +electronInterface.createTransaction = function() { + var sendAmount = parseFloat($("input#sendAmount").val()) + if ((!sendAmount) || (sendAmount < 0)) + $("#sendVerifyErrors").text("invalid amount") + else + $("#sendVerifyErrors").text("") +} diff --git a/electrum-client.js b/electrum-client.js index f021409..9c47fc8 100644 --- a/electrum-client.js +++ b/electrum-client.js @@ -65,7 +65,7 @@ electrumRequest = function (method, params, callback) { } } request(options, function(err,response,body) { - if (err) console.error(err) + if (err) console.log("Error from electrum. Is the electrum daemon running?",err) callback(err,body) }) @@ -202,7 +202,10 @@ ec.payToMany = function (outputs, callback) { ec.getBalance = function (callback) { electrumRequest("getbalance", [], function (err,output) { - callback(err,output.result) + if ((output) && output.result) + callback(err,output.result) + else + callback(1,null) }) } diff --git a/index.html b/index.html index ad2b913..7e68582 100644 --- a/index.html +++ b/index.html @@ -87,8 +87,9 @@

mmt payment metadata app

Balance available: BTC

Pay to:

-

Amount:

- +

Amount:

+ +

diff --git a/mmt-metadata.js b/mmt-metadata.js index ed29c31..52de47a 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -33,7 +33,6 @@ var verbose = true var walletFile = '~/.electrum/testnet/wallets/default_wallet' - function publishMessage (sbot, messageType, content, recipients) { // publish an encrypted message @@ -288,8 +287,8 @@ ssbClient(function (err, sbot) { //ec.setupElectrum(walletFile, function (err,output) { ec.getBalance(function(err,output) { - if (err) console.error(err) - wallets[currentWallet].balance = output.confirmed + if (err) console.log(err) + else wallets[currentWallet].balance = output.confirmed electronInterface.displayWalletInfo(wallets[currentWallet]) }) ec.listAddresses(function(err,output){ From edad576d702480959bb22b228d8805d449b0826a Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 14 May 2018 22:52:27 +0200 Subject: [PATCH 58/72] verify bitcoin addresses --- bitcoin-utils.js | 9 ++ electron-interface.js | 13 ++- index.html | 6 ++ mmt-metadata.js | 1 + package-lock.json | 193 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + testvalidate | 13 +++ 7 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 bitcoin-utils.js create mode 100644 testvalidate diff --git a/bitcoin-utils.js b/bitcoin-utils.js new file mode 100644 index 0000000..7b3a943 --- /dev/null +++ b/bitcoin-utils.js @@ -0,0 +1,9 @@ +var bitcoin = require('bitcoinjs-lib') + +function validAddress(address) { + try { + return bitcoin.address.toOutputScript(address, bitcoin.networks.testnet) + } catch (e) { return false } +} + +module.exports = { validAddress } diff --git a/electron-interface.js b/electron-interface.js index 798851f..02b2bdc 100644 --- a/electron-interface.js +++ b/electron-interface.js @@ -1,4 +1,5 @@ +var bitcoinUtils = require('./bitcoin-utils') var electronInterface = module.exports = {} @@ -79,9 +80,15 @@ electronInterface.displayPayments = function(wallet) { } electronInterface.createTransaction = function() { + $("#sendVerifyErrors").text("") + var sendAmount = parseFloat($("input#sendAmount").val()) if ((!sendAmount) || (sendAmount < 0)) - $("#sendVerifyErrors").text("invalid amount") - else - $("#sendVerifyErrors").text("") + $("#sendVerifyErrors").text("Invalid amount. ") + // todo: compare with balance + + + var payTo = $("input#payTo").val() + if (!bitcoinUtils.validAddress(payTo)) + $("#sendVerifyErrors").append("Invalid BTC address. ") } diff --git a/index.html b/index.html index 7e68582..d823d56 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,12 @@ .paymentsUnfilled { display: none; } + .addressesUnfilled { + display: none; + } + #payTo { + width: 400px; + } diff --git a/mmt-metadata.js b/mmt-metadata.js index 52de47a..0f85eb0 100644 --- a/mmt-metadata.js +++ b/mmt-metadata.js @@ -11,6 +11,7 @@ var pull = require('pull-stream') var ssbClient = require('ssb-client') var fs = require('fs') +var bitcoin = require('bitcoinjs-lib') var merge = require('deepmerge') const dontMerge = (destination, source) => source diff --git a/package-lock.json b/package-lock.json index 8711484..a8b1739 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "base-x": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", + "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", + "requires": { + "safe-buffer": "5.1.1" + } + }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", @@ -69,6 +77,51 @@ "tweetnacl": "0.14.5" } }, + "bech32": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.3.tgz", + "integrity": "sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg==" + }, + "bigi": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", + "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "bitcoin-ops": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", + "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==" + }, + "bitcoinjs-lib": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-3.3.2.tgz", + "integrity": "sha512-l5qqvbaK8wwtANPf6oEffykycg4383XgEYdia1rI7/JpGf1jfRWlOUCvx5TiTZS7kyIvY4j/UhIQ2urLsvGkzw==", + "requires": { + "bech32": "1.1.3", + "bigi": "1.4.2", + "bip66": "1.1.5", + "bitcoin-ops": "1.4.1", + "bs58check": "2.1.1", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ecurve": "1.0.6", + "merkle-lib": "2.0.10", + "pushdata-bitcoin": "1.0.1", + "randombytes": "2.0.6", + "safe-buffer": "5.1.1", + "typeforce": "1.12.0", + "varuint-bitcoin": "1.1.0", + "wif": "2.0.6" + } + }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", @@ -86,6 +139,23 @@ "concat-map": "0.0.1" } }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "3.0.4" + } + }, + "bs58check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.1.tgz", + "integrity": "sha512-okRQiWc5FJuA2VOwQ1hB7Sf0MyEFg/EwRN12h4b8HrJoGkZ3xq1CGjkaAfYloLcZyqixQnO5mhPpN6IcHSplVg==", + "requires": { + "bs58": "4.0.1", + "create-hash": "1.2.0" + } + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -130,6 +200,15 @@ "json-buffer": "2.0.11" } }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -197,6 +276,42 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "md5.js": "1.3.4", + "ripemd160": "2.0.2", + "sha.js": "2.4.5" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.3", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.1", + "sha.js": "2.4.11" + }, + "dependencies": { + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + } + } + }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", @@ -273,6 +388,15 @@ "jsbn": "0.1.1" } }, + "ecurve": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", + "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", + "requires": { + "bigi": "1.4.2", + "safe-buffer": "5.1.1" + } + }, "ed2curve": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.1.4.tgz", @@ -470,6 +594,15 @@ "har-schema": "2.0.0" } }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, "hawk": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", @@ -694,6 +827,15 @@ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + } + }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -711,6 +853,11 @@ "trim-newlines": "1.0.0" } }, + "merkle-lib": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", + "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" + }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -1074,11 +1221,27 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "pushdata-bitcoin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", + "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", + "requires": { + "bitcoin-ops": "1.4.1" + } + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "requires": { + "safe-buffer": "5.1.1" + } + }, "rc": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", @@ -1179,6 +1342,15 @@ "glob": "7.1.2" } }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -1513,6 +1685,11 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typeforce": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.12.0.tgz", + "integrity": "sha512-fvnkvueAOFLhtAqDgIA/wMP21SMwS/NQESFKZuwVrj5m/Ew6eK2S0z0iB++cwtROPWDOhaT6OUfla8UwMw4Adg==" + }, "ultron": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", @@ -1537,6 +1714,14 @@ "spdx-expression-parse": "3.0.0" } }, + "varuint-bitcoin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz", + "integrity": "sha512-jCEPG+COU/1Rp84neKTyDJQr478/hAfVp5xxYn09QEH0yBjbmPeMfuuQIrp+BUD83hybtYZKhr5elV3bvdV1bA==", + "requires": { + "safe-buffer": "5.1.1" + } + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -1547,6 +1732,14 @@ "extsprintf": "1.3.0" } }, + "wif": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", + "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "requires": { + "bs58check": "2.1.1" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index e1165d2..d54d636 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ }, "license": "ISC", "dependencies": { + "bitcoinjs-lib": "^3.3.2", "deepmerge": "^2.1.0", "electron": "^1.4.6", "fs": "0.0.1-security", diff --git a/testvalidate b/testvalidate new file mode 100644 index 0000000..7220ee3 --- /dev/null +++ b/testvalidate @@ -0,0 +1,13 @@ + +var bitcoin = require('bitcoinjs-lib') +var address = "mu1yJFE97UsuszLtDbqF8ci6jH3ZEFcA5uN" + +function validAddress(address) { +try { + return bitcoin.address.toOutputScript(address, bitcoin.networks.testnet) +} catch (e) { return false } +} + +if (valid(address)) console.log('yes') + else console.log('no') + From e10712d1b79e17fa16c4e168e57d547062d69276 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 15 May 2018 09:14:43 +0200 Subject: [PATCH 59/72] move files around --- index.html => html/index.html | 10 +++++----- package.json | 4 ++-- bitcoin-utils.js => src/bitcoin-utils.js | 0 electron-interface.js => src/electron-interface.js | 2 +- electrum-client.js => src/electrum-client.js | 0 main.js => src/main.js | 2 +- mmt-metadata.js => src/mmt-metadata.js | 7 ++++--- testvalidate | 13 ------------- 8 files changed, 13 insertions(+), 25 deletions(-) rename index.html => html/index.html (93%) rename bitcoin-utils.js => src/bitcoin-utils.js (100%) rename electron-interface.js => src/electron-interface.js (98%) rename electrum-client.js => src/electrum-client.js (100%) rename main.js => src/main.js (96%) rename mmt-metadata.js => src/mmt-metadata.js (98%) delete mode 100644 testvalidate diff --git a/index.html b/html/index.html similarity index 93% rename from index.html rename to html/index.html index d823d56..c68a4c1 100644 --- a/index.html +++ b/html/index.html @@ -5,8 +5,8 @@ mmt payment metadata app - - + +