This commit is contained in:
Matias Alejo Garcia 2015-03-06 12:00:10 -03:00
parent 04fb7ba032
commit 320de62f13
348 changed files with 7756 additions and 30885 deletions

View File

@ -1,3 +0,0 @@
{
"directory": "lib"
}

2
.ctags
View File

@ -1,2 +0,0 @@
--exclude=js/copayBundle.js
--exclude=lib/bitcore/browser/bundle.js

143
.gitignore vendored
View File

@ -1,85 +1,82 @@
# from https://github.com/github/gitignore/blob/master/Node.gitignore
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.sw*
*.sig
tags
pids
logs
results
build
node_modules
# extras
*.swp
*.swo
*~
.project
peerdb.json
npm-debug.log
.nodemonignore
.DS_Store
public/lib/*
public/js/angularjs-all.js
public/js/main.js
public/js/vendors.js
public/css/main.css
README.html
lib/*
!lib/socket.io.js
!lib/sjcl.js
js/copayBundle.js
js/copayMain.js
css/copay.min.css
css/vendors.min.css
# translation
po/*
!po/*.po
js/translations.js
src/js/translations.js
webapp
browser-extensions/chrome/copay-chrome-extension
browser-extensions/chrome/copay-chrome-extension.zip
browser-extensions/firefox/firefox-addon
browser-extensions/firefox/data
browser-extensions/firefox/copay.xpi
version.js
!js/controllers/version.js
# version
src/js/version.js
# cordova
cordova/project/*
cordova/*.keystore
coverage/
# Logs
logs
*.log
shell/bin/linux
shell/bin/darwin
shell/bin/win32
# readme
README.html
shell/scripts/bin
shell/scripts/build
# Runtime data
pids
*.pid
*.seed
dist/darwin
dist/linux
dist/windows
dist/web
dist/*.dmg
dist/*.tar.gz
dist/*.exe
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
doc/
/node_modules
/*-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules
bower_components
# Users Environment Variables
.lock-wscript
# OSX
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# VIM ignore
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~
# copay public
public/icons/*
public/css/*
public/lib/*
public/js/*

15
.jshint
View File

@ -1,15 +0,0 @@
{
"camelcase": true,
"curly": true,
"eqeqeq": true,
"freeze": true,
"indent": 2,
"newcap": true,
"quotmark": "single",
"maxdepth": 3,
"maxstatements": 15,
"maxlen": 80,
"eqnull": true,
"funcscope": true,
"node": true
}

View File

@ -1,9 +1,8 @@
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
// Project Configuration
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
release: {
options: {
bump: true,
@ -26,11 +25,11 @@ module.exports = function(grunt) {
}
},
exec: {
prod: {
command: 'node ./util/build.js'
version: {
command: 'node ./util/version.js'
},
dev: {
command: 'node ./util/build.js -d'
clear: {
command: 'rm -Rf bower_components node_modules'
}
},
watch: {
@ -44,52 +43,22 @@ module.exports = function(grunt) {
files: ['README.md'],
tasks: ['markdown']
},
scripts: {
files: [
'js/models/*.js',
'js/util/*.js',
'js/plugins/*.js',
'js/*.js',
'!js/copayBundle.js',
'!js/copayMain.js'
],
tasks: ['exec:dev']
},
css: {
files: ['css/src/*.css'],
tasks: ['cssmin:desktop']
files: ['src/css/*.css'],
tasks: ['concat:css']
},
main: {
files: [
'js/init.js',
'js/app.js',
'js/directives.js',
'js/filters.js',
'js/routes.js',
'js/services/*.js',
'js/controllers/*.js'
'src/js/init.js',
'src/js/app.js',
'src/js/directives/*.js',
'src/js/filters/*.js',
'src/js/routes.js',
'src/js/services/*.js',
'src/js/models/*.js',
'src/js/controllers/*.js'
],
tasks: ['concat:main']
},
config: {
files: ['config.js'],
tasks: ['exec:dev', 'concat:main']
},
test: {
files: ['test/**/*.js'],
tasks: ['mochaTest']
}
},
mochaTest: {
tests: {
options: {
require: 'setup/node.js',
reporter: 'spec',
mocha: require('mocha')
},
src: [
'test/*.js',
]
tasks: ['concat:js']
}
},
markdown: {
@ -97,72 +66,80 @@ module.exports = function(grunt) {
files: [{
expand: true,
src: 'README.md',
dest: '.',
dest: './doc',
ext: '.html'
}]
}
},
concat: {
vendors: {
src: [
'lib/moment/min/moment.min.js',
'lib/qrcode-generator/js/qrcode.js',
'lib/lodash/dist/lodash.js',
'lib/bitcore.js',
'lib/file-saver/FileSaver.js',
'lib/socket.io-client/socket.io.js',
'lib/sjcl.js',
'lib/qrcode-decoder-js/lib/qrcode-decoder.min.js',
'lib/moment/lang/*.js'
],
dest: 'lib/vendors.js'
options: {
sourceMap: false,
sourceMapStyle: 'link' // embed, link, inline
},
angular: {
src: [
'lib/angular/angular.min.js',
'lib/angular-route/angular-route.min.js',
'lib/angular-moment/angular-moment.js',
'lib/angular-qrcode/qrcode.js',
'lib/ng-idle/angular-idle.min.js',
'lib/angular-foundation/mm-foundation.min.js',
'lib/angular-foundation/mm-foundation-tpls.min.js',
'lib/angular-gettext/dist/angular-gettext.min.js',
'lib/angular-load/angular-load.min.js',
'lib/angular-gravatar/build/md5.min.js',
'lib/angular-gravatar/build/angular-gravatar.min.js',
'lib/angular-touch/angular-touch.min.js'
// If you add libs here, remember to add it too to karma.conf
'bower_components/fastclick/lib/fastclick.js',
'bower_components/qrcode-generator/js/qrcode.js',
'bower_components/qrcode-decoder-js/lib/qrcode-decoder.js',
'bower_components/moment/min/moment-with-locales.js',
'bower_components/angular/angular.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/angular-local-storage/dist/angular-local-storage.js',
'bower_components/angular-foundation/mm-foundation.js',
'bower_components/angular-foundation/mm-foundation-tpls.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-moment/angular-moment.js',
'bower_components/ng-lodash/build/ng-lodash.js',
'bower_components/angular-qrcode/qrcode.js',
'bower_components/angular-gettext/dist/angular-gettext.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/angular-bitcore-wallet-client/angular-bitcore-wallet-client.js',
'bower_components/angular-ui-switch/angular-ui-switch.js'
],
dest: 'lib/angularjs-all.js'
dest: 'public/lib/angular.js'
},
main: {
js: {
src: [
'js/app.js',
'js/directives.js',
'js/filters.js',
'js/routes.js',
'js/services/*.js',
'js/controllers/*.js',
'js/translations.js',
'js/init.js',
'src/js/app.js',
'src/js/routes.js',
'src/js/directives/*.js',
'src/js/filters/*.js',
'src/js/models/*.js',
'src/js/services/*.js',
'src/js/controllers/*.js',
'src/js/translations.js',
'src/js/version.js',
'src/js/init.js'
],
dest: 'js/copayMain.js'
dest: 'public/js/copay.js'
},
css: {
src: ['src/css/*.css'],
dest: 'public/css/copay.css'
},
foundation: {
src: [
'bower_components/angular/angular-csp.css',
'bower_components/foundation/css/foundation.css',
'bower_components/animate.css/animate.css',
'bower_components/angular-ui-switch/angular-ui-switch.css'
],
dest: 'public/css/foundation.css',
}
},
cssmin: {
desktop: {
copay: {
files: {
'css/copay.min.css': ['css/src/*.css'],
'public/css/copay.css': ['src/css/*.css'],
}
},
mobile: {
foundation: {
files: {
'css/copay.min.css': ['css/src/*.css', '!css/src/desktop.css', '!css/src/animation.css'],
}
},
vendors: {
files: {
'css/vendors.min.css': ['css/foundation.min.css', 'css/foundation-icons.css']
'public/css/foundation.css': [
'bower_components/angular/angular-csp.css',
'bower_components/foundation/css/foundation.css',
'bower_components/animate.css/animate.css'
]
}
}
},
@ -172,16 +149,15 @@ module.exports = function(grunt) {
},
prod: {
files: {
'js/copayMain.js': ['js/copayMain.js'],
'lib/angularjs-all.js': ['lib/angularjs-all.js'],
'lib/vendors.js': ['lib/vendors.js']
'public/js/copay.js': ['public/js/copay.js'],
'public/lib/angular.js': ['public/lib/angular.js']
}
}
},
nggettext_extract: {
pot: {
files: {
'po/template.pot': ['index.html', 'views/*.html', 'views/**/*.html']
'po/template.pot': ['public/index.html', 'public/views/*.html', 'public/views/**/*.html']
}
},
},
@ -191,70 +167,58 @@ module.exports = function(grunt) {
module: 'copayApp'
},
files: {
'js/translations.js': ['po/*.po']
'src/js/translations.js': ['po/*.po']
}
},
},
copy: {
dist: {
files: [
{
src: [
'index.html',
'init.js',
'config.js',
'popup.html',
'css/vendors.min.css',
'css/copay.min.css',
'js/copayBundle.js',
'js/copayMain.js',
'lib/vendors.js',
'lib/angularjs-all.js',
'font/**',
'img/**',
'sound/**',
'views/**'
],
dest: 'dist/web/'
}
],
},
icons: {
expand: true,
flatten: true,
src: 'bower_components/foundation-icon-fonts/foundation-icons.*',
dest: 'public/icons/'
}
},
jsdoc: {
dist: {
src: ['js/models/*.js', 'js/plugins/*.js'],
options: {
destination: 'doc',
configure: 'jsdoc.conf.json',
template: './node_modules/grunt-jsdoc/node_modules/ink-docstrap/template',
theme: 'flatly'
}
karma: {
unit: {
configFile: 'test/karma.conf.js'
},
prod: {
configFile: 'test/karma.conf.js',
singleRun: true
}
},
coveralls: {
options: {
debug: false,
coverageDir: 'coverage/report-lcov',
dryRun: true,
force: true,
recursive: false
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-angular-gettext');
grunt.loadNpmTasks('grunt-markdown');
grunt.loadNpmTasks('grunt-release');
grunt.loadNpmTasks('grunt-exec');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-karma-coveralls');
grunt.registerTask('default', [
'exec:dev', 'nggettext_compile', 'concat', 'cssmin:desktop', 'cssmin:vendors'
]);
grunt.registerTask('mobile', [
'exec:dev', 'nggettext_compile', 'concat', 'cssmin:mobile', 'cssmin:vendors'
]);
grunt.registerTask('dist', [
'exec:prod', 'nggettext_compile', 'concat', 'cssmin:desktop', 'cssmin:vendors', 'uglify', 'copy:dist'
]);
grunt.registerTask('dist-dbg', [
'exec:prod', 'nggettext_compile', 'concat', 'cssmin:desktop', 'cssmin:vendors', 'copy:dist'
]);
grunt.registerTask('dist-mobile', [
'exec:prod', 'nggettext_compile', 'concat', 'cssmin:mobile', 'cssmin:vendors', 'uglify', 'copy:dist'
]);
grunt.registerTask('dist-mobile-dbg', [
'exec:dev', 'nggettext_compile', 'concat', 'cssmin:mobile', 'cssmin:vendors', 'copy:dist'
'nggettext_compile', 'exec:version', 'concat', 'copy'
]);
grunt.registerTask('prod', [
'exec:prod', 'nggettext_compile', 'concat', 'cssmin:desktop', 'cssmin:vendors', 'uglify'
'default', 'uglify'
]);
grunt.registerTask('translate', ['nggettext_extract']);
grunt.registerTask('docs', ['jsdoc']);
grunt.registerTask('test', ['karma:unit']);
grunt.registerTask('test-coveralls', ['karma:prod', 'coveralls']);
};

View File

@ -21,8 +21,8 @@ cordova-base:
# release-android: cordova-base
# make -C cordova release-android
#
wp8:
cordova/build.sh WP8
wp8-prod:
cordova/build.sh WP8 --clear
cordova/wp/fix-svg.sh
echo -e "\a"
@ -31,7 +31,7 @@ wp8-debug:
cordova/wp/fix-svg.sh
echo -e "\a"
ios:
ios-prod:
cordova/build.sh IOS --clear
cd cordova/project && cordova build ios
open cordova/project/platforms/ios/Copay.xcodeproj
@ -41,10 +41,14 @@ ios-debug:
cd cordova/project && cordova build ios
open cordova/project/platforms/ios/Copay.xcodeproj
android:
cordova/build.sh ANDROID --dbgjs --clear
cd cordova/project && cordova run android
android-prod:
cordova/build.sh ANDROID --clear
cd cordova/project && cordova build android --release
android-debug:
cordova/build.sh ANDROID --dbgjs --clear
cd cordova/project && cordova run android
android-debug-fast:
cordova/build.sh ANDROID --dbgjs
cd cordova/project && cordova run android

53
app.js
View File

@ -1,54 +1,13 @@
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
app.use(express.static(__dirname + '/public'));
// This is not really necesarry, just to simulate
// Content Security Policy from Google Chrome Apps.
//
// app.use(function(req, res, next){
// res.header("Content-Security-Policy", "script-src 'self';object-src 'none';media-src 'self';frame-src 'none';font-src 'self' data:");
// next();
// });
var port = process.env.PORT || 3000;
app.listen(port);
console.log("App listening on port " + port);
app.use('/', express.static(__dirname + '/'));
app.get('*', function(req, res) {
return res.sendFile(__dirname + '/' + 'index.html');
res.sendFile(path.join(__dirname, 'public'));
});
app.start = function(port, callback) {
app.set('port', port);
app.use(express.static(__dirname));
if (process.env.USE_HTTPS) {
var path = require('path');
var bc = path.dirname(require.resolve('bitcore/package.json'));
var pserver = require(bc + '/examples/PayPro/server.js');
pserver.removeListener('request', pserver.app);
// pserver.options['no-tx'] = true;
// pserver.options['discovery'] = true;
pserver.on('request', function(req, res) {
if (req.url.indexOf('/-/') === 0) {
return pserver.app(req, res);
}
return app(req, res);
});
pserver.listen(port, function() {
callback('https://localhost:' + port);
});
return;
}
app.listen(port, function() {
callback('http://localhost:' + port);
});
};
module.exports = app;

View File

@ -1,3 +1,8 @@
# Warning
This NEEDS to be updated.
## Running in the Native Shell
Copay can be executed from within a "native" application shell, providing some

View File

@ -3,19 +3,23 @@
"keywords": [
"copay",
"wallet",
"multisignature"
"multisignature",
"bircore"
],
"dependencies": {
"angular": "~1.3.0",
"angular": "~1.3.13",
"angular-foundation": "*",
"angular-route": "~1.3.0",
"angular-qrcode": "~3.1.0",
"angular-mocks": "~1.3.0",
"angular-gettext": "~1.1.0",
"mocha": "~1.18.2",
"chai": "~1.9.1",
"sjcl": "1.0.0",
"file-saver": "*",
"angular-animate": "~1.3.13",
"angular-touch": "~1.3.0",
"angular-qrcode": "~5.1.0",
"angular-gettext": "~2.0.5",
"animate.css": "~3.2.0",
"foundation": "zurb/bower-foundation#~5.5.1",
"foundation-icon-fonts": "*",
"ng-lodash": "~0.2.0",
"angular-moment": "~0.9.0",
"angular-bitcore-wallet-client": "^0.0.14",
"angular-ui-router": "~0.2.13",
"qrcode-decoder-js": "*",
"angular-moment": "~0.7.1",
"socket.io-client": ">=1.0.0",
@ -26,6 +30,6 @@
"angular-touch": "~1.3.0"
},
"resolutions": {
"angular": "~1.3.0"
"qrcode-generator": "0.0.1"
}
}

View File

@ -1,9 +0,0 @@
Development
* Just run:
```
$ sh chrome/build.sh
```
* The ZIP file is *chrome/copay-chrome-extension.zip*

View File

@ -1,64 +0,0 @@
#! /bin/bash
# Description: This script compiles and copy the needed files to later package the application for Chrome
OpenColor="\033["
Red="1;31m"
Yellow="1;33m"
Green="1;32m"
CloseColor="\033[0m"
# Check function OK
checkOK() {
if [ $? != 0 ]; then
echo "${OpenColor}${Red}* ERROR. Exiting...${CloseColor}"
exit 1
fi
}
# Configs
BUILDDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APPDIR="$BUILDDIR/copay-chrome-extension"
ZIPFILE="copay-chrome-extension.zip"
VERSION=`cut -d '"' -f2 $BUILDDIR/../../version.js|head -n 1`
# Move to the build directory
cd $BUILDDIR
# Create/Clean temp dir
echo "${OpenColor}${Green}* Checking temp dir...${CloseColor}"
if [ -d $APPDIR ]; then
rm -rf $APPDIR
fi
mkdir -p $APPDIR
# Re-compile copayBundle.js
echo "${OpenColor}${Green}* Generating copay bundle...${CloseColor}"
grunt prod
checkOK
# Copy all chrome-extension files
echo "${OpenColor}${Green}* Copying all chrome-extension files...${CloseColor}"
sed "s/APP_VERSION/$VERSION/g" manifest.json > $APPDIR/manifest.json
checkOK
INCLUDE=`cat ../include`
cd $BUILDDIR/../..
LIBS=`cat index.html |grep -o -E 'src="([^"#]+)"' | cut -d'"' -f2|grep lib`
echo "LIBS: $LIBS"
CMD="rsync -rLRv --exclude-from $BUILDDIR/../exclude $INCLUDE $LIBS $APPDIR"
echo $CMD
$CMD
checkOK
# Zipping chrome-extension
echo "${OpenColor}${Green}* Zipping all chrome-extension files...${CloseColor}"
cd $BUILDDIR
rm $ZIPFILE
zip -qr $ZIPFILE "`basename $APPDIR`"
checkOK
echo "${OpenColor}${Yellow}\nThe Chrome Extension is ready at $BUILDDIR/copay-chrome-extension.zip${CloseColor}"

View File

@ -1,8 +0,0 @@
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', {
'bounds': {
'width': 1200,
'height': 800
}
});
});

View File

@ -1,19 +0,0 @@
{
"manifest_version": 2,
"name": "Copay",
"description": "A secure Bitcoin wallet for friends and companies",
"version": "APP_VERSION",
"permissions": [
"storage",
"notifications",
"videoCapture"
],
"app": {
"background": {
"scripts": ["initial.js"]
}
},
"icons": {
"128": "img/icons/icon.png"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,19 +0,0 @@
lib/socket.io
lib/*/test
lib/*/demo
lib/sjcl/
lib/angular/angular.js
lib/moment/lang
lib/moment/min/*lang*
lib/moment/moment.js
lib/angular/angular.min.js.gzip
lib/bitcore/node_modules
lib/bitcore/.git
lib/bitcore/docs
lib/bitcore/lib
lib/bitcore/examples
lib/bitcore/coverage
lib/bitcore/build
.git
tests
.*

View File

@ -1,16 +0,0 @@
css
font
img
js
sound
views
config.js
init.js
initial.js
version.js
index.html
popup.html
lib/angular/angular-csp.css
lib/angular/angular.min.js.map
lib/angular-route/angular-route.min.js.map
lib/angular-touch/angular-touch.min.js.map

View File

@ -1,96 +0,0 @@
'use strict';
var defaultConfig = {
// DEFAULT network (livenet or testnet)
networkName: 'livenet',
logLevel: 'info',
// wallet limits
limits: {
totalCopayers: 6,
mPlusN: 100,
},
// network layer config
network: {
testnet: {
url: 'https://test-insight.bitpay.com:443',
transports: ['polling'],
},
livenet: {
url: 'https://insight.bitpay.com:443',
transports: ['polling'],
},
},
// wallet default config
wallet: {
requiredCopayers: 2,
totalCopayers: 3,
spendUnconfirmed: true,
reconnectDelay: 5000,
idleDurationMin: 4,
settings: {
unitName: 'bits',
unitToSatoshi: 100,
unitDecimals: 2,
alternativeName: 'US Dollar',
alternativeIsoCode: 'USD',
}
},
// local encryption/security config
passphraseConfig: {
iterations: 5000,
storageSalt: 'mjuBtGybi/4=',
},
rates: {
url: 'https://insight.bitpay.com:443/api/rates',
},
verbose: 1,
plugins: {
//LocalStorage: true,
// EncryptedLocalStorage: true,
//GoogleDrive: true,
//InsightStorage: true
EncryptedInsightStorage: true,
},
// This can be changed on the UX > Settings > Insight livenet
EncryptedInsightStorage: {
url: 'https://insight.bitpay.com:443/api/email',
//url: 'http://localhost:3001/api/email'
// This KDF parameters are for the passphrase for Insight authentication
// Are not related to encryption itself.
//
// WARN: Changing this parameters would prevent accesing previously created profiles.
iterations: 1000,
salt: 'jBbYTj8zTrOt6V',
},
minPasswordStrength: 4,
/*
GoogleDrive: {
home: 'copay',
// This clientId was generated at:
// https://console.developers.google.com/project
// To run Copay with Google Drive at your domain you need
// to generata your own Id.
// for localhost:3001 you can use you can:
//
clientId: '232630733383-a35gcnovnkgka94394i88gq60vtjb4af.apps.googleusercontent.com',
// for copay.io:
// clientId: '1036948132229-biqm3b8sirik9lt5rtvjo9kjjpotn4ac.apps.googleusercontent.com',
},
*/
};
if (typeof module !== 'undefined')
module.exports = defaultConfig;

View File

@ -1,26 +0,0 @@
// core
module.exports.PublicKeyRing = require('./js/models/PublicKeyRing');
module.exports.TxProposal = require('./js/models/TxProposal');
module.exports.TxProposals = require('./js/models/TxProposals');
module.exports.PrivateKey = require('./js/models/PrivateKey');
module.exports.HDPath = require('./js/models/HDPath');
module.exports.HDParams = require('./js/models/HDParams');
module.exports.Async = require('./js/models/Async');
module.exports.Insight = require('./js/models/Insight');
module.exports.RateService = require('./js/models/RateService');
module.exports.Identity = require('./js/models/Identity');
module.exports.Wallet = require('./js/models/Wallet');
module.exports.Compatibility = require('./js/models/Compatibility');
module.exports.PluginManager = require('./js/models/PluginManager');
module.exports.crypto = require('./js/util/crypto');
module.exports.logger = require('./js/util/log');
module.exports.csv = require('./js/util/csv');
module.exports.version = require('./version').version;
module.exports.commitHash = require('./version').commitHash;
module.exports.defaultConfig = require('./config');

View File

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="v0.9.7" android:windowSoftInputMode="adjustPan" package="com.bitpay.copay" xmlns:android="http://schemas.android.com/apk/res/android">
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="v0.10.0" android:windowSoftInputMode="adjustPan" package="com.bitpay.copay" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:hardwareAccelerated="true" android:icon="@drawable/copay" android:label="@string/app_name">
@ -9,7 +9,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:clearTaskOnLaunch="true" android:configChanges="orientation|keyboardHidden" android:exported="false" android:name="com.google.zxing.client.android.CaptureActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:windowSoftInputMode="stateAlwaysHidden">
<activity android:clearTaskOnLaunch="true" android:configChanges="orientation|screenSize|keyboardHidden" android:exported="false" android:name="com.google.zxing.client.android.CaptureActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="com.phonegap.plugins.barcodescanner.SCAN" />
<category android:name="android.intent.category.DEFAULT" />

View File

@ -15,7 +15,6 @@ checkOK() {
# Configs
BUILDDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PROJECT="$BUILDDIR/project"
VERSION=`cut -d '"' -f2 $BUILDDIR/../version.js`
CURRENT_OS=$1
@ -115,27 +114,39 @@ if [ ! -d $PROJECT ]; then
cordova plugin add hu.dpal.phonegap.plugins.spinnerdialog
checkOK
cordova plugin add org.apache.cordova.dialogs
checkOK
cordova plugin add org.apache.cordova.network-information
checkOK
cordova plugin add org.apache.cordova.console
checkok
cordova plugin add hu.dpal.phonegap.plugins.uniquedeviceid
checkok
fi
if $DBGJS
then
echo "${OpenColor}${Green}* Generating copay bundle (debug js)...${CloseColor}"
cd $BUILDDIR/..
grunt dist-mobile-dbg
grunt
checkOK
else
echo "${OpenColor}${Green}* Generating copay bundle...${CloseColor}"
cd $BUILDDIR/..
grunt dist-mobile
grunt prod
checkOK
fi
echo "${OpenColor}${Green}* Copying files...${CloseColor}"
cd $BUILDDIR/..
cp -af dist/web/** $PROJECT/www
cp -af public/** $PROJECT/www
checkOK
sed "s/<\!-- PLACEHOLDER: CORDOVA SRIPT -->/<script type='text\/javascript' charset='utf-8' src='cordova.js'><\/script>/g" index.html > $PROJECT/www/index.html
sed "s/<\!-- PLACEHOLDER: CORDOVA SRIPT -->/<script type='text\/javascript' charset='utf-8' src='cordova.js'><\/script>/g" public/index.html > $PROJECT/www/index.html
checkOK
cd $BUILDDIR

View File

@ -10,6 +10,7 @@
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
<Capability Name="ID_CAP_NETWORKING" />
<Capability Name="ID_CAP_ISV_CAMERA" />
<Capability Name="ID_CAP_IDENTITY_DEVICE" />
</Capabilities>
<Tasks>
<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />

View File

@ -1,594 +0,0 @@
/*
* Foundation Icons v 3.0
* Made by ZURB 2013 http://zurb.com/playground/foundation-icon-fonts-3
* MIT License
*/
@font-face {
font-family: "foundation-icons";
src: url("../font/foundation-icons.eot");
src: url("../font/foundation-icons.eot?#iefix") format("embedded-opentype"),
url("../font/foundation-icons.woff") format("woff"),
url("../font/foundation-icons.ttf") format("truetype"),
url("../font/foundation-icons.svg#fontcustom") format("svg");
font-weight: normal;
font-style: normal;
}
.fi-address-book:before,
.fi-alert:before,
.fi-align-center:before,
.fi-align-justify:before,
.fi-align-left:before,
.fi-align-right:before,
.fi-anchor:before,
.fi-annotate:before,
.fi-archive:before,
.fi-arrow-down:before,
.fi-arrow-left:before,
.fi-arrow-right:before,
.fi-arrow-up:before,
.fi-arrows-compress:before,
.fi-arrows-expand:before,
.fi-arrows-in:before,
.fi-arrows-out:before,
.fi-asl:before,
.fi-asterisk:before,
.fi-at-sign:before,
.fi-background-color:before,
.fi-battery-empty:before,
.fi-battery-full:before,
.fi-battery-half:before,
.fi-bitcoin-circle:before,
.fi-bitcoin:before,
.fi-blind:before,
.fi-bluetooth:before,
.fi-bold:before,
.fi-book-bookmark:before,
.fi-book:before,
.fi-bookmark:before,
.fi-braille:before,
.fi-burst-new:before,
.fi-burst-sale:before,
.fi-burst:before,
.fi-calendar:before,
.fi-camera:before,
.fi-check:before,
.fi-checkbox:before,
.fi-clipboard-notes:before,
.fi-clipboard-pencil:before,
.fi-clipboard:before,
.fi-clock:before,
.fi-closed-caption:before,
.fi-cloud:before,
.fi-comment-minus:before,
.fi-comment-quotes:before,
.fi-comment-video:before,
.fi-comment:before,
.fi-comments:before,
.fi-compass:before,
.fi-contrast:before,
.fi-credit-card:before,
.fi-crop:before,
.fi-crown:before,
.fi-css3:before,
.fi-database:before,
.fi-die-five:before,
.fi-die-four:before,
.fi-die-one:before,
.fi-die-six:before,
.fi-die-three:before,
.fi-die-two:before,
.fi-dislike:before,
.fi-dollar-bill:before,
.fi-dollar:before,
.fi-download:before,
.fi-eject:before,
.fi-elevator:before,
.fi-euro:before,
.fi-eye:before,
.fi-fast-forward:before,
.fi-female-symbol:before,
.fi-female:before,
.fi-filter:before,
.fi-first-aid:before,
.fi-flag:before,
.fi-folder-add:before,
.fi-folder-lock:before,
.fi-folder:before,
.fi-foot:before,
.fi-foundation:before,
.fi-graph-bar:before,
.fi-graph-horizontal:before,
.fi-graph-pie:before,
.fi-graph-trend:before,
.fi-guide-dog:before,
.fi-hearing-aid:before,
.fi-heart:before,
.fi-home:before,
.fi-html5:before,
.fi-indent-less:before,
.fi-indent-more:before,
.fi-info:before,
.fi-italic:before,
.fi-key:before,
.fi-laptop:before,
.fi-layout:before,
.fi-lightbulb:before,
.fi-like:before,
.fi-link:before,
.fi-list-bullet:before,
.fi-list-number:before,
.fi-list-thumbnails:before,
.fi-list:before,
.fi-lock:before,
.fi-loop:before,
.fi-magnifying-glass:before,
.fi-mail:before,
.fi-male-female:before,
.fi-male-symbol:before,
.fi-male:before,
.fi-map:before,
.fi-marker:before,
.fi-megaphone:before,
.fi-microphone:before,
.fi-minus-circle:before,
.fi-minus:before,
.fi-mobile-signal:before,
.fi-mobile:before,
.fi-monitor:before,
.fi-mountains:before,
.fi-music:before,
.fi-next:before,
.fi-no-dogs:before,
.fi-no-smoking:before,
.fi-page-add:before,
.fi-page-copy:before,
.fi-page-csv:before,
.fi-page-delete:before,
.fi-page-doc:before,
.fi-page-edit:before,
.fi-page-export-csv:before,
.fi-page-export-doc:before,
.fi-page-export-pdf:before,
.fi-page-export:before,
.fi-page-filled:before,
.fi-page-multiple:before,
.fi-page-pdf:before,
.fi-page-remove:before,
.fi-page-search:before,
.fi-page:before,
.fi-paint-bucket:before,
.fi-paperclip:before,
.fi-pause:before,
.fi-paw:before,
.fi-paypal:before,
.fi-pencil:before,
.fi-photo:before,
.fi-play-circle:before,
.fi-play-video:before,
.fi-play:before,
.fi-plus:before,
.fi-pound:before,
.fi-power:before,
.fi-previous:before,
.fi-price-tag:before,
.fi-pricetag-multiple:before,
.fi-print:before,
.fi-prohibited:before,
.fi-projection-screen:before,
.fi-puzzle:before,
.fi-quote:before,
.fi-record:before,
.fi-refresh:before,
.fi-results-demographics:before,
.fi-results:before,
.fi-rewind-ten:before,
.fi-rewind:before,
.fi-rss:before,
.fi-safety-cone:before,
.fi-save:before,
.fi-share:before,
.fi-sheriff-badge:before,
.fi-shield:before,
.fi-shopping-bag:before,
.fi-shopping-cart:before,
.fi-shuffle:before,
.fi-skull:before,
.fi-social-500px:before,
.fi-social-adobe:before,
.fi-social-amazon:before,
.fi-social-android:before,
.fi-social-apple:before,
.fi-social-behance:before,
.fi-social-bing:before,
.fi-social-blogger:before,
.fi-social-delicious:before,
.fi-social-designer-news:before,
.fi-social-deviant-art:before,
.fi-social-digg:before,
.fi-social-dribbble:before,
.fi-social-drive:before,
.fi-social-dropbox:before,
.fi-social-evernote:before,
.fi-social-facebook:before,
.fi-social-flickr:before,
.fi-social-forrst:before,
.fi-social-foursquare:before,
.fi-social-game-center:before,
.fi-social-github:before,
.fi-social-google-plus:before,
.fi-social-hacker-news:before,
.fi-social-hi5:before,
.fi-social-instagram:before,
.fi-social-joomla:before,
.fi-social-lastfm:before,
.fi-social-linkedin:before,
.fi-social-medium:before,
.fi-social-myspace:before,
.fi-social-orkut:before,
.fi-social-path:before,
.fi-social-picasa:before,
.fi-social-pinterest:before,
.fi-social-rdio:before,
.fi-social-reddit:before,
.fi-social-skillshare:before,
.fi-social-skype:before,
.fi-social-smashing-mag:before,
.fi-social-snapchat:before,
.fi-social-spotify:before,
.fi-social-squidoo:before,
.fi-social-stack-overflow:before,
.fi-social-steam:before,
.fi-social-stumbleupon:before,
.fi-social-treehouse:before,
.fi-social-tumblr:before,
.fi-social-twitter:before,
.fi-social-vimeo:before,
.fi-social-windows:before,
.fi-social-xbox:before,
.fi-social-yahoo:before,
.fi-social-yelp:before,
.fi-social-youtube:before,
.fi-social-zerply:before,
.fi-social-zurb:before,
.fi-sound:before,
.fi-star:before,
.fi-stop:before,
.fi-strikethrough:before,
.fi-subscript:before,
.fi-superscript:before,
.fi-tablet-landscape:before,
.fi-tablet-portrait:before,
.fi-target-two:before,
.fi-target:before,
.fi-telephone-accessible:before,
.fi-telephone:before,
.fi-text-color:before,
.fi-thumbnails:before,
.fi-ticket:before,
.fi-torso-business:before,
.fi-torso-female:before,
.fi-torso:before,
.fi-torsos-all-female:before,
.fi-torsos-all:before,
.fi-torsos-female-male:before,
.fi-torsos-male-female:before,
.fi-torsos:before,
.fi-trash:before,
.fi-trees:before,
.fi-trophy:before,
.fi-underline:before,
.fi-universal-access:before,
.fi-unlink:before,
.fi-unlock:before,
.fi-upload-cloud:before,
.fi-upload:before,
.fi-usb:before,
.fi-video:before,
.fi-volume-none:before,
.fi-volume-strike:before,
.fi-volume:before,
.fi-web:before,
.fi-wheelchair:before,
.fi-widget:before,
.fi-wrench:before,
.fi-x-circle:before,
.fi-x:before,
.fi-yen:before,
.fi-zoom-in:before,
.fi-zoom-out:before {
font-family: "foundation-icons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
display: inline-block;
text-decoration: inherit;
}
.fi-address-book:before { content: "\f100"; }
.fi-alert:before { content: "\f101"; }
.fi-align-center:before { content: "\f102"; }
.fi-align-justify:before { content: "\f103"; }
.fi-align-left:before { content: "\f104"; }
.fi-align-right:before { content: "\f105"; }
.fi-anchor:before { content: "\f106"; }
.fi-annotate:before { content: "\f107"; }
.fi-archive:before { content: "\f108"; }
.fi-arrow-down:before { content: "\f109"; }
.fi-arrow-left:before { content: "\f10a"; }
.fi-arrow-right:before { content: "\f10b"; }
.fi-arrow-up:before { content: "\f10c"; }
.fi-arrows-compress:before { content: "\f10d"; }
.fi-arrows-expand:before { content: "\f10e"; }
.fi-arrows-in:before { content: "\f10f"; }
.fi-arrows-out:before { content: "\f110"; }
.fi-asl:before { content: "\f111"; }
.fi-asterisk:before { content: "\f112"; }
.fi-at-sign:before { content: "\f113"; }
.fi-background-color:before { content: "\f114"; }
.fi-battery-empty:before { content: "\f115"; }
.fi-battery-full:before { content: "\f116"; }
.fi-battery-half:before { content: "\f117"; }
.fi-bitcoin-circle:before { content: "\f118"; }
.fi-bitcoin:before { content: "\f119"; }
.fi-blind:before { content: "\f11a"; }
.fi-bluetooth:before { content: "\f11b"; }
.fi-bold:before { content: "\f11c"; }
.fi-book-bookmark:before { content: "\f11d"; }
.fi-book:before { content: "\f11e"; }
.fi-bookmark:before { content: "\f11f"; }
.fi-braille:before { content: "\f120"; }
.fi-burst-new:before { content: "\f121"; }
.fi-burst-sale:before { content: "\f122"; }
.fi-burst:before { content: "\f123"; }
.fi-calendar:before { content: "\f124"; }
.fi-camera:before { content: "\f125"; }
.fi-check:before { content: "\f126"; }
.fi-checkbox:before { content: "\f127"; }
.fi-clipboard-notes:before { content: "\f128"; }
.fi-clipboard-pencil:before { content: "\f129"; }
.fi-clipboard:before { content: "\f12a"; }
.fi-clock:before { content: "\f12b"; }
.fi-closed-caption:before { content: "\f12c"; }
.fi-cloud:before { content: "\f12d"; }
.fi-comment-minus:before { content: "\f12e"; }
.fi-comment-quotes:before { content: "\f12f"; }
.fi-comment-video:before { content: "\f130"; }
.fi-comment:before { content: "\f131"; }
.fi-comments:before { content: "\f132"; }
.fi-compass:before { content: "\f133"; }
.fi-contrast:before { content: "\f134"; }
.fi-credit-card:before { content: "\f135"; }
.fi-crop:before { content: "\f136"; }
.fi-crown:before { content: "\f137"; }
.fi-css3:before { content: "\f138"; }
.fi-database:before { content: "\f139"; }
.fi-die-five:before { content: "\f13a"; }
.fi-die-four:before { content: "\f13b"; }
.fi-die-one:before { content: "\f13c"; }
.fi-die-six:before { content: "\f13d"; }
.fi-die-three:before { content: "\f13e"; }
.fi-die-two:before { content: "\f13f"; }
.fi-dislike:before { content: "\f140"; }
.fi-dollar-bill:before { content: "\f141"; }
.fi-dollar:before { content: "\f142"; }
.fi-download:before { content: "\f143"; }
.fi-eject:before { content: "\f144"; }
.fi-elevator:before { content: "\f145"; }
.fi-euro:before { content: "\f146"; }
.fi-eye:before { content: "\f147"; }
.fi-fast-forward:before { content: "\f148"; }
.fi-female-symbol:before { content: "\f149"; }
.fi-female:before { content: "\f14a"; }
.fi-filter:before { content: "\f14b"; }
.fi-first-aid:before { content: "\f14c"; }
.fi-flag:before { content: "\f14d"; }
.fi-folder-add:before { content: "\f14e"; }
.fi-folder-lock:before { content: "\f14f"; }
.fi-folder:before { content: "\f150"; }
.fi-foot:before { content: "\f151"; }
.fi-foundation:before { content: "\f152"; }
.fi-graph-bar:before { content: "\f153"; }
.fi-graph-horizontal:before { content: "\f154"; }
.fi-graph-pie:before { content: "\f155"; }
.fi-graph-trend:before { content: "\f156"; }
.fi-guide-dog:before { content: "\f157"; }
.fi-hearing-aid:before { content: "\f158"; }
.fi-heart:before { content: "\f159"; }
.fi-home:before { content: "\f15a"; }
.fi-html5:before { content: "\f15b"; }
.fi-indent-less:before { content: "\f15c"; }
.fi-indent-more:before { content: "\f15d"; }
.fi-info:before { content: "\f15e"; }
.fi-italic:before { content: "\f15f"; }
.fi-key:before { content: "\f160"; }
.fi-laptop:before { content: "\f161"; }
.fi-layout:before { content: "\f162"; }
.fi-lightbulb:before { content: "\f163"; }
.fi-like:before { content: "\f164"; }
.fi-link:before { content: "\f165"; }
.fi-list-bullet:before { content: "\f166"; }
.fi-list-number:before { content: "\f167"; }
.fi-list-thumbnails:before { content: "\f168"; }
.fi-list:before { content: "\f169"; }
.fi-lock:before { content: "\f16a"; }
.fi-loop:before { content: "\f16b"; }
.fi-magnifying-glass:before { content: "\f16c"; }
.fi-mail:before { content: "\f16d"; }
.fi-male-female:before { content: "\f16e"; }
.fi-male-symbol:before { content: "\f16f"; }
.fi-male:before { content: "\f170"; }
.fi-map:before { content: "\f171"; }
.fi-marker:before { content: "\f172"; }
.fi-megaphone:before { content: "\f173"; }
.fi-microphone:before { content: "\f174"; }
.fi-minus-circle:before { content: "\f175"; }
.fi-minus:before { content: "\f176"; }
.fi-mobile-signal:before { content: "\f177"; }
.fi-mobile:before { content: "\f178"; }
.fi-monitor:before { content: "\f179"; }
.fi-mountains:before { content: "\f17a"; }
.fi-music:before { content: "\f17b"; }
.fi-next:before { content: "\f17c"; }
.fi-no-dogs:before { content: "\f17d"; }
.fi-no-smoking:before { content: "\f17e"; }
.fi-page-add:before { content: "\f17f"; }
.fi-page-copy:before { content: "\f180"; }
.fi-page-csv:before { content: "\f181"; }
.fi-page-delete:before { content: "\f182"; }
.fi-page-doc:before { content: "\f183"; }
.fi-page-edit:before { content: "\f184"; }
.fi-page-export-csv:before { content: "\f185"; }
.fi-page-export-doc:before { content: "\f186"; }
.fi-page-export-pdf:before { content: "\f187"; }
.fi-page-export:before { content: "\f188"; }
.fi-page-filled:before { content: "\f189"; }
.fi-page-multiple:before { content: "\f18a"; }
.fi-page-pdf:before { content: "\f18b"; }
.fi-page-remove:before { content: "\f18c"; }
.fi-page-search:before { content: "\f18d"; }
.fi-page:before { content: "\f18e"; }
.fi-paint-bucket:before { content: "\f18f"; }
.fi-paperclip:before { content: "\f190"; }
.fi-pause:before { content: "\f191"; }
.fi-paw:before { content: "\f192"; }
.fi-paypal:before { content: "\f193"; }
.fi-pencil:before { content: "\f194"; }
.fi-photo:before { content: "\f195"; }
.fi-play-circle:before { content: "\f196"; }
.fi-play-video:before { content: "\f197"; }
.fi-play:before { content: "\f198"; }
.fi-plus:before { content: "\f199"; }
.fi-pound:before { content: "\f19a"; }
.fi-power:before { content: "\f19b"; }
.fi-previous:before { content: "\f19c"; }
.fi-price-tag:before { content: "\f19d"; }
.fi-pricetag-multiple:before { content: "\f19e"; }
.fi-print:before { content: "\f19f"; }
.fi-prohibited:before { content: "\f1a0"; }
.fi-projection-screen:before { content: "\f1a1"; }
.fi-puzzle:before { content: "\f1a2"; }
.fi-quote:before { content: "\f1a3"; }
.fi-record:before { content: "\f1a4"; }
.fi-refresh:before { content: "\f1a5"; }
.fi-results-demographics:before { content: "\f1a6"; }
.fi-results:before { content: "\f1a7"; }
.fi-rewind-ten:before { content: "\f1a8"; }
.fi-rewind:before { content: "\f1a9"; }
.fi-rss:before { content: "\f1aa"; }
.fi-safety-cone:before { content: "\f1ab"; }
.fi-save:before { content: "\f1ac"; }
.fi-share:before { content: "\f1ad"; }
.fi-sheriff-badge:before { content: "\f1ae"; }
.fi-shield:before { content: "\f1af"; }
.fi-shopping-bag:before { content: "\f1b0"; }
.fi-shopping-cart:before { content: "\f1b1"; }
.fi-shuffle:before { content: "\f1b2"; }
.fi-skull:before { content: "\f1b3"; }
.fi-social-500px:before { content: "\f1b4"; }
.fi-social-adobe:before { content: "\f1b5"; }
.fi-social-amazon:before { content: "\f1b6"; }
.fi-social-android:before { content: "\f1b7"; }
.fi-social-apple:before { content: "\f1b8"; }
.fi-social-behance:before { content: "\f1b9"; }
.fi-social-bing:before { content: "\f1ba"; }
.fi-social-blogger:before { content: "\f1bb"; }
.fi-social-delicious:before { content: "\f1bc"; }
.fi-social-designer-news:before { content: "\f1bd"; }
.fi-social-deviant-art:before { content: "\f1be"; }
.fi-social-digg:before { content: "\f1bf"; }
.fi-social-dribbble:before { content: "\f1c0"; }
.fi-social-drive:before { content: "\f1c1"; }
.fi-social-dropbox:before { content: "\f1c2"; }
.fi-social-evernote:before { content: "\f1c3"; }
.fi-social-facebook:before { content: "\f1c4"; }
.fi-social-flickr:before { content: "\f1c5"; }
.fi-social-forrst:before { content: "\f1c6"; }
.fi-social-foursquare:before { content: "\f1c7"; }
.fi-social-game-center:before { content: "\f1c8"; }
.fi-social-github:before { content: "\f1c9"; }
.fi-social-google-plus:before { content: "\f1ca"; }
.fi-social-hacker-news:before { content: "\f1cb"; }
.fi-social-hi5:before { content: "\f1cc"; }
.fi-social-instagram:before { content: "\f1cd"; }
.fi-social-joomla:before { content: "\f1ce"; }
.fi-social-lastfm:before { content: "\f1cf"; }
.fi-social-linkedin:before { content: "\f1d0"; }
.fi-social-medium:before { content: "\f1d1"; }
.fi-social-myspace:before { content: "\f1d2"; }
.fi-social-orkut:before { content: "\f1d3"; }
.fi-social-path:before { content: "\f1d4"; }
.fi-social-picasa:before { content: "\f1d5"; }
.fi-social-pinterest:before { content: "\f1d6"; }
.fi-social-rdio:before { content: "\f1d7"; }
.fi-social-reddit:before { content: "\f1d8"; }
.fi-social-skillshare:before { content: "\f1d9"; }
.fi-social-skype:before { content: "\f1da"; }
.fi-social-smashing-mag:before { content: "\f1db"; }
.fi-social-snapchat:before { content: "\f1dc"; }
.fi-social-spotify:before { content: "\f1dd"; }
.fi-social-squidoo:before { content: "\f1de"; }
.fi-social-stack-overflow:before { content: "\f1df"; }
.fi-social-steam:before { content: "\f1e0"; }
.fi-social-stumbleupon:before { content: "\f1e1"; }
.fi-social-treehouse:before { content: "\f1e2"; }
.fi-social-tumblr:before { content: "\f1e3"; }
.fi-social-twitter:before { content: "\f1e4"; }
.fi-social-vimeo:before { content: "\f1e5"; }
.fi-social-windows:before { content: "\f1e6"; }
.fi-social-xbox:before { content: "\f1e7"; }
.fi-social-yahoo:before { content: "\f1e8"; }
.fi-social-yelp:before { content: "\f1e9"; }
.fi-social-youtube:before { content: "\f1ea"; }
.fi-social-zerply:before { content: "\f1eb"; }
.fi-social-zurb:before { content: "\f1ec"; }
.fi-sound:before { content: "\f1ed"; }
.fi-star:before { content: "\f1ee"; }
.fi-stop:before { content: "\f1ef"; }
.fi-strikethrough:before { content: "\f1f0"; }
.fi-subscript:before { content: "\f1f1"; }
.fi-superscript:before { content: "\f1f2"; }
.fi-tablet-landscape:before { content: "\f1f3"; }
.fi-tablet-portrait:before { content: "\f1f4"; }
.fi-target-two:before { content: "\f1f5"; }
.fi-target:before { content: "\f1f6"; }
.fi-telephone-accessible:before { content: "\f1f7"; }
.fi-telephone:before { content: "\f1f8"; }
.fi-text-color:before { content: "\f1f9"; }
.fi-thumbnails:before { content: "\f1fa"; }
.fi-ticket:before { content: "\f1fb"; }
.fi-torso-business:before { content: "\f1fc"; }
.fi-torso-female:before { content: "\f1fd"; }
.fi-torso:before { content: "\f1fe"; }
.fi-torsos-all-female:before { content: "\f1ff"; }
.fi-torsos-all:before { content: "\f200"; }
.fi-torsos-female-male:before { content: "\f201"; }
.fi-torsos-male-female:before { content: "\f202"; }
.fi-torsos:before { content: "\f203"; }
.fi-trash:before { content: "\f204"; }
.fi-trees:before { content: "\f205"; }
.fi-trophy:before { content: "\f206"; }
.fi-underline:before { content: "\f207"; }
.fi-universal-access:before { content: "\f208"; }
.fi-unlink:before { content: "\f209"; }
.fi-unlock:before { content: "\f20a"; }
.fi-upload-cloud:before { content: "\f20b"; }
.fi-upload:before { content: "\f20c"; }
.fi-usb:before { content: "\f20d"; }
.fi-video:before { content: "\f20e"; }
.fi-volume-none:before { content: "\f20f"; }
.fi-volume-strike:before { content: "\f210"; }
.fi-volume:before { content: "\f211"; }
.fi-web:before { content: "\f212"; }
.fi-wheelchair:before { content: "\f213"; }
.fi-widget:before { content: "\f214"; }
.fi-wrench:before { content: "\f215"; }
.fi-x-circle:before { content: "\f216"; }
.fi-x:before { content: "\f217"; }
.fi-yen:before { content: "\f218"; }
.fi-zoom-in:before { content: "\f219"; }
.fi-zoom-out:before { content: "\f21a"; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,181 +0,0 @@
.head .menu a.dropdown:hover,
.head .menu a.dropdown.hover {
border-bottom: 1px solid #fff;
}
.head .menu ul.hover {
background: #FFFFFF;
}
.head .menu ul li a:hover {
background-color: #F8F8FB;
color: #2C3E50;
}
.col3 a.selected:hover {
background-color: #213140;
color: #fff;
}
.col3 a:hover {
background-color: #16A085;
color: #fff;
}
a:hover {
color: #2980b9;
}
a.button-setup.add-wallet:hover {
opacity: 1;
}
a.button-setup:hover {
color: #666;
border-color: #666;
}
.createProfile .button-setup a:hover, .home .button-setup a:hover, .settings .button-setup a:hover, .import-profile .button-setup a:hover {
background: #3C4E60;
}
.name-wallet i:hover {
color: #fff;
}
ul.pagination li.current a:hover, ul.pagination li.current a:focus {
background: #16A085;
}
.button.outline.light-gray:hover {
background: rgba(206,213,220,0.40);
color: #4B6178;
}
.button.outline.dark-gray:hover {
background: rgba(255,255,255,.1);
color: #fff;
}
button.secondary:hover,
button.secondary:focus,
.button.secondary:hover,
.button.secondary:focus {
background-color: #2980B9;
color: #fff;
}
button.primary:hover,
button.primary:focus,
.button.primary:hover,
.button.primary:focus {
background-color: #16A085;
color: #fff;
}
button.warning:hover,
button.warning:focus,
.button.warning:hover,
.button.warning:focus {
background-color: #82251A;
color: #e6e6e6;
}
button.white:hover,
button.white:focus,
.button.white:hover,
.button.white:focus {
background-color: #E0E0E0;
color: #2C3E50;
}
button.black:hover,
button.black:focus,
.button.black:hover,
.button.black:focus {
background-color: #213140;
color: #fff;
}
button.gray:hover,
button.gray:focus,
.button.gray:hover,
.button.gray:focus {
background-color: #E0E5E5;
color: #2C3E50;
}
.wallet-selection.wallets li:hover {
background-color: #3C4E60;
}
.wallet-selection.wallets a.wallet-item:hover,
.side-nav.wallets a.wallet-item:hover {
color: #7A8C9E;
line-height: 20px;
}
.side-nav li.nav-item:hover {
background-color: #3C4E60;
overflow: hidden;
}
.fi-trash.text-gray:hover {
color: #CA5649;
}
a:hover .photo-container {
background: #34495E;
color: #fff;
}
.side-nav li.active:hover a {
background-color: #F8F8FB;
}
.side-nav li:hover a {
background-color: #3C4E60;
}
a.text-gray:hover {color: #2C3E50;}
a.text-black:hover {color: #213140;}
a.text-primary:hover {color: #50E3C2;}
a.text-secondary:hover {color: #4A90E2;}
a.text-white:hover {color: #ccc;}
a.text-warning:hover {color: #FD7262;}
.w-popup-menu li:hover{
background-color: #34B191;
}
.w-popup-menu li:hover .w-popup-icon {
color: transparent;
}
.w-popup-menu li:hover .w-popup-main, .w-popup-menu li:hover .w-popup-sub {
color: #FFFFFF;
}
.createProfile a.text-gray:hover,
.home a.text-gray:hover,
.import-profile a.text-gray:hover,
.settings a.text-gray:hover {
color: #fff;
}
.tabs dd>a:hover {
background: #1C2B39;
}
.tabs dd.active a:hover {
background: transparent;
}
.reveal-modal .close-reveal-modal:hover, dialog .close-reveal-modal:hover {
background: #ddd;
}
.reveal-modal .close-reveal-modal:hover, dialog .close-reveal-modal:hover {
background-color: #7A8C9E;
color: #fff;
}

View File

@ -1,532 +0,0 @@
/*
*
* Copay mobile CSS
*
*/
@media (max-width: 1024px) {
/* disabling text selection */
body {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
input {
-webkit-user-select: auto !important;
-khtml-user-select: auto !important;
-moz-user-select: auto !important;
-ms-user-select: auto !important;
user-select: auto !important;
}
* {
-webkit-user-drag: none;
-moz-user-drag: none;
-ms-user-drag: none;
user-drag: none;
}
/* END disabling text selection */
.inner-wrap {
-webkit-transition-duration: 250ms;
transition-duration: 250ms;
}
body {
overflow: hidden;
-ms-content-zooming: none;
}
.loading-screen {
background-color: #2C3E50;
}
.logo-setup {
margin: 0 0 1rem 0;
}
.sidebar {
display: none;
}
.page, .main, .setup-page {
height: 100%;
}
.main {
margin-left: 0;
padding: 60px 0 80px 0;
}
/* Fix IE 10 */
.extra-margin-bottom {
display: block
height: 75px
overflow: hidden
clear: both
}
.main {
height: 99%
overflow: auto
}
/* Fix IE 11 */
_:-ms-fullscreen, :root .extra-margin-bottom {
display: block;
height: 75px;
overflow: hidden;
clear: both;
}
_:-ms-fullscreen, :root .main {
height: 99%;
overflow: auto;
}
/* Fix Firefox */
@-moz-document url-prefix() {
.extra-margin-bottom {
display: block;
height: 75px;
overflow: hidden;
clear: both;
}
}
.tab-bar {
display: block;
position: fixed;
width: 100%;
z-index: 5;
background: #2C3E50;
}
.bottom-bar {
display: block;
position: fixed;
bottom: 0;
width: 100%;
z-index: 5;
background: #2C3E50;
}
.home, .settings, .createProfile, .import-profile {
overflow: hidden;
padding: 1rem 0;
}
.modal-mobile {
padding: 20px .5rem;
}
.reveal-modal {
padding: 0;
}
.reveal-modal .close-reveal-modal, dialog .close-reveal-modal {
padding: 0.8rem;
position: relative;
background: #E4E8EC;
top: 0;
right: 0;
line-height: 0;
color: #7A8C9E;
border-radius: 3px;
}
header {
background-color: #2C3E50;
height: 120px;
width: 100%;
line-height: 110%;
padding: 1rem;
}
header .photo-container {
width: 45px;
height: 45px;
margin-bottom: 5px;
}
header h1 {
color: #fff;
text-align: center;
}
.amount {
background-color: #F1F3F5;
width: 100%;
text-align: center;
padding: 2.4rem 1rem;
margin-bottom: 15px;
}
.scroll-section {
position: absolute;
top: 120px;
overflow-y: auto;
}
.col2 {
width: 180px;
}
.col2 a.wallet-item {
padding: 0.15rem 0 0.3rem;
}
.col3 a {
height: 45px;
padding: 12px 5px;
}
.status {
bottom: 65px;
left: 0;
}
.right-off-canvas-menu {
background-color: #213140 ;
}
.left-off-canvas-menu {
background: #E4E8EC;
line-height: 24px;
}
.off-canvas-wrap,.inner-wrap{
height:100%;
}
.home-wallet .avatar-wallet {
padding: 1.7rem;
width: 90px;
height: 90px;
position: absolute;
top: -43px;
font-size: 35px;
border: 3px solid #fff;
}
.home-wallet .wallet-info {
margin-left: 100px;
}
.copayers {
position: relative;
padding: 0;
overflow-y: none;
}
ul.copayer-list img {
width: 30px;
height: 30px;
}
.hide-tab-bar {
display: none;
}
.tab-bar h1 {
font-weight: 700;
text-align: center;
text-transform: uppercase;
font-size: 14px;
}
ul.off-canvas-list li a {
font-size: 12px;
vertical-align: middle;
font-weight: 100;
border-bottom: transparent;
padding: 0.66667rem 1rem;
color: #7A8C9E;
border-top: 1px solid rgba(255,255,255,0.25);
-moz-box-shadow: none;
box-shadow: none;
}
ul.off-canvas-list li a i {
vertical-align: middle;
}
ul.off-canvas-list li a.wallet-item {
border: none;
-moz-box-shadow: none;
box-shadow: none;
}
ul.off-canvas-list li a i {
opacity: 0.6;
}
.buttons-sidebar {
color: #4B6178;
}
.buttons-sidebar .col1 i {
background-color: #fff;
color: #4B6178;
}
.bottombar-item a {
color: #7A8C9E;
padding: 0.5rem 0;
display: block;
border-bottom: 3px solid transparent;
}
.bottombar-item a.active {
color: #E4E8EC;
background-color: #213140;
border-bottom: 3px solid #1ABC9C;
}
.box-founds {
background-color: #213140;
}
.left-small {
border-right: none;
}
.right-small {
border-left: none;
}
.right-small a, .left-small a {
color: white;
}
.panel.last-transactions {
margin-bottom: 3.25rem;
}
.addresses .list-addr contact {
margin-left: 0;
font-size: 14px;
}
a.missing-copayers {
bottom: -34px;
text-align: center;
padding: .7rem;
width: 100%;
}
.button, button {
padding: 1rem 1.2rem 1.0625rem;
}
.box-setup {
margin-bottom: 50px;
}
.footer-setup {
margin-bottom: 50px;
}
.label {
font-size: 80%;
padding: 0.15rem 0.2rem;
}
.sidebar-mobile-wallets {
background: #E4E8EC;
}
.sidebar-mobile-wallets .avatar-wallet {
margin-top: 5px;
}
.sidebar-mobile-wallets li {
overflow: hidden;
padding:.6rem 0.4rem;
border-bottom: 1px solid #DDE2E7;
}
.sidebar-mobile-wallets li.nav-item.selected {
background-color: #fff;
}
/*
* Remove all vendors hover / shadow / fade
*/
.tooltip {
display: none !important;
}
.move-right .exit-off-canvas,
.move-left .exit-off-canvas {
box-shadow: none;
}
ul.off-canvas-list li a:hover {
background: none;
}
.side-nav li a:not(.button) {
padding: 0;
}
a, button, .button, input, textarea, select, .reveal-modal {
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
-webkit-tap-highlight-color:rgba(0,0,0,0);
}
.modal.fade {
opacity: 1;
}
.modal.fade .modal-dialog, .modal.in .modal-dialog, .reveal-modal-bg {
-webkit-transition: none !important;
transition: none !important;
-webkit-transform: none !important;
transform: none !important;
}
.move-right .close-menu {
cursor: pointer;
box-shadow: none;
display: block;
position: absolute;
background: rgba(255,255,255,.2);
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1002;
}
/*******************************************/
.pin {
margin: 0 auto;
width: 35%;
text-align: center;
overflow: hidden;
}
.pin-box {
color: #fff;
font-size: 14px;
width: 25%;
float: left;
}
.pin-numbers {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
height: 72%;
margin-bottom: 1.5%;
}
.pin-button-bar {
height: 25%;
}
a.pin-button {
margin: 2.5%;
display: inline-block;
color: #CED5DC;
font-size: 210%;
font-weight: 100;
border: 1px solid #4B6178;
border-radius: 100%;
width: 70px;
padding-top: 1rem;
height: 70px;
}
a.pin-button:active {
color: #fff;
background-color: #3E5367;
}
.icon-circle, .icon-circle-active {
color: #1ABC9C;
}
.tab-bar {
position: relative;
}
}
@media (max-width: 640px) {
.tab-bar {
position: absolute;
}
.modal-mobile {
padding: 60px 0.5rem;
}
.tx-comment {
border-top: 1px solid #eee;
padding-top: 10px;
margin-top: 10px;
}
.reveal-modal {
border: none;
}
.reveal-modal-bg {
position: absolute;
height: 0;
width: 0;
background: none;
display: none;
top: 0;
left: 0;
}
/* notifications */
.dr-notification {
width: 100%;
border-radius: 0;
box-shadow: none;
border-bottom: 1.5px solid #D6DBE0;
}
.dr-notification-container {
width: 100%;
}
.dr-notification-container.top {
top: 2.813rem;
}
.dr-notification-wrapper {
width: 100%;
margin: 0;
}
.dr-notification-close-btn {
font-size: 20px;
}
.dr-notification-image {
font-size: 30px;
}
.dr-notification-text {
font-size: 12px;
line-height: 120%;
}
}

Binary file not shown.

View File

@ -1,970 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-8-23: Created.
-->
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
Created by FontForge 20120731 at Fri Aug 23 09:25:55 2013
By Jordan Humphreys
Created by Jordan Humphreys with FontForge 2.0 (http://fontforge.sf.net)
</metadata>
<defs>
<font id="fontcustom" horiz-adv-x="369" >
<font-face
font-family="fontcustom"
font-weight="500"
font-stretch="normal"
units-per-em="512"
panose-1="2 0 6 3 0 0 0 0 0 0"
ascent="448"
descent="-64"
bbox="-0.584459 -64.25 512.25 448.25"
underline-thickness="25.6"
underline-position="-51.2"
unicode-range="U+F100-F21A"
/>
<missing-glyph />
<glyph glyph-name="uniF100" unicode="&#xf100;" horiz-adv-x="340"
d="M330 287v0h-24v-30h24c6 0 10 -4 10 -10v-30c0 -6 -4 -10 -10 -10h-24v-29h24c6 0 10 -5 10 -11v-30c0 -6 -4 -10 -10 -10h-24v-29h24c6 0 10 -5 10 -11v-30c0 -6 -4 -10 -10 -10h-24v-9c0 -9 -7 -16 -16 -16h-274c-9 0 -16 7 -16 16v308c0 9 7 16 16 16h274
c9 0 16 -7 16 -16v-9h24c6 0 10 -4 10 -10v-30c0 -6 -4 -10 -10 -10zM234 122v0v44c0 4 -3 8 -6 10l-55 26c13 8 21 24 21 42c0 26 -18 48 -41 48s-41 -22 -41 -48c0 -19 9 -34 22 -42l-56 -26c-3 -2 -5 -6 -5 -10v-44c0 -6 4 -11 9 -11h142c5 0 10 5 10 11z" />
<glyph glyph-name="uniF101" unicode="&#xf101;" horiz-adv-x="425"
d="M423 31c1 -2 2 -4 2 -7c0 -10 -9 -18 -19 -18v0h-388v0c-10 0 -18 8 -18 18c0 4 1 9 4 12v0l191 331h1c3 6 8 11 16 11c7 0 13 -3 16 -9l193 -334c0 -1 1 -1 1 -2l1 -2v0zM213 40c14 0 26 12 26 27s-12 26 -26 26c-15 0 -27 -11 -27 -26s12 -27 27 -27zM239 273v0v0v0v0
c0 6 -5 10 -11 10v0h-32v0c-5 0 -10 -4 -10 -10v-1v-144v0v0c0 -6 5 -11 11 -11h31v0v0c6 0 11 5 11 11v0v0v145z" />
<glyph glyph-name="uniF102" unicode="&#xf102;" horiz-adv-x="355"
d="M337 370c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM312 235c0 -10 -8 -17 -18 -17v0h-233c-10 0 -18 7 -18 17v16c0 10 8 17 18 17h233v0c10 0 18 -7 18 -17v0v-16v0zM320 64c10 0 17 -7 17 -17v0v-16v0
c0 -10 -7 -17 -17 -17v0h-285c-10 0 -18 7 -18 17v16c0 10 8 17 18 17h285v0zM294 149v0v-16v0c0 -10 -7 -17 -17 -17v0v0h-199c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h199v0v0c10 0 17 -7 17 -17z" />
<glyph glyph-name="uniF103" unicode="&#xf103;" horiz-adv-x="355"
d="M337 369c10 0 18 -7 18 -17v-16c0 -10 -8 -18 -18 -18h-320c-10 0 -17 8 -17 18v16c0 10 7 17 17 17h320zM337 268c10 0 18 -7 18 -17v-16c0 -10 -8 -18 -18 -18h-320c-10 0 -17 8 -17 18v16c0 10 7 17 17 17h320zM337 167c10 0 18 -8 18 -18v-16c0 -10 -8 -17 -18 -17
h-320c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h320zM337 66c10 0 18 -8 18 -18v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h320z" />
<glyph glyph-name="uniF104" unicode="&#xf104;" horiz-adv-x="355"
d="M337 370c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM17 218c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h234v0c10 0 18 -8 18 -18v0v-16v0c0 -10 -8 -17 -18 -17v0h-234zM302 64c10 0 18 -7 18 -17v0v-16v0
c0 -10 -8 -17 -18 -17v0h-285c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h285v0zM17 116c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h199v0v0c10 0 18 -7 18 -17v0v-16v0c0 -10 -8 -17 -18 -17v0v0h-199z" />
<glyph glyph-name="uniF105" unicode="&#xf105;" horiz-adv-x="355"
d="M337 370c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM337 268c10 0 18 -7 18 -17v0v-16v0c0 -10 -8 -17 -18 -17v0h-233c-10 0 -18 7 -18 17v16c0 10 8 17 18 17h233v0zM337 64c10 0 18 -7 18 -17v0v-16v0
c0 -10 -8 -17 -18 -17v0h-285c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h285v0v0zM355 149v0v-16v0c0 -10 -8 -17 -18 -17v0v0h-199c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h199v0v0c10 0 18 -7 18 -17z" />
<glyph glyph-name="uniF106" unicode="&#xf106;" horiz-adv-x="393"
d="M392 104c1 -1 1 -3 1 -4c0 -4 -4 -8 -8 -8h-21c-33 -58 -95 -97 -167 -97s-134 39 -167 97h-22c-4 0 -8 4 -8 8c0 2 1 4 2 5l47 82c1 3 4 5 7 5s6 -2 7 -4v0l48 -84v0c1 -1 2 -3 2 -4c0 -4 -5 -8 -9 -8h-12c20 -22 48 -38 79 -44v150h-46c-4 0 -8 4 -8 8v0v35v0
c0 4 4 8 8 8v0h46v27c-20 10 -34 30 -34 54c0 33 27 59 60 59s59 -26 59 -59c0 -24 -14 -44 -34 -54v-27h47v0c4 0 8 -4 8 -8v0v-35v0c0 -4 -4 -8 -8 -8h-47v-150c31 6 59 22 79 44h-12c-4 0 -8 4 -8 8c0 2 1 4 2 5l46 82c1 3 5 5 8 5s6 -2 7 -4v0l48 -84v0zM197 296
c18 0 33 16 33 34s-15 33 -33 33s-34 -15 -34 -33s16 -34 34 -34z" />
<glyph glyph-name="uniF107" unicode="&#xf107;" horiz-adv-x="388"
d="M360 98c17 -9 28 -27 28 -47c0 -29 -24 -54 -53 -54c-22 0 -42 14 -50 34h-182c-8 -20 -28 -34 -50 -34c-29 0 -53 25 -53 54c0 20 11 38 28 47v188c-17 9 -28 27 -28 47c0 29 24 54 53 54c18 0 34 -10 44 -24h194c10 14 26 24 44 24c29 0 53 -25 53 -54
c0 -20 -11 -38 -28 -47v-188zM79 98c7 -4 13 -10 18 -16h195c5 6 10 12 17 16v188c-11 6 -18 15 -23 26h-184c-5 -11 -12 -20 -23 -26v-188z" />
<glyph glyph-name="uniF108" unicode="&#xf108;" horiz-adv-x="401"
d="M401 279v0v-247v0c0 -12 -9 -21 -21 -21h-1h-357h-1c-12 0 -21 9 -21 21v0v247v1c0 5 2 10 5 14v0l42 72v0c2 4 6 7 11 7v0v0h284v0h1c6 0 12 -4 13 -10l40 -69v-1c3 -4 5 -8 5 -13v-1zM269 154c1 2 2 4 1 6s-4 3 -6 3h-30v81c0 3 -3 6 -6 6h-55c-3 0 -6 -3 -6 -6v-81
h-30c-2 0 -5 -1 -6 -3s0 -4 1 -6l64 -90c1 -2 3 -2 5 -2v0c2 0 4 0 5 2zM39 301h323l-27 47h-269z" />
<glyph glyph-name="uniF109" unicode="&#xf109;" horiz-adv-x="292"
d="M2 188c-3 4 -3 9 -1 13s7 7 12 7h62v167c0 7 6 13 13 13h116c7 0 12 -6 12 -13v-167h63c5 0 9 -3 11 -7s2 -9 -1 -13l-132 -187c-2 -3 -7 -5 -11 -5v0c-4 0 -8 2 -10 5z" />
<glyph glyph-name="uniF10A" unicode="&#xf10a;" horiz-adv-x="393"
d="M192 335c4 3 9 3 13 1s7 -6 7 -11v-62h168c7 0 13 -6 13 -13v-116c0 -7 -6 -13 -13 -13h-168v-62c0 -5 -3 -9 -7 -11s-9 -2 -13 1l-187 132c-3 2 -5 7 -5 11v0c0 4 2 8 5 10z" />
<glyph glyph-name="uniF10B" unicode="&#xf10b;" horiz-adv-x="393"
d="M201 49c-4 -3 -10 -3 -14 -1s-7 6 -7 11v62h-167c-7 0 -13 6 -13 13v116c0 7 6 13 13 13h167v62c0 5 3 9 7 11s10 2 14 -1l186 -132c3 -2 6 -7 6 -11v0c0 -4 -3 -8 -6 -10z" />
<glyph glyph-name="uniF10C" unicode="&#xf10c;" horiz-adv-x="292"
d="M289 196c3 -4 3 -9 1 -13s-6 -7 -11 -7h-63v-167c0 -7 -5 -13 -12 -13h-116c-7 0 -13 6 -13 13v167h-62c-5 0 -10 3 -12 7s-2 9 1 13l133 187c2 3 6 5 10 5v0c4 0 9 -2 11 -5z" />
<glyph glyph-name="uniF10D" unicode="&#xf10d;" horiz-adv-x="512"
d="M201 -5c-1 -3 -4 -6 -7 -7s-7 0 -9 2l-30 31l-83 -82c-4 -4 -9 -4 -13 0l-56 56c-4 4 -4 9 0 13l82 83l-31 30c-2 2 -3 6 -2 9s4 6 7 7l157 26c3 0 6 0 8 -2v0c2 -2 3 -5 3 -8zM311 389c1 3 4 6 7 7s7 0 9 -2l30 -31l83 82c4 4 9 4 13 0l56 -56c4 -4 4 -9 0 -13l-82 -83
l31 -30c2 -2 3 -6 2 -9s-4 -6 -7 -7l-157 -26c-3 0 -6 0 -8 2v0c-2 2 -3 5 -3 8z" />
<glyph glyph-name="uniF10E" unicode="&#xf10e;" horiz-adv-x="512"
d="M26 104c1 3 3 6 6 7s7 0 9 -2l31 -31l83 83c4 4 8 4 12 0l57 -57c4 -4 4 -9 0 -13l-82 -82l30 -31c2 -2 4 -6 3 -9s-4 -5 -7 -6l-158 -27c-3 0 -5 1 -7 3v0c-2 2 -3 4 -3 7zM486 280c-1 -3 -3 -6 -6 -7s-7 0 -9 2l-31 31l-83 -83c-4 -4 -8 -4 -12 0l-57 57
c-4 4 -4 9 0 13l82 82l-30 31c-2 2 -4 6 -3 9s4 5 7 6l158 27c3 0 5 -1 7 -3v0c2 -2 3 -4 3 -7z" />
<glyph glyph-name="uniF10F" unicode="&#xf10f;" horiz-adv-x="512"
d="M184 -10c-1 -3 -2 -5 -5 -6s-7 0 -9 2l-28 28l-76 -76c-3 -3 -8 -3 -11 0l-53 53c-3 3 -3 8 0 11l76 76l-28 28c-2 2 -3 6 -2 9s3 4 6 5l145 25c3 0 5 -1 7 -3v0c2 -2 2 -4 2 -7zM328 394c1 3 2 5 5 6s7 0 9 -2l28 -28l76 76c3 3 8 3 11 0l53 -53c3 -3 3 -8 0 -11
l-76 -76l28 -28c2 -2 3 -6 2 -9s-3 -4 -6 -5l-145 -25c-3 0 -5 1 -7 3v0c-2 2 -2 4 -2 7zM458 120c3 -1 5 -2 6 -5s0 -7 -2 -9l-28 -28l76 -76c3 -3 3 -8 0 -11l-53 -53c-3 -3 -8 -3 -11 0l-76 76l-28 -28c-2 -2 -6 -3 -9 -2s-4 3 -5 6l-25 145c0 3 1 5 3 7v0c2 2 4 2 7 2z
M54 264c-3 1 -5 2 -6 5s0 7 2 9l28 28l-76 76c-3 3 -3 8 0 11l53 53c3 3 8 3 11 0l76 -76l28 28c2 2 6 3 9 2s4 -3 5 -6l25 -145c0 -3 -1 -5 -3 -7v0c-2 -2 -4 -2 -7 -2z" />
<glyph glyph-name="uniF110" unicode="&#xf110;" horiz-adv-x="512"
d="M24 90c1 3 3 6 6 7s6 0 8 -2l28 -28l76 75c3 3 9 3 12 0l52 -52c3 -3 3 -9 0 -12l-76 -75l28 -29c2 -2 3 -5 2 -8s-3 -4 -6 -5l-144 -25c-3 0 -6 0 -8 2v0c-2 2 -2 5 -2 8zM488 294c-1 -3 -3 -6 -6 -7s-6 0 -8 2l-28 28l-76 -75c-3 -3 -9 -3 -12 0l-52 52c-3 3 -3 9 0 12
l76 75l-28 29c-2 2 -3 5 -2 8s3 4 6 5l144 25c3 0 6 0 8 -2v0c2 -2 2 -5 2 -8zM358 -40c-3 1 -6 3 -7 6s0 6 2 8l28 28l-75 76c-3 3 -3 9 0 12l52 52c3 3 9 3 12 0l75 -76l29 28c2 2 5 3 8 2s4 -3 5 -6l25 -144c0 -3 0 -6 -2 -8v0c-2 -2 -5 -2 -8 -2zM154 424
c3 -1 6 -3 7 -6s0 -6 -2 -8l-28 -28l75 -76c3 -3 3 -9 0 -12l-52 -52c-3 -3 -9 -3 -12 0l-75 76l-29 -28c-2 -2 -5 -3 -8 -2s-4 3 -5 6l-25 144c0 3 0 6 2 8v0c2 2 5 2 8 2z" />
<glyph glyph-name="uniF111" unicode="&#xf111;" horiz-adv-x="440"
d="M94 315c2 1 3 2 5 3c17 15 37 27 59 34c11 3 23 4 35 5c2 0 6 -2 7 -4s0 -6 -2 -8c-3 -3 -6 -5 -10 -6c-15 -5 -29 -9 -44 -14c-3 -1 -6 -6 -9 -8c-7 -6 -14 -10 -21 -16l-3 -3v-1c4 2 7 3 11 4c12 4 23 9 35 11c10 2 21 -1 32 -2c2 0 5 -2 7 -4c8 -6 15 -13 23 -19
c3 -2 3 -4 1 -7c-5 -7 -11 -8 -18 -4c-6 3 -10 7 -15 11c-3 2 -5 4 -9 3c-7 -1 -15 -1 -22 -2c-3 0 -5 -1 -7 -2c-10 -7 -20 -15 -30 -22c-2 -1 -3 -4 -3 -7c1 0 2 0 3 1c8 5 17 6 26 7c3 0 6 1 9 1c12 2 20 -3 29 -10c7 -5 14 -10 21 -16c4 -3 6 -8 6 -13
c0 -9 0 -18 -3 -27c0 -1 -1 -3 0 -3c6 -4 2 -9 1 -13c-3 -9 -7 -18 -10 -27c-3 -8 -9 -13 -18 -16c-21 -6 -41 -13 -62 -20c-8 -3 -17 -4 -26 -2c-17 4 -33 2 -49 -5c-7 -3 -15 -7 -23 -11c-9 13 -14 27 -17 41c-4 17 -4 35 -2 52c0 1 2 3 3 4c17 7 25 21 31 37
c7 19 9 40 21 57c13 19 23 39 40 55c8 8 16 18 23 27c3 4 5 4 8 -1s3 -11 -1 -16c-10 -13 -21 -26 -31 -39c-1 -1 -1 -2 -2 -4zM167 170c4 0 8 -1 10 3c4 9 11 16 18 22c2 2 2 3 1 5c-4 7 -6 14 -10 21c-1 2 -3 4 -5 5c-6 4 -12 8 -19 12c-2 1 -4 2 -6 1
c-5 -2 -10 -5 -15 -7c-4 -2 -9 -3 -13 -5c-11 -4 -14 -13 -17 -23c-2 -6 -1 -11 4 -16c6 -6 12 -13 17 -20c2 -2 3 -2 6 -1c10 3 19 5 29 3zM346 69c-3 -3 -7 -4 -10 -7c-15 -14 -34 -24 -53 -30c-11 -4 -23 -5 -35 -6c-7 -1 -10 7 -6 12c3 3 7 7 11 8c12 4 25 7 37 11
c5 2 9 5 13 8c8 6 16 13 24 19c1 1 2 2 2 4c-4 -2 -9 -4 -13 -6c-11 -4 -21 -9 -32 -10s-22 1 -33 2c-2 0 -5 2 -7 4c-7 5 -13 11 -20 16s-6 12 3 15c3 1 8 1 11 -1c6 -3 11 -8 17 -12c2 -1 4 -2 6 -2c8 0 15 1 22 2c3 0 7 1 10 3c9 7 19 14 28 21c2 1 2 4 3 7
c-12 -8 -26 -8 -39 -9c-9 -1 -16 1 -23 7c-9 7 -19 14 -28 21c-2 2 -4 5 -4 8c0 9 1 18 2 27c0 3 2 6 -1 9c-1 1 0 3 0 4c1 4 3 7 4 11c3 7 5 13 7 20c3 9 9 15 19 18c21 6 42 13 62 20c9 3 17 4 26 2c18 -5 35 -2 52 6c6 3 12 7 19 10c8 -9 12 -21 15 -32
c6 -20 6 -40 4 -61c0 -5 -4 -5 -7 -6c-10 -4 -17 -13 -21 -22c-5 -10 -8 -21 -11 -32c-5 -15 -10 -30 -19 -43c-7 -10 -13 -20 -20 -30c-6 -8 -13 -15 -19 -23l-21 -24c-4 -4 -5 -4 -8 1s-2 10 2 16c10 13 20 25 30 38c1 1 1 3 2 5c-1 0 -1 1 -1 1zM245 186
c3 -8 6 -16 10 -24c1 -2 2 -3 4 -4c6 -4 13 -8 19 -12c2 -1 4 -2 7 -1c8 3 15 7 23 10s14 6 17 14c2 4 3 9 4 13c1 5 1 9 -3 13c-7 7 -13 14 -19 21c-1 1 -3 1 -4 1c-11 -3 -22 -5 -33 -3c-2 0 -6 -1 -7 -3c-7 -8 -12 -17 -18 -25z" />
<glyph glyph-name="uniF112" unicode="&#xf112;" horiz-adv-x="343"
d="M338 140c4 -3 6 -7 4 -12v0v-2v0h-1l-28 -49v0c-3 -5 -9 -6 -14 -3c-1 0 -1 0 -2 1l-87 50v-103v0v0c0 -5 -4 -9 -9 -10v0h-58v0c-6 0 -10 4 -10 10v3v100l-89 -51v0v0c-4 -3 -10 -2 -13 2v0l-30 51v0c-3 5 -1 11 4 14c1 0 1 1 2 1l88 50l-90 51v1v0v0v0c-5 3 -7 8 -4 13
v0l29 49v0v1c3 5 9 7 14 4v0l89 -52v103v0c0 5 5 10 10 10v0h57v0v0c6 0 10 -4 10 -10v0v-103l90 51v0c5 3 10 2 13 -3v0l28 -49v0l1 -1c3 -5 1 -11 -4 -14v0l-89 -51l89 -51v0v-1z" />
<glyph glyph-name="uniF113" unicode="&#xf113;" horiz-adv-x="384"
d="M384 192v-9v0c0 -76 -46 -102 -85 -102c-27 0 -75 22 -78 39v3c-16 -22 -41 -36 -65 -36c-44 0 -70 31 -70 75c0 60 50 111 102 111c27 0 47 -13 56 -30l4 18v0c1 3 4 5 7 5h37c4 0 7 -2 7 -6l-1 -2h1l-22 -101c0 -2 -1 -8 -1 -11c0 -14 8 -21 17 -21c18 0 39 29 39 80
c-7 72 -67 128 -140 128c-78 0 -141 -63 -141 -141s63 -141 141 -141c19 0 37 3 53 10v0c1 0 2 1 3 1c2 0 4 -1 5 -2v0l34 -21v0c3 -1 4 -4 4 -7c0 -4 -2 -6 -5 -7c-28 -16 -60 -25 -94 -25c-106 0 -192 86 -192 192s86 192 192 192s192 -86 192 -192zM226 157l11 52
c-5 10 -16 23 -36 23c-36 0 -62 -32 -62 -65c0 -23 14 -40 37 -40c24 0 40 16 50 30z" />
<glyph glyph-name="uniF114" unicode="&#xf114;"
d="M122 53h133l17 -45h-167zM136 98l52 138l53 -138h-105zM333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-3l-106 270v0c-2 5 -7 9 -13 9h-45c-6 0 -11 -4 -13 -9v0l-106 -270h-11c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297z" />
<glyph glyph-name="uniF115" unicode="&#xf115;" horiz-adv-x="484"
d="M476 236c5 0 8 -4 8 -9v-62c0 -5 -3 -9 -8 -9h-40v-95v0v0c0 -5 -4 -9 -9 -9h-418c-5 0 -9 4 -9 9v0v0v262v0v0c0 5 4 9 9 9h418c5 0 9 -4 9 -9v0v0v-87h40zM385 103v177h-333v-177h333z" />
<glyph glyph-name="uniF116" unicode="&#xf116;" horiz-adv-x="484"
d="M476 236c5 0 8 -4 8 -9v-62c0 -5 -3 -9 -8 -9h-40v-95v0v0c0 -5 -4 -9 -9 -9h-418c-5 0 -9 4 -9 9v0v0v262v0v0c0 5 4 9 9 9h418c5 0 9 -4 9 -9v0v0v-87h40zM385 103v177h-333v-177h333zM78 128v129h281v-129h-281z" />
<glyph glyph-name="uniF117" unicode="&#xf117;" horiz-adv-x="484"
d="M476 236c5 0 8 -4 8 -9v-62c0 -5 -3 -9 -8 -9h-40v-95v0v0c0 -5 -4 -9 -9 -9h-418c-5 0 -9 4 -9 9v0v0v262v0v0c0 5 4 9 9 9h418c5 0 9 -4 9 -9v0v0v-87h40zM385 103v177h-333v-177h333zM276 255l-50 -126h-149v126h199z" />
<glyph glyph-name="uniF118" unicode="&#xf118;" horiz-adv-x="384"
d="M191 253c12 -3 50 -8 44 -33c-6 -24 -43 -12 -55 -9zM175 190c14 -4 60 -11 53 -38c-7 -26 -50 -13 -64 -9zM238 378c103 -26 166 -129 140 -232s-129 -166 -232 -140s-166 129 -140 232s129 166 232 140zM277 219c4 26 -16 40 -43 49l9 34l-21 6l-8 -34
c-6 1 -11 3 -17 4l8 34l-21 5l-9 -34c-5 1 -9 2 -13 3v0l-29 7l-6 -22l16 -4c9 -2 9 -9 9 -13l-9 -39c1 0 1 -1 2 -1c-1 0 -1 1 -2 1l-14 -55c-1 -3 -4 -6 -10 -5l-15 3l-11 -24l28 -6c5 -1 10 -3 15 -4l-9 -35l21 -6l9 35c6 -2 12 -3 17 -4l-9 -35l21 -5l9 35
c36 -7 63 -4 74 28c9 26 0 41 -19 51c14 3 24 12 27 31z" />
<glyph glyph-name="uniF119" unicode="&#xf119;" horiz-adv-x="260"
d="M213 205c31 -7 51 -26 47 -67c-5 -51 -44 -65 -98 -68v-47v0v0c0 -4 -2 -7 -6 -7v0v0v0h-20v0v0c-4 0 -6 3 -6 7v0v46c-8 0 -17 1 -26 1v-47v0v0c0 -4 -2 -7 -6 -7v0v0v0h-20v0v0c-4 0 -6 3 -6 7v0v47h-23h-42v0c-3 0 -6 4 -6 7v0v0l5 27h1c1 3 3 5 6 5v0v0h23
c9 0 12 7 13 11v85v0v61c-1 7 -6 14 -19 14h-24v0v0c-4 0 -6 2 -6 6v22c0 4 2 6 6 6v0h45v0h21v47v0v0c0 4 2 7 6 7v0v0v0v0h20v0v0c4 0 6 -3 6 -7v0v-46c9 0 17 1 26 1v45v0v0c0 4 2 7 6 7v0v0v0v0h20v0v0c4 0 6 -3 6 -7v0v-47c42 -4 75 -16 79 -54c3 -28 -9 -45 -28 -55z
M105 277v-64c18 0 76 -5 76 32c0 38 -58 32 -76 32zM105 109c22 0 91 -5 91 35c0 42 -69 36 -91 36v-71z" />
<glyph glyph-name="uniF11A" unicode="&#xf11a;" horiz-adv-x="342"
d="M91 347c0 24 12 36 36 36s37 -12 37 -36s-13 -37 -37 -37s-36 13 -36 37zM341 15c1 -1 1 -2 1 -3c0 -4 -2 -6 -6 -6c-2 0 -4 1 -5 3v0v0v1l-107 184h-3c-3 0 -6 1 -8 2v0v0v1h-1l-35 20v0v0v0v0l-23 23v-76l45 -44v0l49 -85c3 -4 4 -8 4 -13c0 -6 -2 -11 -6 -15
s-9 -6 -15 -6c-8 0 -15 4 -19 11v0l-47 81l-37 37l-41 -72v0l-49 -49c-4 -5 -10 -8 -17 -8c-6 0 -11 2 -15 6s-6 9 -6 15s2 12 7 16v0l45 45l36 62v0v96l-19 -18v-52v0c0 -4 -1 -8 -4 -11s-7 -4 -11 -4c-3 0 -6 1 -8 2s-5 4 -6 6s-2 4 -2 7v0v62h1h-1c0 1 1 2 2 3v0l54 55
c7 8 17 11 27 11c12 0 21 -4 28 -13l47 -47l31 -18c6 -3 9 -7 9 -14c0 -3 0 -6 -2 -9l107 -186v0z" />
<glyph glyph-name="uniF11B" unicode="&#xf11b;" horiz-adv-x="239"
d="M231 120c5 -4 8 -10 8 -17c0 -5 -3 -10 -6 -14v0l-1 -1v0l-102 -102v0c-4 -4 -10 -7 -16 -7c-12 0 -21 9 -21 21v0v0v1v0v124l-55 -55c-4 -5 -9 -7 -16 -7c-12 0 -22 10 -22 22c0 6 2 11 6 15v0v0v0l87 86v11l-86 86c-4 4 -7 9 -7 15c0 12 10 22 22 22c6 0 12 -3 16 -7
l55 -55v119c-1 2 -1 4 -1 6c0 12 9 22 21 22c7 0 13 -3 17 -8l101 -101c5 -4 8 -9 8 -16c0 -5 -3 -10 -6 -14v0v0c-1 -1 -1 -2 -2 -3l-72 -71zM186 103l-50 51v-101zM136 230l50 50l-50 50v-100z" />
<glyph glyph-name="uniF11C" unicode="&#xf11c;" horiz-adv-x="242"
d="M186 197c31 -5 56 -35 56 -71c0 -44 -29 -79 -85 -79h-144c-7 0 -13 6 -13 13v264c0 7 6 13 13 13h140c55 0 83 -35 83 -74c0 -36 -23 -60 -50 -66zM62 283v-61h77c21 0 34 11 34 30c0 18 -13 31 -34 31h-77zM142 101c23 0 37 12 37 33c0 18 -13 33 -37 33h-80v-66h80z
" />
<glyph glyph-name="uniF11D" unicode="&#xf11d;" horiz-adv-x="328"
d="M328 334v-327v0c0 -5 -3 -8 -8 -8v0v0h-312v0c-4 0 -8 4 -8 8v0v0v0v1v65v303v1c0 5 3 8 8 8h153v-66v-84v-29c0 -2 2 -4 4 -4c1 0 2 0 3 1v0l29 30h1c1 1 1 1 2 1s2 0 3 -1v0l29 -29c1 -1 2 -2 3 -2c2 0 4 2 4 4v29v84v66h29v0h1c5 0 8 -3 8 -8v-319v0c0 -5 -3 -8 -8 -8
h-1v0h-242v-19c1 -4 4 -7 8 -7h261v0c5 0 8 4 8 9v0v309h17v0c4 0 8 -4 8 -8v0z" />
<glyph glyph-name="uniF11E" unicode="&#xf11e;" horiz-adv-x="328"
d="M328 334v-327v0c0 -5 -3 -8 -8 -8v0v0h-312v0c-4 0 -8 4 -8 8v0v0v0v1v65v303v1c0 5 3 8 8 8h260v0h1c5 0 8 -3 8 -8v-319v0c0 -5 -3 -8 -8 -8h-1v0h-242v-19c1 -4 4 -7 8 -7h261v0c5 0 8 4 8 9v0v309h17v0c4 0 8 -4 8 -8v0zM25 326v0v-64c0 -5 4 -8 9 -8h209v0
c5 0 8 3 8 8v0v64v0c0 5 -3 8 -8 8h-209c-5 0 -9 -3 -9 -8z" />
<glyph glyph-name="uniF11F" unicode="&#xf11f;" horiz-adv-x="218"
d="M203 381c9 0 15 -7 15 -16v-34v-235v-82c0 -6 -5 -11 -11 -11c-3 0 -7 2 -9 4l-81 82v0c-2 2 -5 3 -8 3s-5 -1 -7 -3v0l-83 -83v0c-2 -2 -5 -3 -8 -3c-6 0 -11 5 -11 11v82v235v34c0 9 6 16 15 16h188z" />
<glyph glyph-name="uniF120" unicode="&#xf120;" horiz-adv-x="265"
d="M0 325c0 24 12 36 36 36s35 -12 35 -36s-11 -35 -35 -35s-36 11 -36 35zM194 325c0 24 11 36 35 36s36 -12 36 -36s-12 -35 -36 -35s-35 11 -35 35zM0 192c0 24 12 36 36 36s35 -12 35 -36s-11 -36 -35 -36s-36 12 -36 36zM194 192c0 24 11 36 35 36s36 -12 36 -36
s-12 -36 -36 -36s-35 12 -35 36zM0 59c0 24 12 36 36 36s35 -12 35 -36s-11 -36 -35 -36s-36 12 -36 36zM194 59c0 24 11 36 35 36s36 -12 36 -36s-12 -36 -36 -36s-35 12 -35 36z" />
<glyph glyph-name="uniF121" unicode="&#xf121;" horiz-adv-x="395"
d="M395 192c0 -5 -3 -9 -6 -11v0l-48 -28l27 -46v0c2 -4 1 -9 -1 -13s-6 -6 -10 -6v0h-54v-55h-1c0 -4 -2 -8 -6 -10s-9 -3 -13 -1v0l-47 27l-27 -47v0c-2 -3 -6 -6 -11 -6s-9 3 -11 6v0l-27 46l-49 -28v0c-4 -2 -8 -1 -12 1s-7 6 -7 10v0v55h-55v0c-4 0 -8 3 -10 7
s-3 8 -1 12v0l27 48l-47 28v0c-3 2 -6 6 -6 11s3 9 6 11v0l48 28l-27 46v0c-2 4 -1 9 1 13s6 6 10 6v0h54v55v0c0 4 3 8 7 10s8 3 12 1v0l48 -27l27 47v0c2 3 6 6 11 6s9 -3 11 -6v0l27 -46l49 28v0c4 2 8 1 12 -1s7 -6 7 -10v0v-55h55v0c4 0 8 -3 10 -7s3 -8 1 -12v-1
l-27 -47l47 -28v0c3 -2 6 -6 6 -11zM165 134l12 7l-34 59l-12 -7l21 -37l-49 21l-13 -8l34 -59l13 8l-22 38zM189 148l42 24l-7 11l-29 -17l-8 13l29 17l-6 11l-29 -17l-7 13l29 17l-6 11l-42 -24zM286 204l13 7l-17 69l-14 -8l14 -49l-36 36l-9 -5l13 -49l-35 36l-14 -8
l51 -49l13 8l-13 46z" />
<glyph glyph-name="uniF122" unicode="&#xf122;" horiz-adv-x="395"
d="M167 163l-5 31l24 -20zM395 192c0 -5 -3 -9 -6 -11v0l-48 -28l27 -46v0c2 -4 1 -9 -1 -13s-6 -6 -10 -6v0h-54v-55h-1c0 -4 -2 -8 -6 -10s-9 -3 -13 -1v0l-47 27l-27 -47v0c-2 -3 -6 -6 -11 -6s-9 3 -11 6v0l-27 46l-49 -28v0c-4 -2 -8 -1 -12 1s-7 6 -7 10v0v55h-55v0
c-4 0 -8 3 -10 7s-3 8 -1 12v0l27 48l-47 28v0c-3 2 -6 6 -6 11s3 9 6 11v0l48 28l-27 46v0c-2 4 -1 9 1 13s6 6 10 6v0h54v55v0c0 4 3 8 7 10s8 3 12 1v0l48 -27l27 47v0c2 3 6 6 11 6s9 -3 11 -6v0l27 -46l49 28v0c4 2 8 1 12 -1s7 -6 7 -10v0v-55h55v0c4 0 8 -3 10 -7
s3 -8 1 -12v-1l-27 -47l47 -28v0c3 -2 6 -6 6 -11zM134 114c16 9 18 22 12 33c-13 22 -43 -4 -48 5c-2 4 0 8 5 11c6 3 14 5 21 3l1 14c-9 2 -18 0 -27 -5c-14 -8 -18 -21 -12 -31c13 -22 42 4 48 -6c2 -3 1 -8 -6 -12c-8 -5 -17 -5 -24 -3l-1 -14c9 -2 20 -2 31 5zM205 157
l14 8l-57 46l-15 -9l11 -72l14 8l-2 12l25 15zM224 168l38 22l-7 11l-25 -15l-27 48l-13 -7zM270 195l42 24l-6 11l-29 -17l-8 13l28 17l-6 11l-29 -17l-7 13l29 17l-6 11l-42 -24z" />
<glyph glyph-name="uniF123" unicode="&#xf123;" horiz-adv-x="395"
d="M395 192c0 -5 -3 -9 -6 -11v0l-48 -28l27 -46v0c2 -4 1 -9 -1 -13s-6 -6 -10 -6v0h-54v-55h-1c0 -4 -2 -8 -6 -10s-9 -3 -13 -1v0l-47 27l-27 -47v0c-2 -3 -6 -6 -11 -6s-9 3 -11 6v0l-27 46l-49 -28v0c-4 -2 -8 -1 -12 1s-7 6 -7 10v0v55h-55v0c-4 0 -8 3 -10 7
s-3 8 -1 12v0l27 48l-47 28v0c-3 2 -6 6 -6 11s3 9 6 11v0l48 28l-27 46v0c-2 4 -1 9 1 13s6 6 10 6v0h54v55v0c0 4 3 8 7 10s8 3 12 1v0l48 -27l27 47v0c2 3 6 6 11 6s9 -3 11 -6v0l27 -46l49 28v0c4 2 8 1 12 -1s7 -6 7 -10v0v-55h55v0c4 0 8 -3 10 -7s3 -8 1 -12v-1
l-27 -47l47 -28v0c3 -2 6 -6 6 -11z" />
<glyph glyph-name="uniF124" unicode="&#xf124;" horiz-adv-x="326"
d="M320 246c4 0 6 -3 6 -7v-225c0 -4 -2 -6 -6 -6h-314c-4 0 -6 2 -6 6v225c0 4 2 7 6 7h314zM109 55c34 0 56 18 56 44c0 18 -13 26 -25 31c14 7 21 17 21 31c0 18 -18 30 -44 30c-15 0 -27 -2 -37 -7c-1 -1 -2 -2 -2 -3l3 -22c0 -1 1 -2 2 -2h3c8 4 16 6 24 6
c15 0 15 -6 15 -9c0 -5 -3 -11 -24 -13c-2 0 -3 -1 -3 -3v-22c0 -2 1 -3 3 -3c25 -1 30 -7 30 -16c0 -8 -9 -13 -20 -13s-19 1 -29 5c-1 0 -2 1 -3 0s-1 -1 -1 -2l-3 -22c0 -1 1 -3 2 -4c9 -4 21 -6 32 -6zM245 61v0v125c0 2 -1 3 -3 3h-13h-2l-38 -19c-1 -1 -2 -2 -2 -3
l3 -22c0 -1 1 -3 2 -3c1 -1 2 0 3 0l17 7v-88c0 -2 1 -4 3 -4h27c2 0 3 2 3 4zM320 347c4 0 6 -2 6 -6v-66c0 -4 -2 -7 -6 -7h-314c-4 0 -6 3 -6 7v66c0 4 2 6 6 6h34v-16c0 -17 9 -34 36 -34s36 17 36 34v16h102v-16c0 -17 9 -34 36 -34s36 17 36 34v16h34zM76 318
c-11 0 -15 4 -15 13v16v16c0 9 4 13 15 13s15 -4 15 -13v-16v-16c0 -9 -4 -13 -15 -13zM250 318c-11 0 -15 4 -15 13v16v16c0 9 4 13 15 13s15 -4 15 -13v-16v-16c0 -9 -4 -13 -15 -13z" />
<glyph glyph-name="uniF125" unicode="&#xf125;" horiz-adv-x="415"
d="M159 175c0 32 17 49 49 49s48 -17 48 -49s-16 -48 -48 -48s-49 16 -49 48zM396 324c5 0 9 -1 13 -5s6 -9 6 -14v-259c0 -5 -2 -10 -6 -14s-8 -5 -13 -5v-1h-377v1c-5 0 -9 1 -13 5s-6 9 -6 14v259c0 5 2 10 6 14s8 5 13 5v0h85v15c0 5 2 9 6 13s8 6 13 6h168
c5 0 10 -2 14 -6s5 -8 5 -13v-15h86v0zM209 77c18 0 34 4 49 13s27 21 36 36s13 31 13 49c0 27 -10 51 -29 70s-42 29 -69 29s-51 -10 -70 -29s-29 -43 -29 -70s10 -50 29 -69s43 -29 70 -29zM389 248v0v51h-75v-51h75z" />
<glyph glyph-name="uniF126" unicode="&#xf126;" horiz-adv-x="397"
d="M393 293c5 -5 5 -13 0 -18l-250 -250c-2 -2 -6 -4 -9 -4v1l-1 -1c-3 0 -6 2 -8 4l-121 121c-2 2 -4 6 -4 9s2 7 4 9l66 66c5 5 12 5 17 0l47 -47l176 176c2 2 5 4 8 4s7 -2 9 -4z" />
<glyph glyph-name="uniF127" unicode="&#xf127;" horiz-adv-x="381"
d="M379 323c3 -3 3 -8 0 -11l-209 -209c-2 -2 -4 -3 -6 -3v0v0c-2 0 -4 1 -6 3l-81 80c-2 2 -3 4 -3 6s1 4 3 6l44 44c3 3 9 3 12 0l31 -31l159 160c2 2 4 2 6 2s4 0 6 -2zM277 173l51 52v-185v0c0 -14 -12 -26 -26 -26v0h-1v0v0h-275v0v0v0v0c-14 0 -26 12 -26 26v0v276v0
c0 14 12 26 26 26h1v0h234l-51 -51h-159v-226h226v108z" />
<glyph glyph-name="uniF128" unicode="&#xf128;" horiz-adv-x="315"
d="M315 360v0v-362v0v0c0 -15 -12 -27 -27 -27h-1h-259v0h-1c-15 0 -27 12 -27 27v0v0v362v0v0c0 15 12 27 27 27v0h75v17v1c0 5 3 8 8 8v0v0h95v0c5 0 8 -3 8 -8v0v0v-18h75v0c15 0 27 -12 27 -27v0v0zM264 22v0v314h-25v-16v0c0 -5 -5 -9 -10 -9h-143v0v0
c-5 0 -10 4 -10 9v1v15h-25v-314h213zM102 237v0v0v-13v0v0c0 -3 -3 -6 -6 -6h-1v0h-12v0c-3 0 -7 3 -7 6v0v0v13c0 3 4 7 7 7h12v-1l1 1c3 0 6 -4 6 -7zM239 237v0v0v-13v0v0c0 -3 -4 -6 -7 -6h-98v0c-3 0 -7 3 -7 6v0v0v13c0 3 4 7 7 7h98v0c3 0 7 -4 7 -7zM102 186v0v0
v-13v0v0c0 -3 -3 -6 -6 -6h-1v0h-12v0c-3 0 -7 3 -7 6v0v0v13c0 3 4 7 7 7h12v-1l1 1c3 0 6 -4 6 -7zM239 186v0v0v-13v0v0c0 -3 -4 -6 -7 -6h-98v0c-3 0 -7 3 -7 6v0v0v13c0 3 4 7 7 7h98v0c3 0 7 -4 7 -7zM102 135v0v0v-13v0v0c0 -3 -3 -6 -6 -6h-1v0h-12v0
c-3 0 -7 3 -7 6v0v0v13c0 3 4 6 7 6h12v0h1c3 0 6 -3 6 -6zM239 135v0v0v-13v0v0c0 -3 -4 -6 -7 -6h-98v0c-3 0 -7 3 -7 6v0v0v13c0 3 4 6 7 6h98v0c3 0 7 -3 7 -6z" />
<glyph glyph-name="uniF129" unicode="&#xf129;" horiz-adv-x="392"
d="M391 228c2 -2 2 -7 0 -9l-116 -116v0v0l-59 -16v0c-2 -1 -5 0 -7 2s-2 4 -1 6v0l16 59v0v0l115 116c2 2 7 2 9 0zM227 107l35 9l-25 26zM309 73c3 0 6 -3 6 -6v0v0v-69v0v0c0 -15 -12 -27 -27 -27h-1h-259v0h-1c-15 0 -27 12 -27 27v0v0v362v0v0c0 15 12 27 27 27v0h75
v17v1c0 5 3 8 8 8v0v0h95v0c4 0 8 -3 8 -8v0v0v-18h75v0c15 0 27 -12 27 -27v0v0v-68v0c0 -3 -3 -7 -6 -7v0h-39c-3 0 -6 4 -6 7v0v44h-25v-16v0c0 -5 -5 -9 -10 -9h-143v0v0c-5 0 -10 4 -10 9v1v15h-25v-314h213v45v0c0 3 3 6 6 6v0v0h39v0z" />
<glyph glyph-name="uniF12A" unicode="&#xf12a;" horiz-adv-x="315"
d="M315 360v0v-362v0v0c0 -15 -12 -27 -27 -27h-1h-259v0h-1c-15 0 -27 12 -27 27v0v0v362v0v0c0 15 12 27 27 27v0h75v17v1c0 5 3 8 8 8v0v0h95v0c5 0 8 -3 8 -8v0v0v-18h75v0c15 0 27 -12 27 -27v0v0zM264 22v0v314h-25v-16v0c0 -5 -5 -9 -10 -9h-143v0v0
c-5 0 -10 4 -10 9v1v15h-25v-314h213z" />
<glyph glyph-name="uniF12B" unicode="&#xf12b;" horiz-adv-x="384"
d="M192 333c-78 0 -141 -63 -141 -141s63 -141 141 -141s141 63 141 141s-63 141 -141 141zM192 384v0c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM290 263c4 -4 4 -10 0 -14l-91 -91c-2 -2 -4 -3 -7 -3v0c-3 0 -5 1 -7 3l-62 62
c-2 2 -3 4 -3 7s1 6 3 8l20 20c4 4 10 4 14 0l35 -36l64 64c4 4 10 4 14 0z" />
<glyph glyph-name="uniF12C" unicode="&#xf12c;" horiz-adv-x="342"
d="M333 300c5 -1 9 -6 9 -11v-94v-6v-94c0 -5 -4 -10 -9 -11l-160 -32h-4l-160 32c-5 1 -9 6 -9 11v94v6v94c0 5 4 10 9 11l160 32h4zM149 150c1 2 1 5 0 7s-3 4 -5 5l-19 8c-2 1 -4 1 -6 0s-4 -3 -5 -5c-2 -4 -7 -14 -17 -14c-14 0 -24 17 -24 41s10 41 24 41
c9 0 14 -7 17 -13c2 -4 8 -6 12 -4l18 8c2 1 4 3 5 5s0 4 -1 6c-11 23 -28 35 -51 35c-38 0 -64 -31 -64 -78s26 -78 64 -78c23 0 41 12 52 36zM308 150c1 2 1 5 0 7s-3 4 -5 5l-18 8c-2 1 -5 1 -7 0s-4 -3 -5 -5c-2 -4 -6 -14 -16 -14c-14 0 -25 17 -25 41s11 41 25 41
c9 0 14 -7 17 -13c2 -4 7 -6 11 -4l18 8c2 1 4 3 5 5s0 4 -1 6c-11 23 -27 35 -50 35c-38 0 -65 -31 -65 -78s27 -78 65 -78c23 0 40 12 51 36z" />
<glyph glyph-name="uniF12D" unicode="&#xf12d;" horiz-adv-x="473"
d="M387 206c46 6 86 -35 86 -84c0 -18 -6 -35 -16 -50c-3 -4 -7 -7 -12 -7h-414c-5 0 -10 3 -13 8c-12 20 -18 42 -18 66c0 66 49 121 110 121c8 0 15 -1 23 -3c27 39 70 62 115 62c65 0 121 -47 139 -113z" />
<glyph glyph-name="uniF12E" unicode="&#xf12e;" horiz-adv-x="470"
d="M302 166h92v-93v0c-2 -8 -9 -14 -17 -14h-225l-44 -44c-3 -5 -9 -8 -15 -8c-10 0 -17 7 -17 17v35h-59v0c-8 0 -15 6 -17 14v0v288v0c1 9 8 16 17 16v0h360c9 0 16 -7 17 -16v0v-91h-92c-5 0 -9 -4 -9 -9v0v-86v0c0 -5 4 -9 9 -9zM461 245c5 0 9 -4 9 -9v-36
c0 -5 -4 -8 -9 -8h-133c-5 0 -9 3 -9 8v36c0 5 4 9 9 9h133z" />
<glyph glyph-name="uniF12F" unicode="&#xf12f;" horiz-adv-x="394"
d="M394 361v0v-288v0c-2 -8 -9 -14 -17 -14h-225l-44 -44c-3 -5 -9 -8 -15 -8c-10 0 -17 7 -17 17v35h-59v0c-8 0 -15 6 -17 14v0v288v0c1 9 8 16 17 16v0h360c9 0 16 -7 17 -16zM87 189c14 0 26 12 26 26s-10 24 -23 24c-3 0 -5 0 -6 -1c3 12 13 25 24 31v0h1v0
c1 1 2 2 2 3s-1 2 -2 3v0l-14 9v0c-1 0 -1 1 -2 1s-1 -1 -2 -1v0c-21 -15 -34 -36 -34 -61c0 -22 14 -34 30 -34zM154 189c14 0 27 12 27 26s-10 24 -23 24c-3 0 -6 0 -7 -1c3 12 14 25 25 31v0v0v0c1 1 2 2 2 3s0 2 -1 3v0l-14 9v0c-1 0 -1 1 -2 1s-1 -1 -2 -1v0
c-21 -15 -34 -36 -34 -61c0 -22 13 -34 29 -34zM235 152c21 15 35 37 35 62c0 22 -14 34 -30 34c-14 0 -26 -13 -26 -27s9 -24 22 -24c3 0 6 0 7 1c-3 -12 -14 -25 -25 -31v0v0v0c-1 -1 -2 -2 -2 -3s1 -2 2 -3h-1l14 -9v0c1 0 2 -1 3 -1s0 1 1 1v0zM303 152
c21 15 34 37 34 62c0 22 -13 34 -29 34c-14 0 -27 -13 -27 -27s10 -24 23 -24c3 0 6 0 7 1c-3 -12 -14 -25 -25 -31v0v0v0c-1 -1 -2 -2 -2 -3s0 -2 1 -3v0l14 -9v0c1 0 1 -1 2 -1s1 1 2 1v0z" />
<glyph glyph-name="uniF130" unicode="&#xf130;" horiz-adv-x="394"
d="M394 361v0v-288v0c-2 -8 -9 -14 -17 -14h-225l-44 -44c-3 -5 -9 -8 -15 -8c-10 0 -17 7 -17 17v35h-59v0c-8 0 -15 6 -17 14v0v288v0c1 9 8 16 17 16v0h360c9 0 16 -7 17 -16zM305 155v124l-65 -30v28c0 7 -6 12 -13 12h-110c-7 0 -12 -5 -12 -12v-120c0 -7 5 -12 12 -12
h110c7 0 13 5 13 12v29z" />
<glyph glyph-name="uniF131" unicode="&#xf131;" horiz-adv-x="394"
d="M394 361v0v-288v0c-2 -8 -9 -14 -17 -14h-225l-44 -44c-3 -5 -9 -8 -15 -8c-10 0 -17 7 -17 17v35h-59v0c-8 0 -15 6 -17 14v0v288v0c1 9 8 16 17 16v0h360c9 0 16 -7 17 -16z" />
<glyph glyph-name="uniF132" unicode="&#xf132;" horiz-adv-x="461"
d="M461 357v0v-217v0c-1 -6 -7 -11 -13 -11v0h-44v-26c0 -7 -6 -13 -13 -13c-4 0 -9 3 -11 6l-33 33h-57v150v0c-1 6 -5 10 -11 10h-115v68v0c1 7 6 11 13 11h271v0c7 0 12 -5 13 -11zM253 264c6 0 11 -5 12 -11v0v-193h-1c-1 -5 -5 -10 -11 -10h-151l-30 -29
c-2 -3 -5 -5 -9 -5c-6 0 -12 5 -12 11v23h-40v0c-5 0 -10 5 -11 10v0v193v0c1 6 5 11 11 11v0h242z" />
<glyph glyph-name="uniF133" unicode="&#xf133;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51c78 0 141 63 141 141s-63 141 -141 141s-141 -63 -141 -141s63 -141 141 -141zM267 281c4 2 9 1 12 -2s4 -8 2 -12l-60 -100l-3 -3l-101 -61c-2 -1 -3 -1 -5 -1s-5 1 -7 3v0
c-3 3 -4 8 -2 12l61 101l3 3z" />
<glyph glyph-name="uniF134" unicode="&#xf134;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM193 333v-282c78 0 140 63 140 141s-62 141 -140 141z" />
<glyph glyph-name="uniF135" unicode="&#xf135;" horiz-adv-x="378"
d="M378 314v-1v0v-37h-378v36v2c0 8 6 13 14 13h1h349h1c8 0 13 -5 13 -13zM0 70v155h378v-155v0c0 -7 -6 -13 -13 -13v0h-350v0h-1c-8 0 -14 5 -14 13v0v0z" />
<glyph glyph-name="uniF136" unicode="&#xf136;" horiz-adv-x="419"
d="M405 84c8 0 14 -6 14 -14v-23c0 -8 -6 -14 -14 -14v0h-37v-36c0 -8 -6 -14 -14 -14h-23c-8 0 -14 6 -14 14v36h-241v0c-13 0 -25 12 -25 25v1v0v241h-37v0c-8 0 -14 6 -14 14v23c0 8 6 14 14 14v0h37v36v0c0 8 6 14 14 14h23c8 0 14 -6 14 -14v0v-36h241v0
c13 0 25 -12 25 -25v-1v0v-241h37v0zM102 84v0h215v216h-215v-216z" />
<glyph glyph-name="uniF137" unicode="&#xf137;" horiz-adv-x="348"
d="M348 38v-19v0v0c0 -9 -6 -16 -15 -16h-317v0c-9 0 -16 7 -16 16v0v0v19v0c0 9 7 16 16 16v0h317c9 0 15 -7 15 -16v0zM44 251c1 -1 1 0 2 -1l34 -35l82 81v0c3 3 7 5 12 5s9 -2 12 -5v0l82 -81l35 35c0 1 0 2 1 2h1v0c3 2 6 4 10 4c9 0 17 -8 17 -17v-3v-145v0v0v-2v0
c-1 -8 -8 -14 -17 -14v0v-1h-282v0v0c-9 0 -15 7 -16 15h-1v150h1c0 9 7 16 16 16c4 0 8 -1 11 -4v0v0zM292 208v0h-1h1zM2 309c0 21 10 31 31 31s30 -10 30 -31s-9 -31 -30 -31s-31 10 -31 31zM283 309c0 21 10 31 31 31s31 -10 31 -31s-10 -31 -31 -31s-31 10 -31 31z
M145 350c0 21 10 31 31 31s31 -10 31 -31s-10 -31 -31 -31s-31 10 -31 31z" />
<glyph glyph-name="uniF138" unicode="&#xf138;" horiz-adv-x="325"
d="M0 375h325l-30 -330l-132 -36l-133 36zM260 268l4 40h-102h-103l5 -40h98h6l-6 -2l-94 -40l3 -39h91h49l-3 -52l-46 -13v0v0l-44 11l-3 32v0h-41v0l5 -62l83 -25v0h1l82 25l11 123h-94v0v0z" />
<glyph glyph-name="uniF139" unicode="&#xf139;" horiz-adv-x="422"
d="M124 323v-262v0v0c0 -12 -11 -22 -23 -22v0h-80v1c-12 0 -21 9 -21 21v0v262v0c0 12 9 22 21 22v0h80v0c12 0 22 -10 22 -22h1zM62 65c18 0 32 14 32 32s-14 32 -32 32s-32 -14 -32 -32s14 -32 32 -32zM98 180v139h-72v-139h72zM273 323v-262v0v0c0 -12 -10 -22 -22 -22
v0h-81v1c-12 0 -21 9 -21 21v0v262v0c0 12 9 22 21 22v0h81v0c12 0 22 -10 22 -22v0zM211 65c18 0 32 14 32 32s-14 32 -32 32s-32 -14 -32 -32s14 -32 32 -32zM247 180v0v139h-72v-139h72zM422 323v-262v0v0c0 -12 -10 -22 -22 -22v0h-81v1c-12 0 -21 9 -21 21v0v262v0
c0 12 9 22 21 22v0h81v0c12 0 22 -10 22 -22v0zM360 65c18 0 32 14 32 32s-14 32 -32 32s-32 -14 -32 -32s14 -32 32 -32zM396 180v139h-72v-139h72z" />
<glyph glyph-name="uniF13A" unicode="&#xf13a;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM87 71c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM87 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36
s16 -36 36 -36zM174 156c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 69c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36z" />
<glyph glyph-name="uniF13B" unicode="&#xf13b;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM87 71c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM87 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36
s16 -36 36 -36zM261 69c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36z" />
<glyph glyph-name="uniF13C" unicode="&#xf13c;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM174 153c22 0 39 17 39 39s-17 39 -39 39s-39 -17 -39 -39s17 -39 39 -39z" />
<glyph glyph-name="uniF13D" unicode="&#xf13d;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM87 71c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM87 156c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36
s16 -36 36 -36zM87 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 69c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 156c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 243c20 0 36 16 36 36
s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36z" />
<glyph glyph-name="uniF13E" unicode="&#xf13e;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM87 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM174 156c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36
s16 -36 36 -36zM261 69c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36z" />
<glyph glyph-name="uniF13F" unicode="&#xf13f;" horiz-adv-x="348"
d="M348 329v0v-274v0c0 -20 -17 -37 -37 -37v0h-274v0c-20 0 -37 17 -37 37v0v274v0c0 20 17 37 37 37v0h274v0c20 -1 37 -17 37 -37zM87 243c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36s16 -36 36 -36zM261 69c20 0 36 16 36 36s-16 36 -36 36s-36 -16 -36 -36
s16 -36 36 -36z" />
<glyph glyph-name="uniF140" unicode="&#xf140;" horiz-adv-x="333"
d="M333 295v0v-144v0c0 -7 -5 -13 -12 -13v0h-71v-58v-1v-17v0c0 -16 -13 -29 -29 -29c-11 0 -21 6 -26 15v0l-50 86v0v0v1l-3 3h-51h-1c-7 0 -13 6 -13 13v0v0v144v0v43v0v1v0v0c0 7 6 12 13 12h1h185c2 0 4 0 5 -1v0l50 -50v0c1 -1 2 -3 2 -5v0zM51 316v-138v-2
c0 -7 -6 -13 -13 -13v0v0v0v0h-25v0c-7 0 -12 6 -13 12v0v141v0c0 7 6 12 13 12v0h24l1 1c7 0 13 -6 13 -13v0v0z" />
<glyph glyph-name="uniF141" unicode="&#xf141;" horiz-adv-x="447"
d="M447 294v-204v0v0c0 -11 -9 -20 -20 -20v0v0h-407c-11 0 -20 9 -20 20v0v0v204v0c0 11 9 20 20 20h407v0v0c11 0 20 -9 20 -20v0zM371 266v0v0c0 -2 2 -4 4 -4v0v0h21v-21v0c0 -2 2 -4 4 -4v0h17v0h1c2 0 4 2 4 4v0v43c0 2 -2 4 -4 4h-1v0h-42v0v0c-2 0 -4 -2 -4 -4v-18z
M77 118v0v0c0 2 -2 4 -4 4h-1v0h-21v21v0c0 2 -2 4 -4 4v0h-17v0v0c-2 0 -4 -2 -4 -4v0v-43c0 -2 2 -4 4 -4v0v0h42v0h1c2 0 4 2 4 4v18zM77 284v0v0c0 2 -2 4 -4 4h-43c-2 0 -4 -2 -4 -4v0v0v-43v0v0c0 -2 2 -4 4 -4h17v0v0c2 0 4 2 4 4v0v0v21h22v0c2 0 4 3 4 5v0v17z
M224 96c53 0 96 43 96 96s-43 96 -96 96s-96 -43 -96 -96s43 -96 96 -96zM422 143v0v0c0 2 -2 4 -4 4h-18v0c-2 0 -4 -2 -4 -4v0v0v-21h-21v0c-2 0 -4 -3 -4 -5v0v-17v0v0c0 -2 2 -4 4 -4h43c2 0 4 2 4 4v0v0v43zM224 263c39 0 70 -32 70 -71c0 -15 -4 -29 -12 -40v0
c0 3 -2 7 -4 8l-28 13l-12 6c5 3 9 8 12 14c2 5 3 10 3 16c0 3 0 6 -1 9c-4 14 -14 25 -28 25c-13 0 -25 -10 -29 -24c-1 -3 -1 -6 -1 -10c0 -6 2 -12 4 -17c3 -6 7 -11 12 -14l-11 -5l-29 -13c-3 -1 -4 -5 -4 -8v0c-8 11 -13 25 -13 40c0 39 32 71 71 71z" />
<glyph glyph-name="uniF142" unicode="&#xf142;" horiz-adv-x="209"
d="M126 219c39 -10 83 -26 83 -77c0 -42 -28 -73 -83 -79v-28v0c0 -3 -3 -6 -6 -6h-23v0c-3 0 -6 3 -6 6v28c-39 3 -68 18 -89 39v0c-1 1 -2 3 -2 5c0 1 0 2 1 3v0l22 32v0c1 2 3 3 5 3c1 0 2 0 3 -1v0l1 -1v0c14 -14 34 -28 59 -32v58c-39 9 -81 25 -81 76
c0 38 30 70 81 75v29c0 3 3 6 6 6h23c3 0 6 -3 6 -6v0v-30c30 -3 57 -14 77 -33c1 -1 2 -2 2 -4c0 -1 -1 -3 -2 -4v0l-21 -31h-1c-1 -1 -2 -2 -4 -2c-1 0 -3 0 -4 1v0c-14 12 -30 20 -47 24v-51zM91 227v46c-17 -2 -26 -11 -26 -24c0 -11 11 -17 26 -22zM126 111
c19 4 29 14 29 26s-12 19 -29 24v-50z" />
<glyph glyph-name="uniF143" unicode="&#xf143;" horiz-adv-x="404"
d="M379 194c14 0 25 -11 25 -25v-144c0 -14 -11 -25 -25 -25h-354c-14 0 -25 11 -25 25v144c0 14 11 25 25 25h90c11 0 21 -7 24 -17c9 -28 34 -46 63 -46s54 18 63 46c3 10 13 17 24 17h90zM197 181l-70 98c-1 2 -2 5 -1 7s3 3 6 3h33v88c0 4 3 7 7 7h60c4 0 7 -3 7 -7v-88
h33c3 0 5 -1 6 -3s0 -5 -1 -7l-69 -98c-1 -2 -4 -3 -6 -3v0c-2 0 -4 1 -5 3z" />
<glyph glyph-name="uniF144" unicode="&#xf144;" horiz-adv-x="382"
d="M13 141c-7 0 -13 6 -13 13c0 4 2 7 4 9l176 177c2 3 7 5 11 5s7 -2 9 -5v0l178 -177c3 -2 4 -5 4 -9c0 -7 -5 -13 -12 -13v0h-357v0zM382 52v0c0 -7 -6 -13 -13 -13v0h-357v0c-7 1 -12 6 -12 13v1v49v0c0 7 5 12 12 13v0l357 1v0c7 0 13 -6 13 -13v0v0v-51z" />
<glyph glyph-name="uniF145" unicode="&#xf145;" horiz-adv-x="493"
d="M389 393c7 0 13 -6 13 -13v-376c0 -7 -6 -13 -13 -13v0v0h-376v0v0v0v0c-7 0 -13 6 -13 13v376c0 7 6 13 13 13v0h376v0v0zM51 341v-298h299v298h-299zM490 120c1 0 2 0 3 -1s0 -2 -1 -3l-31 -44c-1 -1 -1 -2 -2 -2v0c-1 0 -2 1 -3 2l-31 44c-1 1 -2 2 -1 3s2 1 3 1h15
v40c0 2 1 3 3 3h27c2 0 3 -1 3 -3v-40h15zM427 264c-1 0 -2 0 -3 1s0 2 1 3l31 44c1 1 2 2 3 2v0c1 0 1 -1 2 -2l32 -44c1 -1 1 -2 0 -3s-2 -1 -3 -1h-15v-40c0 -2 -1 -3 -3 -3h-27c-2 0 -3 1 -3 3v40h-15zM109 284c0 17 8 26 25 26s25 -9 25 -26s-8 -25 -25 -25
s-25 8 -25 25zM182 252c6 -1 11 -6 11 -12v-72v0c0 -3 -1 -5 -3 -7c-4 -4 -12 -4 -16 0c-2 2 -3 4 -3 7v0v50v0c0 2 -1 4 -3 4s-4 -2 -4 -4v0v-32v-33v-66c0 -7 -5 -13 -12 -13s-13 6 -13 13v66v0c0 2 -1 4 -3 4s-4 -2 -4 -4v0v-66c0 -7 -5 -13 -12 -13s-13 6 -13 13v99v32
v0v0c0 2 -1 4 -3 4s-3 -2 -3 -4v0v0v-50v0c0 -3 -2 -5 -4 -7c-4 -4 -11 -4 -15 0c-2 2 -3 4 -3 7v0v72v0c0 7 5 12 12 12v0h91v0zM238 284c0 17 9 26 26 26s25 -9 25 -26s-8 -25 -25 -25s-26 8 -26 25zM312 252c6 -1 10 -6 10 -12v-72v0c0 -3 -1 -5 -3 -7
c-4 -4 -11 -4 -15 0c-2 2 -3 4 -3 7v0v50v0c0 2 -1 4 -3 4s-4 -2 -4 -4v0v-32v-33v-66c0 -7 -5 -13 -12 -13s-13 6 -13 13v66v0c0 2 -1 4 -3 4s-4 -2 -4 -4v0v-66c0 -7 -5 -13 -12 -13s-13 6 -13 13v99v32v0v0c0 2 -1 4 -3 4s-4 -2 -4 -4v0v0v-50v0c0 -3 -1 -5 -3 -7
c-4 -4 -11 -4 -15 0c-2 2 -3 4 -3 7v0v72v0c0 7 5 12 12 12v0h91v0z" />
<glyph glyph-name="uniF146" unicode="&#xf146;" horiz-adv-x="283"
d="M280 125c3 -2 3 -5 2 -8v0v0v0v0c-19 -34 -55 -67 -115 -67c-68 0 -122 38 -140 98h-21v-1c-3 0 -6 3 -6 6v21c0 3 3 6 6 6v0h15v12v13h-15v0c-3 0 -6 3 -6 6v21c0 3 3 6 6 6v0h21c19 59 73 96 140 96c60 0 96 -33 115 -67v0v0v0v0c1 -3 1 -6 -2 -8h-1v0l-40 -19v0
c-3 -1 -5 -1 -7 2v0c-12 22 -37 40 -65 40c-34 0 -61 -17 -75 -44h100v0c3 0 6 -3 6 -6v-21c0 -3 -3 -6 -6 -6v0v0v0v0h-110c-1 -5 -1 -8 -1 -13v-12h111v0c3 0 6 -3 6 -6v-21c0 -3 -3 -6 -6 -6v0h-101c14 -28 41 -45 76 -45c28 0 52 17 64 39l1 1c2 3 4 3 7 2v0l40 -19v0h1
z" />
<glyph glyph-name="uniF147" unicode="&#xf147;" horiz-adv-x="365"
d="M359 204c4 -2 6 -6 6 -11c0 -4 -2 -8 -4 -10v0v0l-1 -1l-79 -79v0c-24 -27 -60 -44 -99 -44c-35 0 -66 14 -90 36v-1l-87 87c-3 3 -5 7 -5 11c0 3 1 7 3 9v0l80 79c24 27 60 45 99 45c35 0 67 -14 91 -36v1zM182 102c50 0 90 40 90 90s-40 90 -90 90s-90 -40 -90 -90
s40 -90 90 -90zM139 192c0 29 14 43 43 43s44 -14 44 -43s-15 -44 -44 -44s-43 15 -43 44z" />
<glyph glyph-name="uniF148" unicode="&#xf148;" horiz-adv-x="372"
d="M372 192c0 -3 -1 -5 -4 -7v-1l-192 -111c-2 -2 -5 -2 -7 -2c-5 0 -8 3 -8 8v78l-146 -84c-2 -2 -4 -2 -6 -2c-5 0 -9 3 -9 8v226v0c0 5 4 8 9 8c2 0 4 0 6 -2l146 -84v78v0c0 5 3 8 8 8c2 0 5 0 7 -2l191 -111v0c3 -1 5 -4 5 -8z" />
<glyph glyph-name="uniF149" unicode="&#xf149;" horiz-adv-x="268"
d="M229 163c-20 -20 -44 -32 -70 -37v-41h28v0c2 0 4 0 6 -2s2 -4 2 -6v-35c0 -4 -4 -8 -8 -8v0h-28v-34v0c0 -4 -4 -8 -8 -8v0h-35v0v0h-2v0c-4 1 -6 4 -6 8v0v34h-27v0c-4 0 -8 4 -8 8v0v35v0c0 2 0 4 2 6s4 2 6 2v0h27v41c-25 5 -50 18 -69 37c-52 52 -52 138 0 190
s138 52 190 0s52 -138 0 -190zM134 175c46 0 83 37 83 83s-37 83 -83 83s-83 -37 -83 -83s37 -83 83 -83z" />
<glyph glyph-name="uniF14A" unicode="&#xf14a;" horiz-adv-x="227"
d="M68 345c0 28 14 42 42 42s42 -14 42 -42s-14 -42 -42 -42s-42 14 -42 42zM227 171v0v-3c0 -3 -1 -6 -3 -9s-3 -4 -6 -6s-6 -3 -9 -3c-8 0 -14 4 -17 12v0l-20 76v0c-1 3 -3 5 -6 5c-4 0 -5 -2 -5 -6v-2v0l32 -122c1 -1 1 -2 1 -3l1 -1h-1h1c0 -6 -4 -10 -10 -10h-24v-81
c0 -4 -1 -7 -3 -10s-5 -6 -8 -8s-6 -3 -10 -3c-6 0 -11 3 -15 7s-6 8 -6 14v81h-12v-81c0 -6 -2 -10 -6 -14s-8 -7 -14 -7s-11 3 -15 7s-6 8 -6 14v81h-24c-6 0 -10 4 -10 10v0v0v1c0 1 0 2 1 3l33 123v1v0v0v1v0c-1 3 -2 5 -5 5s-5 -2 -6 -5v0v0l-20 -76h-1
c-3 -8 -8 -12 -16 -12c-5 0 -10 3 -13 6s-5 7 -5 12v3v0l28 105v0l1 2v0c3 9 8 13 18 13v1h132v-1v0c10 0 16 -4 19 -13v0l1 -2v0z" />
<glyph glyph-name="uniF14B" unicode="&#xf14b;" horiz-adv-x="410"
d="M410 334c0 -10 -4 -19 -11 -25v0l-156 -155v-118v0v-2c0 -10 -7 -17 -17 -17c-3 0 -6 1 -9 2v0v0l-1 1l-40 23v0c-5 3 -9 9 -9 15v0v0v96l-155 154c-8 6 -12 16 -12 26c0 18 15 33 33 33h2v0h343v0c18 -1 32 -15 32 -33zM114 301v0v0v0z" />
<glyph glyph-name="uniF14C" unicode="&#xf14c;" horiz-adv-x="411"
d="M100 308v45v1c0 7 6 12 13 12v0v0h185v0c7 0 12 -5 12 -12v0v-47h-31v27h-148v-26h-31zM76 18v262h259v-262h-259zM128 167v-37c0 -1 0 -1 1 -2s2 -1 3 -1h52v-53c0 -1 0 -2 1 -3s2 -1 3 -1h37c1 0 1 0 2 1s2 2 2 3v53h52c1 0 2 0 3 1s1 1 1 2v37c0 2 -2 4 -4 4h-52v52
c0 2 -2 4 -4 4h-37c-2 0 -4 -2 -4 -4v-52h-52c-2 0 -4 -2 -4 -4zM20 280v0h31v-262h-31v0c-11 0 -20 9 -20 20v1v220v0c0 11 9 21 20 21zM411 38v0c0 -11 -9 -20 -20 -20v0v0h-31v262h31c11 0 20 -9 20 -20v0v-222z" />
<glyph glyph-name="uniF14D" unicode="&#xf14d;" horiz-adv-x="372"
d="M364 325c4 0 8 -4 8 -8v-169c0 -2 -1 -5 -3 -6c-21 -22 -51 -36 -84 -36c-31 0 -58 11 -79 31c-23 27 -57 45 -96 45c-20 0 -39 -4 -56 -13v-145c0 -15 -12 -27 -27 -27s-27 12 -27 27v322c0 15 12 27 27 27c11 0 20 -6 24 -15c20 18 47 29 77 29c31 0 59 -11 80 -31
c23 -27 56 -45 95 -45c21 0 41 5 58 14v0h3z" />
<glyph glyph-name="uniF14E" unicode="&#xf14e;" horiz-adv-x="425"
d="M397 325c15 0 28 -13 28 -28v-248c0 -15 -13 -28 -28 -28h-369c-15 0 -28 13 -28 28v248c0 15 13 28 28 28h30l26 32c3 4 8 6 13 6h74c6 0 12 -5 15 -10c3 -4 13 -16 23 -28h188zM374 124v31c0 2 -1 4 -3 4h-45v45c0 2 -2 3 -4 3h-31c-2 0 -4 -1 -4 -3v-45h-45
c-2 0 -3 -2 -3 -4v-31c0 -1 0 -1 1 -2s1 -1 2 -1h45v-45c0 -1 0 -2 1 -3s2 -1 3 -1h31c1 0 2 0 3 1s1 2 1 3v45h45c1 0 1 0 2 1s1 1 1 2z" />
<glyph glyph-name="uniF14F" unicode="&#xf14f;" horiz-adv-x="425"
d="M312 181c9 0 17 -8 17 -17v0v0v0v-15h-34v15c0 9 8 17 17 17zM397 325c15 0 28 -13 28 -28v-248c0 -15 -13 -28 -28 -28h-369c-15 0 -28 13 -28 28v248c0 15 13 28 28 28h30l26 32c3 4 8 6 13 6h74c6 0 12 -5 15 -10c3 -4 13 -16 23 -28h188zM374 77v0v67c0 3 -2 5 -5 5
h-6h-9v15v0c0 23 -19 42 -42 42s-41 -19 -41 -42v-15h-8h-6c-3 0 -5 -2 -5 -5v-67c0 -3 2 -5 5 -5h112c3 0 5 2 5 5z" />
<glyph glyph-name="uniF150" unicode="&#xf150;" horiz-adv-x="425"
d="M397 325c15 0 28 -13 28 -28v-248c0 -15 -13 -28 -28 -28h-369c-15 0 -28 13 -28 28v248c0 15 13 28 28 28h30l26 32c3 4 8 6 13 6h74c6 0 12 -5 15 -10c3 -4 13 -16 23 -28h188z" />
<glyph glyph-name="uniF151" unicode="&#xf151;" horiz-adv-x="264"
d="M0 264c0 15 7 22 22 22s22 -7 22 -22s-7 -22 -22 -22s-22 7 -22 22zM168 368c0 30 15 45 45 45s45 -15 45 -45s-15 -44 -45 -44s-45 14 -45 44zM92 354c0 19 9 28 28 28s28 -9 28 -28s-9 -28 -28 -28s-28 9 -28 28zM249 69v0c9 -11 13 -24 13 -38c0 -17 -5 -31 -17 -43
s-26 -17 -43 -17c-13 0 -25 3 -35 11s-18 18 -22 30l-76 131l1 1c-5 8 -9 16 -11 25c-3 11 -5 22 -5 33c0 29 10 53 31 74s45 31 74 31c19 0 37 -5 53 -14s29 -23 38 -39s14 -33 14 -52c0 -21 -5 -41 -17 -59v0c-6 -11 -9 -23 -9 -35c0 -14 3 -27 11 -39zM39 311
c0 15 7 23 22 23s22 -8 22 -23s-7 -22 -22 -22s-22 7 -22 22z" />
<glyph glyph-name="uniF152" unicode="&#xf152;" horiz-adv-x="356"
d="M325 59c1 0 1 -1 1 -2v-1l-6 -12c0 -1 -1 -1 -2 -1h-1l-16 8c-1 0 -1 1 -1 2s1 0 1 1l6 12c1 1 2 2 3 1zM325 328c1 0 1 -1 1 -2v-1l-7 -11c0 -1 0 -2 -1 -2l-2 1l-15 9c-1 0 -1 0 -1 1v2l7 11c1 1 2 2 3 1zM295 75c1 -1 2 -2 1 -3l-7 -12c0 -1 -1 -1 -2 -1h-1l-4 3l-5 2
l-62 -34v0v0c-1 -1 -4 -1 -5 -1s-3 0 -4 1v0v0l-63 34l-62 -34v0h-1c-1 -1 -3 -1 -4 -1s-3 0 -4 1h-1v0l-67 37c-3 1 -4 3 -4 6v274c0 3 2 6 5 7s6 0 9 -1l62 -34l62 34h1v1h2h2h2h2l1 -1v0l62 -34l62 34c2 2 6 3 9 1l7 -5l7 -3c1 0 1 -1 1 -2s-1 0 -1 -1l-6 -12
c0 -1 -1 -1 -2 -1l-1 1l-9 5v-252zM76 46v256l-58 31v-256zM210 46v256l-67 36v-256zM354 160c1 0 2 -2 2 -3v-27c0 -1 -1 -2 -2 -2h-13c-1 0 -3 1 -3 2v27c0 1 2 3 3 3h13zM354 52c1 0 2 -1 2 -2v-10c0 -8 -5 -11 -10 -11c-2 0 -4 1 -6 2l-8 4c-1 0 -1 1 -1 2v1l6 12l1 1
l2 1h1h13zM349 314c0 0 7 -4 7 -12v-10c0 -1 -1 -2 -2 -2h-13c-1 0 -3 1 -3 2v8l-6 4c-1 0 -1 0 -1 1v2l6 11c1 1 2 2 3 1zM354 267c1 0 2 -1 2 -2v-27c0 -1 -1 -2 -2 -2h-13c-1 0 -3 1 -3 2v27c0 1 2 2 3 2h13zM354 106c1 0 2 -1 2 -2v-27c0 -1 -1 -3 -2 -3h-13
c-1 0 -3 2 -3 3v27c0 1 2 2 3 2h13zM354 213c1 0 2 -1 2 -2v-27c0 -1 -1 -2 -2 -2h-13c-1 0 -3 1 -3 2v27c0 1 2 2 3 2h13z" />
<glyph glyph-name="uniF153" unicode="&#xf153;" horiz-adv-x="427"
d="M193 140c4 0 8 -4 8 -8v-112c0 -4 -4 -8 -8 -8h-72c-4 0 -8 4 -8 8v112c0 4 4 8 8 8h72zM306 372c4 0 8 -4 8 -8v-344c0 -4 -4 -8 -8 -8h-72c-4 0 -8 4 -8 8v344c0 4 4 8 8 8h72zM420 267c4 0 7 -3 7 -7v-240c0 -4 -3 -8 -7 -8h-73c-4 0 -8 4 -8 8v240c0 4 4 7 8 7h73z
M80 267c4 0 8 -3 8 -7v-240c0 -4 -4 -8 -8 -8h-72c-4 0 -8 4 -8 8v240c0 4 4 7 8 7h72z" />
<glyph glyph-name="uniF154" unicode="&#xf154;" horiz-adv-x="387"
d="M380 238c4 0 7 -4 7 -8v-77c0 -4 -3 -8 -7 -8h-372c-4 0 -8 4 -8 8v77c0 4 4 8 8 8h372zM226 357c3 -1 5 -4 5 -8v-77c0 -4 -2 -7 -5 -8v0h-218c-4 0 -8 4 -8 8v77c0 4 4 8 8 8h218v0zM275 120c4 0 8 -4 8 -8v-77c0 -4 -4 -8 -8 -8h-267c-4 0 -8 4 -8 8v77c0 4 4 8 8 8
h267z" />
<glyph glyph-name="uniF155" unicode="&#xf155;" horiz-adv-x="380"
d="M212 382c93 -1 167 -76 168 -169c0 -4 -2 -6 -6 -6h-1v0h-161c-4 0 -7 2 -7 6v161v0v1c0 4 3 7 7 7zM341 174v0v-2c0 -94 -76 -170 -170 -170s-171 76 -171 170s77 171 171 171h1v0h1c4 0 7 -3 7 -7l-1 -1h1v-147c0 -4 2 -7 6 -7h148c4 0 7 -3 7 -7z" />
<glyph glyph-name="uniF156" unicode="&#xf156;" horiz-adv-x="410"
d="M384 37h-359c-14 0 -25 11 -25 25v260c0 14 11 25 25 25h359c14 0 26 -11 26 -25v-260c0 -14 -12 -25 -26 -25zM359 87v210h-309v-210h309zM162 111c-5 0 -10 2 -13 5l-25 25l-31 -25c-8 -6 -19 -6 -25 2s-6 19 2 25l44 36c7 6 17 6 24 -1l21 -21l46 72c4 5 9 8 16 8
s12 -4 15 -10l27 -58l52 92c5 9 16 12 25 7s12 -15 7 -24l-70 -123c-3 -6 -9 -9 -16 -9s-13 5 -16 11l-28 59l-40 -63c-3 -5 -8 -7 -13 -8h-2z" />
<glyph glyph-name="uniF157" unicode="&#xf157;" horiz-adv-x="399"
d="M148 320c-3 2 -5 5 -5 9c0 6 4 10 10 10c3 0 6 -1 8 -3l60 -60c3 -2 5 -5 5 -9c0 -6 -5 -10 -11 -10c-2 0 -4 1 -6 2v0h-1v1zM215 111h-25c-14 0 -28 0 -41 1l24 -42c2 -3 4 -7 4 -11c0 -10 -8 -18 -18 -18c-6 0 -11 3 -14 7v0l-38 65l-37 -65h-1c-3 -4 -8 -7 -14 -7
c-10 0 -18 8 -18 18c0 4 2 8 4 11l32 56c-8 6 -14 29 -14 56c0 13 2 24 4 34l-57 33v0c-4 2 -6 6 -6 11c0 7 6 13 13 13c2 0 4 0 6 -1v0l56 -33c1 0 2 1 3 1h137v-129zM306 125l31 -55c2 -3 4 -7 4 -11c0 -10 -8 -18 -18 -18c-6 0 -11 3 -14 7h-1l-37 65l-38 -65v0
c-3 -4 -8 -7 -14 -7c-10 0 -18 8 -18 18c0 4 2 8 4 11l31 54v116l83 -83c-2 -17 -7 -29 -13 -32zM399 235c0 -4 -2 -8 -4 -10v0l-11 -11v0h-10h-40l-14 -14c1 -5 1 -11 1 -16l-72 72l42 42l26 45l13 -22c3 0 5 -2 7 -3v1l26 -15c7 -3 11 -10 11 -18v-21l20 -20
c3 -2 5 -6 5 -10z" />
<glyph glyph-name="uniF158" unicode="&#xf158;" horiz-adv-x="321"
d="M148 302c58 0 104 -48 104 -106c0 -13 -2 -24 -6 -36c0 -1 -1 -2 -1 -3c0 0 -15 -26 -25 -38c-1 -2 -3 -3 -4 -5c-7 -8 -10 -11 -10 -24c1 -27 1 -37 -1 -45c-4 -26 -23 -39 -55 -40v0v0c-9 0 -17 7 -17 16c0 5 1 10 4 13s7 5 12 5c21 1 22 7 23 11v2c1 5 0 21 0 37
c-1 26 10 38 18 48l4 4c6 7 17 24 21 32c2 7 3 15 3 23c0 39 -31 72 -70 72s-71 -33 -71 -72c0 -9 -8 -17 -17 -17s-17 8 -17 17c0 58 47 106 105 106zM172 194c0 13 -11 24 -24 24s-24 -11 -24 -24c0 -8 -7 -15 -15 -15s-14 7 -14 15c0 29 24 52 53 52s52 -23 52 -52
c0 -8 -6 -15 -14 -15s-14 7 -14 15zM75 142c6 6 16 6 22 0c3 -3 5 -8 5 -12s-2 -8 -5 -11l-70 -71c-3 -3 -7 -4 -11 -4s-8 1 -11 4s-5 8 -5 12s2 8 5 11zM207 334c38 0 69 -30 69 -68v0v-7v0c0 -3 -3 -6 -6 -6v0h-12v0c-3 0 -6 3 -6 6v0v7v0c0 24 -21 44 -45 44v0v0h-7v0
c-3 0 -5 3 -5 6v0v11v0c0 3 2 7 5 7v0h7v0v0zM321 266v0v-7v0c0 -3 -3 -6 -6 -6v0h-11v0c-3 0 -7 3 -7 6v0v7v0c0 49 -41 89 -90 89v0v0h-7v0c-3 0 -5 3 -5 6v0v12v0c0 3 2 6 5 6v0h7v0v0c63 0 114 -50 114 -113z" />
<glyph glyph-name="uniF159" unicode="&#xf159;" horiz-adv-x="409"
d="M295 379c63 0 114 -51 114 -114c0 -68 -33 -108 -59 -140l-6 -7c-31 -38 -128 -108 -132 -111c-2 -2 -5 -2 -8 -2s-5 0 -7 2c-4 3 -101 73 -132 111l-6 7c-26 32 -59 72 -59 140c0 63 51 114 114 114c36 0 69 -16 90 -44c21 28 55 44 91 44z" />
<glyph glyph-name="uniF15A" unicode="&#xf15a;" horiz-adv-x="353"
d="M348 254c3 -2 5 -6 5 -10v-233c0 -7 -6 -13 -13 -13h-96c-7 0 -12 6 -12 13v143h-111v-143c0 -7 -5 -13 -12 -13h-96c-7 0 -13 6 -13 13v233c0 4 2 8 5 10l161 129c5 4 11 4 16 0z" />
<glyph glyph-name="uniF15B" unicode="&#xf15b;" horiz-adv-x="300"
d="M0 362v0h300l-27 -306l-123 -34l-123 34zM243 289l1 11h-94v0h-94l1 -11l9 -103h84v0h46l-4 -49l-42 -11v0v0l-42 11l-3 30h-20h-17l5 -59l77 -21v0v0l77 21v7l9 98l1 11h-10h-77v0h-50l-3 38h53v0h90h1v8z" />
<glyph glyph-name="uniF15C" unicode="&#xf15c;" horiz-adv-x="355"
d="M337 370c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM337 64c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM355 149v0v-16v0c0 -10 -8 -17 -18 -17v0h-198
c-10 0 -18 7 -18 17v16c0 10 8 17 18 17h198v0v0c10 0 18 -7 18 -17zM355 250v0v-16v0c0 -10 -8 -17 -18 -17v0h-198c-10 0 -18 7 -18 17v16c0 10 8 18 18 18h198v0v0c10 0 18 -8 18 -18zM0 192c0 1 0 1 1 2v1l64 36c1 1 1 1 2 1c2 0 3 -1 3 -3v-74v0c0 -2 -1 -3 -3 -3
c-1 0 -1 0 -2 1l-63 36v0c-1 0 -2 2 -2 3z" />
<glyph glyph-name="uniF15D" unicode="&#xf15d;" horiz-adv-x="355"
d="M337 370c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM337 64c10 0 18 -7 18 -17v-16c0 -10 -8 -17 -18 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM355 149v0v-16v0c0 -10 -8 -17 -18 -17v0h-199
c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h199v0c10 0 18 -7 18 -17zM355 250v0v-16v0c0 -10 -8 -17 -18 -17v0h-199c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h199v0c10 0 18 -8 18 -18zM3 152c-2 0 -3 1 -3 3v74v0c0 2 1 3 3 3c1 0 1 0 2 -1l63 -36v0c1 0 2 -2 2 -3
s0 -1 -1 -2v-1l-64 -36c-1 -1 -1 -1 -2 -1z" />
<glyph glyph-name="uniF15E" unicode="&#xf15e;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM212 85v124c0 4 -3 7 -7 7h-26c-4 0 -7 -3 -7 -7v-124c0 -4 3 -6 7 -6h26c4 0 7 2 7 6zM192 244c13 0 23 10 23 23s-10 23 -23 23s-23 -10 -23 -23s10 -23 23 -23z" />
<glyph glyph-name="uniF15F" unicode="&#xf15f;" horiz-adv-x="108"
d="M108 324v-4v0l-58 -261v0c-1 -7 -6 -12 -13 -12h-25v0c-7 1 -12 6 -12 13v3v0v0v0l58 261v0c0 7 6 13 13 13h24c7 0 13 -6 13 -13z" />
<glyph glyph-name="uniF160" unicode="&#xf160;" horiz-adv-x="445"
d="M445 218v0v0v-32v0c0 -2 0 -5 -2 -7s-5 -2 -7 -2v0h-27h-1v-61v0v-39v0c0 -5 -4 -9 -9 -9h-1h-31v0c-5 0 -10 4 -10 9v0v21v0v79h-25v-26v0v-39v0c0 -5 -5 -9 -10 -9v0h-31v0h-1c-5 0 -9 4 -9 9v0v16v23v26h-45c-10 -56 -58 -99 -117 -99c-66 0 -119 53 -119 119
s53 119 119 119c55 0 102 -38 115 -89h163h12h27c2 0 5 -1 7 -3s2 -4 2 -6zM119 128c38 0 68 30 68 68s-30 68 -68 68s-68 -30 -68 -68s30 -68 68 -68z" />
<glyph glyph-name="uniF161" unicode="&#xf161;" horiz-adv-x="488"
d="M60 101c-14 0 -26 12 -26 26v226c0 14 12 25 26 25h368c14 0 25 -11 25 -25v-226c0 -14 -11 -26 -25 -26h-368zM85 327v-175h318v175h-318zM476 76c6 0 12 -6 12 -12v-28c0 -3 -2 -7 -4 -9l-18 -18c-2 -2 -5 -3 -8 -3h-430c-3 0 -6 2 -8 4l-17 18c-2 2 -3 5 -3 8v28
c0 6 6 12 12 12h464zM288 35v12c0 1 -1 2 -2 2h-84c-1 0 -3 -1 -3 -2v-12c0 -1 2 -3 3 -3h84c1 0 2 2 2 3z" />
<glyph glyph-name="uniF162" unicode="&#xf162;" horiz-adv-x="381"
d="M76 173v119h229v-119h-229zM82 92v56h57v-56h-57zM246 92v56h57v-56h-57zM164 92v56h57v-56h-57zM358 368c13 0 23 -10 23 -23v-307v0c-1 -12 -11 -22 -23 -22h-335v0v0c-12 0 -22 10 -23 22v0v307v0c0 13 10 23 23 23v0h335v0zM330 67v0v250h-279v-250h279z" />
<glyph glyph-name="uniF163" unicode="&#xf163;" horiz-adv-x="426"
d="M368 351v0l-45 -45c-3 -3 -7 -3 -10 0v0l-11 11v0c-3 3 -3 7 0 10l45 45v0c3 3 8 3 11 0v0v0l10 -10v0c3 -3 3 -8 0 -11v0v0v0zM206 349c-4 0 -8 3 -8 7v0v64c0 4 4 8 8 8v0h14v0c4 0 8 -4 8 -8v-64v0c0 -4 -4 -7 -8 -7v0h-14v0zM426 243v0v-15v0c0 -4 -3 -7 -7 -7v0h-64
c-4 0 -7 3 -7 7v0v15v0c0 4 3 8 7 8h64v0c4 0 7 -4 7 -8zM213 324c60 0 109 -49 109 -109c0 -22 -7 -42 -18 -59c-18 -26 -28 -60 -29 -99c-1 -2 -4 -5 -7 -5h-1v0h-108v0h-1c-3 0 -5 2 -6 4c-1 37 -12 71 -28 96v0c-13 18 -20 39 -20 63c0 60 49 109 109 109zM268 -12
c4 0 7 -3 7 -7v-17c0 -4 -3 -8 -7 -8h-1v0h-108v0h-1c-4 0 -8 4 -8 8v17c0 4 4 7 8 7h1v0h108v0h1zM268 37c4 0 7 -4 7 -8v-17c0 -4 -3 -8 -7 -8l-1 1v-1h-108v1l-1 -1c-4 0 -8 4 -8 8v17v0c0 4 4 8 8 8h1v0h108v0h1zM71 245c4 0 8 -4 8 -8v0v-14v0c0 -4 -4 -8 -8 -8v0h-64
c-4 0 -7 4 -7 8v14c0 4 3 8 7 8h64v0zM60 354c-3 3 -3 7 0 10v0l11 11v0v0c3 3 8 3 11 0l45 -46v0c3 -3 3 -7 0 -10v0l-11 -10v0c-3 -3 -7 -4 -10 -1v0z" />
<glyph glyph-name="uniF164" unicode="&#xf164;" horiz-adv-x="333"
d="M333 67c0 -7 -6 -13 -13 -13v0v0v0v0h-26v1c-7 0 -11 5 -12 11v0v141v0c0 7 5 13 12 13v0h25h1c7 0 12 -6 12 -13v0v0v-138c0 -1 1 -1 1 -2zM256 46v0v-1v0v0c0 -7 -6 -12 -13 -12h-1h-185c-2 0 -4 0 -5 1v0l-50 50v0c-1 1 -2 3 -2 5v0v144v0c0 7 6 13 13 13v0h70v58v1
v17v0v0c0 16 13 29 29 29c11 0 21 -6 26 -15v0l51 -87c1 -1 1 -2 2 -3h51h1c7 0 13 -6 13 -13v0v0v-144v0v-43zM15 89l1 -1l-1 1v0z" />
<glyph glyph-name="uniF165" unicode="&#xf165;" horiz-adv-x="353"
d="M323 339c39 -39 40 -101 4 -141v0l-52 -52c-9 -9 -20 -16 -31 -21c-4 -10 -10 -20 -18 -28v0l-51 -52c-40 -40 -105 -40 -145 0s-40 105 0 145l52 52v-1c8 8 17 14 27 18c5 11 13 23 22 32l52 51v0c40 36 101 36 140 -3zM140 82l37 38c-17 4 -33 13 -46 26s-23 30 -27 47
l-37 -38v0c-20 -20 -20 -53 0 -73s53 -20 73 0v0zM168 183c9 -9 21 -14 33 -15c-1 12 -6 24 -15 33s-21 14 -33 15c1 -12 6 -24 15 -33zM290 232v0c17 20 16 51 -3 70s-50 20 -70 3v0l-3 -3v0v0l-38 -38c17 -4 33 -13 46 -26s23 -30 27 -47l38 38v0v0z" />
<glyph glyph-name="uniF166" unicode="&#xf166;" horiz-adv-x="431"
d="M414 345c10 0 17 -8 17 -18v-16c0 -10 -7 -17 -17 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h320zM414 217c10 0 17 -7 17 -17v-16c0 -10 -7 -17 -17 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 17 17 17h320zM414 90c10 0 17 -7 17 -17v-16c0 -10 -7 -18 -17 -18
h-320c-10 0 -17 8 -17 18v16c0 10 7 17 17 17h320zM0 319c0 17 9 26 26 26s25 -9 25 -26s-8 -25 -25 -25s-26 8 -26 25zM0 197c0 17 9 26 26 26s25 -9 25 -26s-8 -25 -25 -25s-26 8 -26 25zM0 65c0 17 9 25 26 25s25 -8 25 -25s-8 -26 -25 -26s-26 9 -26 26z" />
<glyph glyph-name="uniF167" unicode="&#xf167;" horiz-adv-x="423"
d="M29 333l-9 -9l-6 7l17 17h10v-55h-12v40zM21 210c-6 0 -10 -2 -14 -6l-7 8c5 6 13 9 21 9c12 0 21 -7 21 -18c0 -9 -8 -18 -22 -28h22v-10h-41v9c22 17 29 22 29 29c0 5 -4 7 -9 7zM30 65c6 -1 13 -5 13 -13c0 -9 -8 -16 -21 -16c-10 0 -18 4 -22 9l6 8c4 -4 10 -7 15 -7
c7 0 11 3 11 7s-3 7 -11 7h-7v10h7c6 0 10 2 10 6s-4 6 -10 6c-5 0 -10 -1 -14 -5l-6 7c4 5 11 9 21 9c13 0 20 -6 20 -15c0 -7 -6 -12 -12 -13zM406 346c10 0 17 -7 17 -17v-16c0 -10 -7 -18 -17 -18h-320c-10 0 -17 8 -17 18v16c0 10 7 17 17 17h320zM406 219
c10 0 17 -8 17 -18v-16c0 -10 -7 -17 -17 -17h-320c-10 0 -17 7 -17 17v16c0 10 7 18 17 18h320zM406 91c10 0 17 -7 17 -17v-16c0 -10 -7 -18 -17 -18h-320c-10 0 -17 8 -17 18v16c0 10 7 17 17 17h320z" />
<glyph glyph-name="uniF168" unicode="&#xf168;" horiz-adv-x="332"
d="M321 103c6 0 11 -6 11 -12v-1v-53c0 -6 -5 -11 -11 -11v0h-182v0c-6 0 -11 5 -11 11v0v53v1c0 6 5 12 11 12v0v0h182v0zM65 103c6 0 12 -6 12 -12v0v0v-54v0c0 -6 -6 -11 -12 -11v0h-53v0v0c-6 0 -12 5 -12 11v0v54v0v0c0 6 6 12 12 12v0v0h53v0zM321 231
c6 0 11 -6 11 -12v-1v-53c0 -6 -5 -11 -11 -11v0h-182v0c-6 0 -11 5 -11 11v0v53v1c0 6 5 12 11 12v0v0h182v0zM65 231c6 0 12 -6 12 -12v0v0v-54v0c0 -6 -6 -11 -12 -11v0h-53v0v0c-6 0 -12 5 -12 11v0v54v0v0c0 6 6 12 12 12v0v0h53v0zM128 293v0v53v1c0 6 5 11 11 11v0v0
h182v0c6 0 11 -5 11 -11v-1v-53c0 -6 -5 -12 -11 -12v0h-182v0c-6 0 -11 6 -11 12v0zM65 358c6 0 12 -5 12 -11v0v0v-54v0c0 -6 -6 -12 -12 -12v0h-53v0v0c-6 0 -12 6 -12 12v0v54v0v0c0 6 6 11 12 11v0v0h53v0z" />
<glyph glyph-name="uniF169" unicode="&#xf169;" horiz-adv-x="332"
d="M0 293v53v1c0 6 6 11 12 11v0v0h309v0c6 0 11 -5 11 -11v0v-54v0c0 -6 -5 -12 -11 -12v0h-309v0c-6 0 -12 6 -12 12v0zM321 230c6 0 11 -5 11 -11v0v-54v0c0 -6 -5 -11 -11 -11v0h-309v0c-6 0 -12 5 -12 11v0v53v1c0 6 6 11 12 11v0v0h309v0zM321 103c6 0 11 -6 11 -12v0
v-54v0c0 -6 -5 -11 -11 -11v0h-309v0c-6 0 -12 5 -12 11v0v53v1c0 6 6 12 12 12v0v0h309v0z" />
<glyph glyph-name="uniF16A" unicode="&#xf16a;" horiz-adv-x="356"
d="M342 222c7 0 14 -7 14 -14v-197c0 -7 -7 -14 -14 -14h-329c-7 0 -13 7 -13 14v197c0 7 6 14 13 14h19h22v43c0 67 54 122 121 122s122 -55 122 -122v0v-43h26h19zM126 265v-43h99v43v1v0v0c0 27 -23 49 -50 49c-28 0 -49 -22 -49 -50z" />
<glyph glyph-name="uniF16B" unicode="&#xf16b;" horiz-adv-x="346"
d="M346 327v-137c0 -2 -1 -5 -3 -6s-5 -2 -7 -1l-130 44c-3 1 -5 3 -5 6s1 6 3 8l30 21l5 4c-18 14 -41 23 -66 23c-40 0 -75 -22 -93 -55v0c-4 -6 -12 -9 -18 -5l-42 24v0c-6 3 -8 11 -5 17v0c31 56 90 93 158 93c50 0 95 -20 128 -53l2 2l31 22c2 2 5 1 8 0s4 -4 4 -7z
M326 131c6 -3 9 -11 6 -17v0c-31 -56 -91 -93 -159 -93c-50 0 -94 20 -127 53l-3 -2l-30 -22c-2 -2 -5 -1 -8 0s-5 4 -5 7v137c0 2 1 5 3 6s5 2 7 1l130 -44c3 -1 6 -3 6 -6s-1 -6 -3 -8l-31 -21l-5 -4c18 -14 41 -23 66 -23c40 0 76 22 94 55v0c4 6 12 9 18 5l41 -24v0z
" />
<glyph glyph-name="uniF16C" unicode="&#xf16c;" horiz-adv-x="397"
d="M233 395c91 0 164 -74 164 -164s-73 -164 -164 -164c-26 0 -51 6 -73 17l-82 -82v1c-8 -8 -20 -14 -33 -14c-25 0 -45 20 -45 45c0 13 6 25 14 33h-1l80 79c-15 25 -24 54 -24 85c0 90 73 164 164 164zM234 132c57 0 103 45 103 102s-46 102 -103 102s-102 -45 -102 -102
s45 -102 102 -102z" />
<glyph glyph-name="uniF16D" unicode="&#xf16d;" horiz-adv-x="394"
d="M381 345c7 0 13 -6 13 -13v-24c0 -2 -1 -2 -2 -3s-4 -2 -5 -3l-188 -110c-1 0 -1 -1 -2 -1s0 1 -1 1l-194 110c-1 1 -2 2 -2 3v27c0 7 6 13 13 13h368zM393 265c1 -1 1 -1 1 -2v-177c0 -1 -1 -3 -2 -3l-1 -1c-1 0 -1 0 -2 1l-107 115c-1 1 0 2 0 3s0 2 1 2l106 62
c1 1 3 1 4 0zM253 182l127 -137c1 -1 1 -3 0 -4s-2 -2 -3 -2h-364c-2 0 -4 1 -6 2c-1 1 -2 2 -2 3s0 2 1 3l142 131c1 1 3 2 4 1l38 -22c5 -3 11 -2 16 1l42 25c1 1 4 0 5 -1zM117 194l-112 -103c-1 -1 -1 -1 -2 -1h-1c-1 1 -2 2 -2 3v167c0 1 1 2 2 3s2 1 3 0l111 -64
c1 -1 2 -1 2 -2s0 -2 -1 -3z" />
<glyph glyph-name="uniF16E" unicode="&#xf16e;" horiz-adv-x="466"
d="M49 347c0 28 14 42 42 42s43 -14 43 -42s-15 -42 -43 -42s-42 14 -42 42zM172 293c5 -1 9 -2 12 -6s6 -8 6 -13v-120v0c0 -5 -3 -10 -6 -13s-7 -5 -12 -5s-10 2 -13 5s-5 8 -5 13v0v82v1c0 4 -2 6 -6 6s-6 -2 -6 -6v-1v-53v-55v-110c0 -6 -2 -11 -6 -15s-8 -6 -14 -6
s-11 2 -15 6s-6 9 -6 15v110v0c0 4 -2 6 -6 6s-6 -2 -6 -6v0v-110c0 -6 -2 -11 -6 -15s-9 -6 -15 -6s-11 2 -15 6s-6 9 -6 15v165v53v1v0c0 4 -1 6 -5 6s-6 -2 -6 -6v0v-1v-82v0c0 -5 -2 -10 -5 -13s-8 -5 -13 -5s-10 2 -13 5s-5 8 -5 13v0v120v0c0 5 2 10 6 14s9 5 14 5v0
h152v0zM305 347c0 28 14 42 42 42s43 -14 43 -42s-15 -43 -43 -43s-42 15 -42 43zM466 171v0v-3c0 -3 0 -6 -2 -9s-4 -5 -7 -7s-6 -2 -9 -2c-8 0 -14 3 -17 11v0l-21 78v0c-1 3 -2 4 -5 4c-4 0 -6 -1 -6 -5v-2v0l33 -124c1 -1 1 -3 1 -4h1h-1h1c0 -6 -4 -10 -10 -10h-25v-82
c0 -6 -2 -11 -6 -15s-9 -6 -15 -6s-11 2 -15 6s-6 9 -6 15v82h-12v-82c0 -4 -1 -8 -3 -11s-4 -6 -7 -8s-7 -2 -11 -2c-6 0 -11 2 -15 6s-6 9 -6 15v82h-24c-6 0 -10 4 -10 10v0v0v0c0 1 0 3 1 4l33 124v1v1v0v1v0c-1 3 -2 4 -5 4s-5 -1 -6 -4v0v0l-21 -78v0
c-3 -8 -9 -11 -17 -11c-5 0 -9 1 -13 5s-5 8 -5 13v3v0l29 106v0v2v0c3 9 9 14 19 14v0h134v0v0c10 0 16 -5 19 -14v0l1 -2v0z" />
<glyph glyph-name="uniF16F" unicode="&#xf16f;" horiz-adv-x="342"
d="M342 354v0v-106v0c0 -4 -4 -8 -8 -8h-35c-4 0 -8 4 -8 8v28l-46 -46c14 -21 23 -46 23 -74c0 -74 -60 -134 -134 -134s-134 60 -134 134s60 134 134 134c28 0 54 -9 76 -24l44 45h-26v0c-4 0 -8 4 -8 8v0v0v35c0 4 4 8 8 8v0h106v0c4 0 8 -4 8 -8v0zM134 73
c46 0 83 37 83 83s-37 83 -83 83s-83 -37 -83 -83s37 -83 83 -83z" />
<glyph glyph-name="uniF170" unicode="&#xf170;" horiz-adv-x="190"
d="M49 346c0 28 14 42 42 42s43 -14 43 -42s-15 -42 -43 -42s-42 14 -42 42zM172 292c5 -1 9 -2 12 -6s6 -9 6 -14v-120v0c0 -5 -3 -9 -6 -12s-7 -5 -12 -5s-10 2 -13 5s-5 7 -5 12v0v83v1c0 4 -2 6 -6 6s-6 -2 -6 -6v-1v-53v-55v-110c0 -6 -2 -11 -6 -15s-8 -6 -14 -6
s-11 2 -15 6s-6 9 -6 15v110v0c0 4 -2 6 -6 6s-6 -2 -6 -6v0v-110c0 -6 -2 -11 -6 -15s-9 -6 -15 -6s-11 2 -15 6s-6 9 -6 15v165v53v1v0c0 4 -1 6 -5 6s-6 -2 -6 -6v0v-1v-83v0c0 -5 -2 -9 -5 -12s-8 -5 -13 -5s-10 2 -13 5s-5 7 -5 12v0v120v0c0 4 1 7 3 10s4 6 7 8
s6 2 10 2v0h152v0z" />
<glyph glyph-name="uniF171" unicode="&#xf171;" horiz-adv-x="430"
d="M430 407v-430v0v-1v-2h-1c-1 -6 -6 -11 -13 -11v0h-402v0c-8 0 -14 6 -14 14v0v0v283v0l161 161v0v0v0v0h255v0v0v0v0c8 0 14 -6 14 -14v0zM305 370l-19 -33l93 -92v125h-74zM161 246h-110v-31l86 -85l139 240h-101v-110v0v0c0 -8 -6 -14 -14 -14v0zM51 14h19l53 93
l-72 72v-165zM99 14h280v194l-106 106zM276 215c34 0 62 -28 62 -62c0 -14 -4 -27 -12 -37l-39 -67c0 -1 -1 -2 -2 -3v0v0c-2 -2 -5 -4 -8 -4c-4 0 -8 1 -10 4v0v1v1l-40 69c-7 10 -12 22 -12 36c0 34 27 62 61 62zM276 122c17 0 30 13 30 30s-13 31 -30 31s-30 -14 -30 -31
s13 -30 30 -30z" />
<glyph glyph-name="uniF172" unicode="&#xf172;" horiz-adv-x="289"
d="M144 395c80 0 145 -65 145 -145c0 -33 -12 -63 -30 -87l-90 -157c-1 -2 -3 -4 -4 -6l-1 -2v1c-5 -6 -12 -10 -20 -10c-9 0 -16 4 -21 11v0v0c-1 1 -1 2 -2 3l-92 161c-18 24 -29 54 -29 86c0 80 64 145 144 145zM143 177c39 0 71 32 71 71s-32 71 -71 71s-71 -32 -71 -71
s32 -71 71 -71z" />
<glyph glyph-name="uniF173" unicode="&#xf173;" horiz-adv-x="385"
d="M76 302c8 0 14 -6 14 -14v-127v0c-1 -7 -7 -12 -14 -12c-42 0 -76 35 -76 77s34 76 76 76zM385 364v0v0v-24v-236v-23v0v-2c0 -8 -6 -14 -14 -14c-4 0 -7 2 -9 4l-134 77h-98c-7 0 -13 6 -14 13v0v132c0 8 6 14 14 14h110l123 70c2 2 5 3 8 3c8 0 14 -6 14 -14zM224 41v0
c3 -6 2 -13 -3 -17v-1l-26 -14v0c-1 -1 -1 -2 -2 -2c-6 -4 -14 -1 -18 5v0l-1 1v0v0l-49 85v1s-1 0 -1 1c-4 7 -2 15 5 19c2 1 4 2 6 2v0h37v0c4 0 7 -3 9 -6v0l43 -73v-1v0v0z" />
<glyph glyph-name="uniF174" unicode="&#xf174;" horiz-adv-x="261"
d="M261 196c0 -65 -48 -119 -111 -128v-28h68v0c11 0 19 -8 19 -19s-8 -20 -19 -20v0h-175v0c-11 0 -20 9 -20 20s9 19 20 19v0h68v28c-63 9 -111 63 -111 128v0v74c0 11 8 19 19 19s20 -8 20 -19v-73v0c0 -51 40 -92 91 -92s92 41 92 92v73c0 11 8 19 19 19s20 -8 20 -19
v-73v0v0v-1v0zM65 197v2v0v119v0c1 36 29 65 65 65s65 -29 66 -65v0v-119v0v-2c0 -36 -30 -65 -66 -65s-65 29 -65 65z" />
<glyph glyph-name="uniF175" unicode="&#xf175;" horiz-adv-x="384"
d="M281 219c3 0 5 -2 5 -5v-44c0 -3 -2 -5 -5 -5h-178c-3 0 -5 2 -5 5v44c0 3 2 5 5 5h178zM192 333c-78 0 -141 -63 -141 -141s63 -141 141 -141s141 63 141 141s-63 141 -141 141zM192 384v0c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192z
" />
<glyph glyph-name="uniF176" unicode="&#xf176;" horiz-adv-x="414"
d="M404 251c6 0 10 -5 10 -11v-96c0 -6 -4 -11 -10 -11h-394c-6 0 -10 5 -10 11v96c0 6 4 11 10 11h394z" />
<glyph glyph-name="uniF177" unicode="&#xf177;" horiz-adv-x="224"
d="M211 295c7 0 13 -6 13 -13v-307c0 -7 -6 -13 -13 -13h-199v0c-7 0 -12 6 -12 13v307c0 7 5 13 12 13v0h199zM112 -24c7 0 13 5 13 12s-6 13 -13 13s-12 -6 -12 -13s5 -12 12 -12zM173 13v0v231h-122v-231h122zM212 368v0v-1v0v0l-9 -9v0v0h-1v0c-3 -3 -7 -3 -10 -1v0v1v0
v0l-5 5v0c-41 41 -109 40 -150 -1v0v0l-6 -5v0c-3 -2 -6 -2 -9 0v0l-10 9v0c-3 3 -3 7 -1 10v1h1v0v0l5 5v0v0c52 52 138 53 190 1v0v-1v0v0l5 -5v0c2 -3 2 -6 0 -9zM174 339c2 -3 2 -6 0 -9v0l-9 -10v0v0v0v0c-3 -3 -8 -3 -11 -1v0v1v0v0l-5 5v0c-21 20 -54 20 -74 0v-1v0
l-6 -5v0c-3 -2 -6 -2 -9 0v0l-10 9v1c-3 3 -3 7 -1 10v0l6 5v0v1c31 31 82 31 114 0v0l5 -6v0z" />
<glyph glyph-name="uniF178" unicode="&#xf178;" horiz-adv-x="224"
d="M211 358c7 0 13 -5 13 -12v-308c0 -7 -6 -12 -13 -12h-199v0c-7 0 -12 5 -12 12v308c0 7 5 12 12 12v0h199zM112 39c7 0 13 5 13 12s-6 13 -13 13s-12 -6 -12 -13s5 -12 12 -12zM173 77v0v230h-122v-230h122z" />
<glyph glyph-name="uniF179" unicode="&#xf179;" horiz-adv-x="471"
d="M442 381c16 0 29 -12 29 -28v-252c0 -16 -13 -29 -29 -29h-156v-44h44c5 0 9 -3 9 -8v-9c0 -5 -4 -8 -9 -8h-194c-5 0 -8 3 -8 8v9c0 5 3 8 8 8h48v44h-155c-16 0 -29 13 -29 29v252c0 16 13 28 29 28h413zM51 123h368v208h-368v-208z" />
<glyph glyph-name="uniF17A" unicode="&#xf17a;" horiz-adv-x="467"
d="M465 48c1 -2 2 -4 2 -6c0 -7 -5 -13 -12 -14v0h-256h-103h-87v1c-1 0 -1 -1 -2 -1c-4 0 -7 3 -7 7c0 2 0 4 1 5l8 13v1h1l81 140c2 4 6 7 11 7s9 -3 11 -7v0l27 -48l114 196c4 8 12 14 21 14s16 -5 20 -13v0l171 -295h-1z" />
<glyph glyph-name="uniF17B" unicode="&#xf17b;" horiz-adv-x="382"
d="M366 378c9 0 16 -7 16 -16v-253c0 -31 -31 -56 -69 -56s-69 25 -69 56s31 56 69 56c6 0 12 -1 18 -2v135h-193v-236c0 -31 -31 -56 -69 -56s-69 25 -69 56s31 56 69 56c6 0 12 -1 18 -2v246c0 9 8 16 17 16v0h262v0z" />
<glyph glyph-name="uniF17C" unicode="&#xf17c;" horiz-adv-x="397"
d="M397 52v0c0 -7 -6 -13 -13 -13v-1h-25v0c-7 0 -13 6 -13 13v1v0v120l-170 -99c-2 -2 -5 -2 -7 -2c-5 0 -8 3 -8 8v78l-146 -84c-2 -2 -4 -2 -6 -2c-5 0 -9 3 -9 8v226v0c0 5 4 8 9 8c2 0 4 0 6 -2l146 -84v78v0c0 5 3 8 8 8c2 0 5 0 7 -2l170 -99v119v2c0 7 6 13 13 13
l1 -1h24v0c7 0 12 -4 13 -11v0v-2v0v0v-280z" />
<glyph glyph-name="uniF17D" unicode="&#xf17d;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51c34 0 66 13 90 33l-24 24c-3 0 -4 1 -6 3v0l-4 7l-21 21l-16 -28h-1c-2 -2 -4 -4 -7 -4c-5 0 -10 5 -10 10c0 2 1 4 2 6l13 23h-21h-23l13 -23c1 -2 3 -4 3 -6
c0 -5 -5 -10 -10 -10c-3 0 -6 2 -8 4v0l-21 36l-21 -36v0c-2 -2 -5 -4 -8 -4c-5 0 -10 5 -10 10c0 2 2 4 3 6l17 31c-4 4 -7 16 -7 31c0 7 1 14 2 19l-32 18v0c-2 1 -3 3 -3 6c0 4 3 7 7 7c1 0 3 0 4 -1v0l31 -18v1v0h25l-65 65c-20 -24 -33 -56 -33 -90
c0 -78 63 -141 141 -141zM300 102c20 24 33 56 33 90c0 78 -63 141 -141 141c-34 0 -66 -13 -90 -33l83 -83h26l30 30h-1l17 30l10 -17h1v0l14 -8c4 -2 6 -6 6 -10v-11l11 -11c2 -1 3 -4 3 -6s-1 -4 -2 -5v0l-6 -6v0h-6h-22l-8 -8c0 -3 1 -6 1 -10c0 -16 -4 -29 -9 -32l3 -4
z" />
<glyph glyph-name="uniF17E" unicode="&#xf17e;" horiz-adv-x="384"
d="M272 213c3 0 5 -3 5 -6v-31v0c0 -3 -2 -5 -5 -5v0v0h-4v0c-3 0 -6 2 -6 5v0v1v0v0v30v0c0 3 3 6 6 6v0h4v0zM293 213c3 0 6 -3 6 -6v0v-30v-1v0c0 -3 -3 -5 -6 -5v0v0h-3v0c-3 0 -6 2 -6 5v0v31v0c0 3 3 6 6 6v0h3v0zM192 384c106 0 192 -86 192 -192s-86 -192 -192 -192
s-192 86 -192 192s86 192 192 192zM192 51c34 0 66 13 90 33l-87 87h-104c-3 0 -6 3 -6 6v0v30v0v0c0 3 3 6 6 6v0h62l-69 69c-20 -24 -33 -56 -33 -90c0 -78 63 -141 141 -141zM300 102c20 24 33 56 33 90c0 78 -63 141 -141 141c-34 0 -66 -13 -90 -33l87 -87h60v0
c3 0 6 -3 6 -6v0v-30v0c0 -3 -3 -6 -6 -6h-18z" />
<glyph glyph-name="uniF17F" unicode="&#xf17f;" horiz-adv-x="360"
d="M301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0v-127v0v0v0v0c0 -5 -4 -9 -9 -9h-33c-5 0 -9 4 -9 9v0v105h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33z
M351 174c5 0 9 -4 9 -9v-36c0 -5 -4 -8 -9 -8h-40v-40c0 -5 -4 -9 -9 -9h-35c-5 0 -9 4 -9 9v40h-40c-5 0 -9 3 -9 8v36c0 5 4 9 9 9h40v40c0 5 4 8 9 8h35c5 0 9 -3 9 -8v-40h40z" />
<glyph glyph-name="uniF180" unicode="&#xf180;" horiz-adv-x="361"
d="M310 410v-392v0v-13c0 -5 -4 -9 -9 -9h-8h-276h-8c-5 0 -9 4 -9 9v13v271v5v12l133 133h9v0h147v0h12c5 0 9 -4 9 -9v-20v0zM51 47h208v341h-108v-91c0 -5 -4 -8 -9 -8h-91v-242zM354 321c4 0 7 -4 7 -8v-360c0 -4 -3 -8 -7 -8h-272v0v0c-4 0 -7 4 -7 8v17h253
c4 0 8 4 8 8v343h18z" />
<glyph glyph-name="uniF181" unicode="&#xf181;" horiz-adv-x="310"
d="M106 119c-7 0 -12 -4 -12 -11s5 -12 12 -12c4 0 8 3 9 7l12 -6c-3 -6 -9 -14 -21 -14c-15 0 -26 10 -26 25s11 24 26 24c12 0 18 -7 21 -14l-12 -5c-1 4 -5 6 -9 6zM148 118c0 -4 26 0 26 -18c0 -10 -7 -17 -20 -17c-10 0 -17 3 -22 8l7 10c4 -3 9 -6 15 -6c3 0 6 1 6 3
c0 5 -27 -1 -27 18c0 8 7 16 20 16c8 0 15 -3 20 -7l-8 -10c-4 3 -10 5 -14 5c-3 0 -3 -1 -3 -2zM204 99l10 32h16l-17 -47h-18l-18 47h16zM310 384v-392v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0zM51 22
h208v340h-108v-90c0 -5 -4 -9 -9 -9h-91v-241z" />
<glyph glyph-name="uniF182" unicode="&#xf182;" horiz-adv-x="361"
d="M301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0v-127v0v0v0v0c0 -5 -4 -9 -9 -9h-33c-5 0 -9 4 -9 9v0v105h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33z
M330 147l28 -28c3 -3 3 -10 0 -13l-25 -25c-3 -3 -9 -3 -12 0l-29 29l-28 -29c-3 -3 -9 -3 -12 0l-25 25c-3 3 -3 10 0 13l28 28l-28 28c-3 3 -3 10 0 13l25 25c3 3 9 3 12 0l28 -28l28 28c3 3 10 3 13 0l25 -25c3 -3 3 -10 0 -13z" />
<glyph glyph-name="uniF183" unicode="&#xf183;" horiz-adv-x="310"
d="M310 384v-392v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0zM51 22h208v340h-108v-90c0 -5 -4 -9 -9 -9h-91v-241zM97 131c15 0 26 -8 26 -23s-11 -24 -26 -24h-21v47h21zM97 96c7 0 11 6 11 12
s-3 11 -11 11h-7v-23h7zM155 132c15 0 26 -9 26 -24s-11 -25 -26 -25s-26 10 -26 25s11 24 26 24zM155 96c7 0 11 5 11 12s-4 11 -11 11s-12 -4 -12 -11s5 -12 12 -12zM213 119c-7 0 -12 -4 -12 -11s5 -12 12 -12c4 0 8 3 9 7l12 -6c-3 -6 -9 -14 -21 -14
c-15 0 -26 10 -26 25s11 24 26 24c12 0 18 -7 21 -14l-12 -5c-1 4 -5 6 -9 6z" />
<glyph glyph-name="uniF184" unicode="&#xf184;" horiz-adv-x="428"
d="M301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0v-84v0v0v-1v0c0 -5 -4 -8 -9 -8h-33c-5 0 -9 3 -9 8v0v63h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33z
M425 248c3 -3 3 -9 0 -12l-163 -163v0v0l-82 -22v0c-3 -2 -7 -2 -10 1c-2 2 -3 6 -2 9v0l22 84l1 -1l-1 1l163 163c3 3 10 3 13 0zM195 78l49 13l-36 36z" />
<glyph glyph-name="uniF185" unicode="&#xf185;" horiz-adv-x="458"
d="M456 112c2 -1 2 -3 2 -5v0c0 -2 0 -4 -2 -5l-94 -68c-2 -1 -5 -2 -7 -1s-3 4 -3 6v32h-86c-4 0 -7 3 -7 7v58c0 4 3 6 7 6h85v32c0 2 2 5 4 6s4 1 6 0zM301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12
c5 0 9 -3 9 -8v-21v0v-207v0v0v-1v0c0 -5 -4 -8 -9 -8h-33c-5 0 -9 3 -9 8v0v186h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33zM107 119c-7 0 -11 -4 -11 -11s4 -12 11 -12c4 0 8 3 9 7l13 -6c-3 -6 -10 -14 -22 -14c-15 0 -26 10 -26 25s11 24 26 24
c12 0 19 -7 22 -14l-13 -5c-1 4 -5 6 -9 6zM156 95c3 0 5 1 5 3c0 5 -26 -1 -26 18c0 8 6 16 19 16c8 0 15 -3 20 -7l-7 -10c-4 3 -10 5 -14 5c-3 0 -4 -1 -4 -2c0 -4 26 0 26 -18c0 -10 -7 -17 -20 -17c-10 0 -17 3 -22 8l8 10c4 -3 9 -6 15 -6zM195 131l10 -32l10 32h16
l-17 -47h-18l-17 47h16z" />
<glyph glyph-name="uniF186" unicode="&#xf186;" horiz-adv-x="458"
d="M456 112c2 -1 2 -3 2 -5v0c0 -2 0 -4 -2 -5l-94 -68c-2 -1 -5 -2 -7 -1s-3 4 -3 6v32h-86c-4 0 -7 3 -7 7v58c0 4 3 6 7 6h85v32c0 2 2 5 4 6s4 1 6 0zM301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12
c5 0 9 -3 9 -8v-21v0v-207v0v0v-1v0c0 -5 -4 -8 -9 -8h-33c-5 0 -9 3 -9 8v0v186h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33zM77 131h22c15 0 26 -8 26 -23s-11 -24 -26 -24h-22v47zM110 108c0 6 -3 11 -11 11h-7v-23h7c7 0 11 6 11 12zM131 108
c0 15 10 24 25 24s26 -9 26 -24s-11 -25 -26 -25s-25 10 -25 25zM168 108c0 7 -5 11 -12 11s-11 -4 -11 -11s4 -12 11 -12s12 5 12 12zM214 119c-7 0 -11 -4 -11 -11s4 -12 11 -12c4 0 8 3 9 7l13 -6c-3 -6 -10 -14 -22 -14c-15 0 -26 10 -26 25s11 24 26 24
c12 0 19 -7 22 -14l-13 -5c-1 4 -5 6 -9 6z" />
<glyph glyph-name="uniF187" unicode="&#xf187;" horiz-adv-x="458"
d="M456 112c2 -1 2 -3 2 -5v0c0 -2 0 -4 -2 -5l-94 -68c-2 -1 -5 -2 -7 -1s-3 4 -3 6v32h-86c-4 0 -7 3 -7 7v58c0 4 3 6 7 6h85v32c0 2 2 5 4 6s4 1 6 0zM301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12
c5 0 9 -3 9 -8v-21v0v-207v0v0v-1v0c0 -5 -4 -8 -9 -8h-33c-5 0 -9 3 -9 8v0v186h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33zM83 131h26c11 0 17 -7 17 -16s-6 -16 -17 -16h-11v-15h-15v47zM111 115c0 3 -2 4 -4 4h-9v-8h9c2 0 4 2 4 4zM133 131h21
c15 0 26 -8 26 -23s-11 -24 -26 -24h-21v47zM166 108c0 6 -4 11 -12 11h-7v-23h7c7 0 12 6 12 12zM225 119h-22v-5h21v-12h-21v-18h-14v47h36v-12z" />
<glyph glyph-name="uniF188" unicode="&#xf188;" horiz-adv-x="458"
d="M456 112c2 -1 2 -3 2 -5v0c0 -2 0 -4 -2 -5l-94 -68c-2 -1 -5 -2 -7 -1s-3 4 -3 6v32h-86c-4 0 -7 3 -7 7v58c0 4 3 6 7 6h85v32c0 2 2 5 4 6s4 1 6 0zM301 46c5 0 9 -4 9 -9v0v-45v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12
c5 0 9 -3 9 -8v-21v0v-207v0v0v-1v0c0 -5 -4 -8 -9 -8h-33c-5 0 -9 3 -9 8v0v186h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v15v0c0 5 4 9 9 9v0h33z" />
<glyph glyph-name="uniF189" unicode="&#xf189;" horiz-adv-x="310"
d="M9 263c-5 0 -9 4 -9 9v9l133 132h9c5 0 9 -3 9 -8v-133c0 -5 -4 -9 -9 -9h-133zM301 413c5 0 9 -3 9 -8v-426c0 -5 -4 -8 -9 -8h-292c-5 0 -9 3 -9 8v224v0c1 4 5 8 9 8h184v0v0c5 0 9 4 9 9v0v0v187v0c1 4 4 6 8 6h91z" />
<glyph glyph-name="uniF18A" unicode="&#xf18a;" horiz-adv-x="389"
d="M381 329c4 0 8 -4 8 -8v-360c0 -4 -4 -8 -8 -8h-271v0v0c-4 0 -8 4 -8 8v18h253c4 0 8 3 8 7v343h18zM338 12c0 -4 -4 -8 -8 -8h-271v0c-4 0 -8 4 -8 8v18h253c4 0 8 3 8 7v343h18c4 0 8 -4 8 -8v-360zM287 63c0 -4 -4 -8 -8 -8h-271c-4 0 -8 4 -8 8v360c0 4 4 8 8 8h271
c4 0 8 -4 8 -8v-360z" />
<glyph glyph-name="uniF18B" unicode="&#xf18b;" horiz-adv-x="310"
d="M110 131c11 0 17 -7 17 -16s-6 -16 -17 -16h-11v-15h-15v47h26zM108 111c2 0 4 2 4 4c0 3 -2 4 -4 4h-9v-8h9zM155 131c15 0 26 -8 26 -23s-11 -24 -26 -24h-21v47h21zM155 96c7 0 12 6 12 12s-4 11 -12 11h-7v-23h7zM190 84v47h36v-12h-22v-5h21v-12h-21v-18h-14z
M310 384v-392v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0zM51 22h208v340h-108v-90c0 -5 -4 -9 -9 -9h-91v-241z" />
<glyph glyph-name="uniF18C" unicode="&#xf18c;" horiz-adv-x="360"
d="M310 86v0v0v-94v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0v-176v0v0v0v0c0 -5 -4 -9 -9 -9h-33c-5 0 -9 4 -9 9v0v154h-108v-90c0 -5 -4 -9 -9 -9h-91v-241h208v64v0c0 5 4 9 9 9v0h33c5 0 9 -4 9 -9v0v0
zM351 174c5 0 9 -4 9 -9v-36c0 -5 -4 -8 -9 -8h-133c-5 0 -9 3 -9 8v36c0 5 4 9 9 9h133z" />
<glyph glyph-name="uniF18D" unicode="&#xf18d;" horiz-adv-x="403"
d="M403 384l-1 -392v0v-13c0 -5 -3 -8 -8 -8h-8h-277h-8c-5 0 -9 3 -9 8v13v45v0c0 5 4 9 9 9v0h34c5 0 8 -4 8 -9v0v-15h209v340h-109v-90c0 -5 -4 -9 -9 -9h-91v-9v0c0 -5 -3 -8 -8 -8v0h-34c-5 0 -8 3 -8 8h-1v9v5v13l133 132h9v0h147v0h13c5 0 8 -3 8 -8v-21h1zM199 146
c0 -45 -37 -82 -82 -82c-13 0 -26 3 -37 9l-41 -41v0c-4 -4 -10 -7 -16 -7c-13 0 -23 9 -23 22c0 7 3 13 7 17v0l40 40c-7 12 -12 27 -12 42c0 45 37 82 82 82s82 -37 82 -82zM70 146c0 -26 21 -48 47 -48s48 22 48 48s-22 47 -48 47s-47 -21 -47 -47z" />
<glyph glyph-name="uniF18E" unicode="&#xf18e;" horiz-adv-x="310"
d="M310 384v-392v0v-13c0 -5 -4 -8 -9 -8h-8h-276h-8c-5 0 -9 3 -9 8v13v271v5v13l133 132h9v0h147v0h12c5 0 9 -3 9 -8v-21v0zM51 22h208v340h-108v-90c0 -5 -4 -9 -9 -9h-91v-241z" />
<glyph glyph-name="uniF18F" unicode="&#xf18f;" horiz-adv-x="439"
d="M389 203c5 -5 5 -13 0 -18l-203 -203v0c-5 -5 -13 -5 -18 0l-164 164c-5 5 -5 14 0 19v0l139 139l-57 58c-5 5 -8 11 -8 18c0 14 12 26 26 26c7 0 13 -3 18 -8l57 -58l27 27c5 5 14 5 19 0v0v0l164 -164v0zM288 156l38 38l-110 110l-149 -148h221zM430 70
c6 -8 9 -17 9 -27c0 -26 -21 -48 -47 -48s-48 22 -48 48c0 11 4 20 10 28l30 52c0 1 1 0 1 1v1v0c2 2 4 3 7 3s5 -2 7 -4v0v0v-1z" />
<glyph glyph-name="uniF190" unicode="&#xf190;" horiz-adv-x="356"
d="M77 -5c-14 0 -32 5 -50 23c-24 24 -27 47 -25 62c2 18 11 34 27 50l150 151c42 42 70 26 83 13c16 -16 26 -42 -14 -82l-138 -139l-27 27l138 139c21 21 16 26 14 28s-8 8 -29 -13l-150 -151c-7 -7 -15 -17 -16 -28c-1 -10 3 -19 14 -30c13 -13 23 -11 26 -11
c9 1 20 8 30 18l178 178c15 15 24 29 28 42c5 19 -1 38 -20 57c-20 20 -50 40 -98 -8l-165 -165c-7 -7 -20 -7 -27 0s-7 20 0 27l165 165c51 51 106 54 152 8c36 -36 36 -71 30 -94c-6 -20 -18 -39 -38 -59l-178 -178c-16 -16 -34 -27 -51 -29c-3 0 -6 -1 -9 -1z" />
<glyph glyph-name="uniF191" unicode="&#xf191;" horiz-adv-x="228"
d="M65 346c6 0 12 -5 12 -11v0v0v-286v0v0c0 -6 -6 -11 -12 -11v0h-54v0v0c-6 0 -11 5 -11 11v0v0v286v0v0c0 6 5 11 11 11v0h53v0h1zM228 49v0v0c0 -6 -5 -11 -11 -11v0h-55v0v0c-6 0 -11 5 -11 11v0v0v286v0v0c0 6 5 11 11 11v0h53v0h2c6 0 11 -5 11 -11v0v0v-286z" />
<glyph glyph-name="uniF192" unicode="&#xf192;" horiz-adv-x="363"
d="M104 240c0 -29 -23 -52 -52 -52s-52 23 -52 52s23 51 52 51s52 -22 52 -51zM311 281c29 0 52 -23 52 -52s-23 -51 -52 -51s-52 22 -52 51s23 52 52 52zM264 172l3 -4c16 -19 35 -44 35 -84c0 -37 -31 -68 -68 -68c-21 0 -40 10 -53 27c-13 -17 -33 -27 -54 -27
c-37 0 -68 31 -68 68c0 40 19 65 35 84l3 4c5 6 13 13 22 21c16 17 37 27 62 27c28 0 52 -13 68 -33c6 -5 11 -11 15 -15zM128 310c0 38 19 58 57 58s57 -20 57 -58s-19 -57 -57 -57s-57 19 -57 57z" />
<glyph glyph-name="uniF193" unicode="&#xf193;" horiz-adv-x="315"
d="M73 88c-2 -9 -11 -16 -20 -16h-40c-9 0 -15 8 -13 16l58 248c2 8 10 16 19 16h85c18 0 34 -2 48 -4c14 -3 25 -7 35 -13s17 -14 22 -24s8 -22 8 -37c0 -33 -13 -60 -41 -80s-66 -31 -116 -31h-12c-9 0 -17 -7 -19 -15zM106 232c-2 -9 3 -16 12 -16h10c22 0 40 5 52 14
s18 22 18 38c0 11 -4 19 -12 24s-19 8 -35 8h-13c-9 0 -18 -7 -20 -15zM307 271c5 -10 8 -21 8 -36c0 -33 -14 -61 -42 -81s-65 -30 -115 -30h-12c-9 0 -17 -8 -19 -16l-14 -60c-2 -9 -11 -16 -20 -16h-40c-9 0 -15 8 -13 16l2 8h28c9 0 17 6 19 15l14 61c2 8 10 15 19 15
h12c50 0 88 11 116 31s41 47 41 80c0 15 -3 27 -8 37v1c1 0 1 -1 2 -1c10 -6 17 -14 22 -24z" />
<glyph glyph-name="uniF194" unicode="&#xf194;" horiz-adv-x="405"
d="M401 298c5 -5 5 -14 0 -19l-253 -254v0v0l-128 -34v0c-5 -2 -12 -2 -16 2s-5 9 -3 14v0l34 130h1v0l253 254c5 5 15 5 20 0zM43 33l77 20l-57 56z" />
<glyph glyph-name="uniF195" unicode="&#xf195;" horiz-adv-x="443"
d="M442 356h1v-330h-1c-1 -11 -10 -21 -22 -21c-1 0 -3 1 -4 1v-1h-393v0c-12 0 -22 10 -23 21v0v2v0v0v328v0c0 13 10 23 23 23v0h393v-1c1 0 3 1 4 1c13 0 22 -10 22 -23zM392 56v272h-341v-218l28 48c1 3 5 5 8 5s6 -2 7 -5v0l19 -33l77 134c2 5 9 10 15 10s11 -4 14 -9
v0l116 -202v0c0 -1 1 -1 1 -2h56zM262 250c0 34 18 52 52 52s52 -18 52 -52s-18 -51 -52 -51s-52 17 -52 51z" />
<glyph glyph-name="uniF196" unicode="&#xf196;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51c78 0 141 63 141 141s-63 141 -141 141s-141 -63 -141 -141s63 -141 141 -141zM276 197c2 -1 2 -3 2 -5s0 -4 -2 -5v0l-120 -69v0h-3c-3 0 -5 1 -5 4v0v138v0v1c0 3 2 6 5 6
c1 0 2 -1 3 -1v0l120 -69v0z" />
<glyph glyph-name="uniF197" unicode="&#xf197;" horiz-adv-x="415"
d="M389 35h-364c-14 0 -25 12 -25 26v262c0 14 11 26 25 26h364c14 0 26 -12 26 -26v-262c0 -14 -12 -26 -26 -26zM364 86v212h-313v-212h313zM283 191l-61 -36l-61 -35v71v70l61 -35z" />
<glyph glyph-name="uniF198" unicode="&#xf198;" horiz-adv-x="276"
d="M276 192c0 -4 -2 -8 -5 -10v0l-254 -146v0c-2 -1 -4 -2 -6 -2c-6 0 -10 4 -11 10v0v293v0v1c0 6 5 12 11 12c2 0 5 -1 7 -2l252 -146c4 -2 6 -6 6 -10z" />
<glyph glyph-name="uniF199" unicode="&#xf199;" horiz-adv-x="371"
d="M362 245c5 0 9 -5 9 -10v-86c0 -3 -1 -5 -3 -7s-3 -3 -6 -3h-124v-123c0 -2 -1 -5 -3 -7s-4 -3 -6 -3h-87c-2 0 -4 1 -6 3s-3 5 -3 7v123h-124c-2 0 -4 1 -6 3s-3 5 -3 7v86c0 5 4 10 9 10h124v123c0 5 4 10 9 10h87c5 0 9 -5 9 -10v-123h124z" />
<glyph glyph-name="uniF19A" unicode="&#xf19a;" horiz-adv-x="221"
d="M221 75c0 -2 -1 -4 -2 -5v0c-12 -12 -31 -20 -61 -20c-36 0 -50 18 -75 18c-14 0 -32 -7 -48 -16v0h-2c-2 0 -4 1 -5 3v0h-1v0l-14 30v0v0v0v2c0 2 1 4 3 5v0v1v0c26 12 45 30 45 51c0 8 -2 15 -5 22h-50v0v0c-3 0 -6 2 -6 5v0v22v0c0 3 3 6 6 6v0v0h28
c-10 14 -19 30 -19 50c0 52 51 85 100 85c46 0 79 -16 96 -50v0c1 -1 1 -2 1 -3c0 -2 -1 -4 -3 -5v0l-37 -22v0v0h-2c-2 0 -5 1 -6 3c-7 17 -23 29 -42 29c-24 0 -43 -15 -43 -38c0 -21 11 -34 20 -49h60v0c3 0 5 -2 5 -5v0v-22v0c0 -3 -2 -6 -5 -6v0h-47c0 -2 1 -6 1 -8
c0 -19 -12 -37 -27 -46c6 2 14 4 20 4c24 0 34 -14 54 -14c18 0 30 8 35 15v0c1 1 3 2 5 2s4 -2 5 -4v0v0v0l15 -37v0c0 -1 1 -2 1 -3z" />
<glyph glyph-name="uniF19B" unicode="&#xf19b;" horiz-adv-x="384"
d="M328 332c35 -35 56 -82 56 -135c0 -106 -86 -192 -192 -192s-192 86 -192 192c0 51 20 98 53 132c2 3 6 6 10 6c3 0 5 -1 7 -3v0h1v0l21 -19v-1v0v0c2 -2 4 -4 4 -7s-2 -7 -4 -9v0c-25 -26 -41 -60 -41 -99c0 -78 63 -141 141 -141s141 63 141 141c0 38 -15 73 -40 98
c-3 2 -5 6 -5 10c0 3 1 5 3 7v0v0v1l21 19v0h1v0c2 2 4 3 7 3s6 -1 8 -3v0zM178 127c-6 0 -11 5 -11 11v0v0v230v0v0c0 6 5 11 11 11v0h28v0v0c6 0 11 -5 11 -11v0v0v-230v0v0c0 -6 -5 -11 -11 -11v0v0h-28v0v0v0v0z" />
<glyph glyph-name="uniF19C" unicode="&#xf19c;" horiz-adv-x="397"
d="M388 313c5 0 9 -3 9 -8v-226v0c0 -5 -4 -8 -9 -8c-2 0 -4 0 -6 2l-146 84v-78v0c0 -5 -3 -8 -8 -8c-2 0 -4 0 -6 2l-171 99v-119v-2c0 -7 -6 -13 -13 -13l-1 1h-23h-1c-7 0 -12 4 -13 11v0v2v0v0v280v0c0 7 6 13 13 13v1h25v0c7 0 13 -6 13 -13v-1v0v-120l170 99
c2 2 5 2 7 2c5 0 8 -3 8 -8v-78l146 84c2 2 4 2 6 2z" />
<glyph glyph-name="uniF19D" unicode="&#xf19d;" horiz-adv-x="325"
d="M324 109c3 -5 1 -11 -4 -14v0l-166 -96v0c-5 -3 -12 -1 -15 4v1l-137 238v0h-1c-1 2 -1 4 -1 6v0v65v0c0 4 2 7 5 9l109 63v0v0l1 1v0c3 1 6 1 9 -1v0l57 -32v0c2 -1 3 -2 4 -4h1l137 -239v0zM93 298c9 5 12 18 7 27s-18 12 -27 7s-12 -18 -7 -27s18 -12 27 -7z" />
<glyph glyph-name="uniF19E" unicode="&#xf19e;" horiz-adv-x="395"
d="M393 100c3 -5 2 -12 -3 -15v0l-167 -96v0c-5 -3 -11 -1 -14 4v1l-7 12l153 88v0c5 3 7 10 4 15v0v0l-104 179l-45 79l41 -24v0c2 -1 3 -2 4 -4v0l138 -238v0v-1zM320 104v0l-166 -96v0c-5 -3 -12 -1 -15 4v1l-137 238v0h-1c-1 2 -1 5 -1 7v0v65v0c0 4 2 7 5 9l109 62v0v1
h1v0c3 1 6 1 9 -1v1l57 -33v0c2 -1 3 -2 4 -4h1l137 -239v0h1c3 -5 1 -12 -4 -15zM93 307c9 5 12 18 7 27s-18 12 -27 7s-12 -18 -7 -27s18 -12 27 -7z" />
<glyph glyph-name="uniF19F" unicode="&#xf19f;" horiz-adv-x="414"
d="M414 268v0v-188c0 -5 -4 -10 -9 -10h-67v79v0h-26h-210h-25v0v-79h-68v0c-5 0 -9 5 -9 10v188v0c0 5 4 9 9 9v0h68v0v110c0 5 4 10 9 10h242c5 0 10 -5 10 -10v-110v0v0h67c5 0 9 -4 9 -9zM312 235v0v127c0 5 -4 9 -9 9h-192v0c-5 0 -9 -4 -9 -9v-127h210zM103 -3v126
h209v-126c0 -5 -5 -10 -10 -10h-190c-5 0 -9 5 -9 10z" />
<glyph glyph-name="uniF1A0" unicode="&#xf1a0;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51c34 0 66 13 90 33l-198 198c-20 -24 -33 -56 -33 -90c0 -78 63 -141 141 -141zM300 102c20 24 33 56 33 90c0 78 -63 141 -141 141c-34 0 -66 -13 -90 -33z" />
<glyph glyph-name="uniF1A1" unicode="&#xf1a1;" horiz-adv-x="391"
d="M391 363v0v-32v0c0 -5 -4 -9 -9 -9h-373v0c-5 0 -9 4 -9 9v0v32v0c0 5 4 10 9 10v0h373c5 0 9 -5 9 -10v0zM359 296c5 0 9 -4 9 -9v0v-190c0 -11 -9 -21 -21 -21h-139v-27c5 -4 8 -10 8 -17c0 -12 -9 -21 -21 -21s-21 9 -21 21c0 7 4 13 9 17v27h-139
c-12 0 -22 10 -22 21v190v0v0c0 5 4 9 9 9h328z" />
<glyph glyph-name="uniF1A2" unicode="&#xf1a2;" horiz-adv-x="293"
d="M293 198v0v0v-3h-1c-1 -5 -6 -8 -11 -8v0v-1c-4 1 -8 2 -13 2c-28 0 -50 -22 -50 -50s22 -50 50 -50c5 0 9 1 13 2v-1c6 0 11 -4 12 -10v0v-67v0c0 -11 -10 -20 -21 -20h-65v0c-6 0 -12 6 -12 12c0 2 0 3 1 4v0c1 4 2 9 2 14c0 28 -22 50 -50 50s-50 -22 -50 -50
c0 -5 1 -10 2 -14v0v-1v0c0 -1 1 -2 1 -3c0 -6 -5 -12 -11 -12h-68h-2c-11 0 -20 9 -20 20v1v66v0v2c0 6 6 12 12 12c1 0 3 -1 4 -1v0c6 -3 12 -4 19 -4c28 0 50 22 50 50s-22 50 -50 50c-7 0 -14 -1 -20 -4c-1 0 -2 -1 -3 -1c-6 0 -12 6 -12 12v0v68v1c0 11 9 21 20 21v0
h75v0c14 1 25 12 25 27c0 6 -1 12 -5 17v0c-4 6 -6 13 -6 21c0 23 20 42 43 42s42 -19 42 -42c0 -8 -2 -15 -6 -21h1c-4 -5 -6 -11 -6 -17c0 -15 11 -26 25 -27v0h1h1h1h62v-1c11 0 20 -9 20 -20v0v-66z" />
<glyph glyph-name="uniF1A3" unicode="&#xf1a3;" horiz-adv-x="435"
d="M52 224c20 0 35 -15 35 -37s-19 -41 -41 -41c-24 0 -46 19 -46 53c0 39 21 73 53 96v0c1 0 2 1 3 1s2 -1 3 -2v0l22 -13v0c2 -1 2 -3 2 -5s-1 -4 -3 -5v0v0v0c-16 -9 -34 -30 -39 -48c2 1 7 1 11 1zM157 224c20 0 35 -15 35 -37s-19 -41 -41 -41c-24 0 -46 19 -46 53
c0 39 21 73 53 96h1c1 0 1 1 2 1s3 -1 4 -2v0l21 -13v0c2 -1 3 -3 3 -5s-2 -4 -4 -5v0v0v0c-16 -9 -33 -30 -38 -48c2 1 6 1 10 1zM284 238c24 0 46 -19 46 -53c0 -39 -21 -73 -53 -96v0c-1 0 -2 -1 -3 -1s-2 1 -3 2v0l-22 13v0c-2 1 -2 3 -2 5s1 4 3 5v0v0v0
c16 9 34 30 39 48c-2 -1 -6 -1 -10 -1c-20 0 -36 15 -36 37s19 41 41 41zM389 238c24 0 46 -19 46 -53c0 -39 -21 -73 -53 -96v0c-1 0 -1 -1 -2 -1s-3 1 -4 2v0l-21 13v0c-2 1 -3 3 -3 5s1 4 3 5v0h1v0c16 9 33 30 38 48c-2 -1 -6 -1 -10 -1c-20 0 -35 15 -35 37
s18 41 40 41z" />
<glyph glyph-name="uniF1A4" unicode="&#xf1a4;" horiz-adv-x="380"
d="M190 382c105 0 190 -85 190 -190s-85 -190 -190 -190s-190 85 -190 190s85 190 190 190zM190 130c34 0 62 28 62 62s-28 62 -62 62s-63 -28 -63 -62s29 -62 63 -62z" />
<glyph glyph-name="uniF1A5" unicode="&#xf1a5;" horiz-adv-x="355"
d="M354 337l1 -137c0 -2 -2 -5 -4 -6s-5 -2 -7 -1l-130 44c-3 1 -5 3 -5 6s1 6 3 8l31 22l5 3c-18 14 -41 23 -66 23c-59 0 -108 -48 -108 -107s49 -107 108 -107c36 0 69 17 89 47c3 4 9 6 13 3l45 -32c2 -1 4 -4 4 -6s0 -4 -1 -6c-34 -50 -91 -80 -151 -80
c-100 0 -181 81 -181 181s81 181 181 181c50 0 95 -20 128 -53l2 2l31 22c2 2 5 1 8 0s4 -4 4 -7z" />
<glyph glyph-name="uniF1A6" unicode="&#xf1a6;" horiz-adv-x="471"
d="M123 210c2 -3 3 -7 5 -10l-53 -24c-14 -7 -23 -22 -23 -39v-56h-41c-6 0 -11 6 -11 13v54c0 5 3 10 7 12l69 32c-16 10 -28 29 -28 52c0 33 23 59 51 59c8 0 15 -2 21 -5c-2 -4 -3 -9 -4 -13c-3 -10 -4 -19 -4 -28c0 -16 4 -33 11 -47zM287 270c-1 4 -1 8 -2 13
c-3 14 -10 27 -18 38h195v0v0c5 0 9 -4 9 -9v0v-33v0c0 -5 -4 -9 -9 -9v0v0h-175zM471 108v0v-33v0c0 -5 -4 -9 -9 -9v0v0h-114v4v11v36h114v0v0c5 0 9 -4 9 -9zM462 219c5 0 9 -4 9 -9v0v-33v0c0 -5 -4 -9 -9 -9v0v0h-126c-3 3 -7 6 -11 8l-53 25c2 4 5 7 7 11c1 2 1 5 2 7
h181v0v0zM314 153c5 -3 9 -9 9 -16v-56v-11c0 -9 -6 -16 -14 -16h-218c-8 0 -14 7 -14 16v11v56c0 7 4 14 9 16l61 28l24 11c-11 7 -19 17 -25 29c-5 11 -9 23 -9 36c0 8 1 14 3 21c8 30 32 52 60 52c29 0 53 -22 60 -53c2 -6 3 -13 3 -20c0 -12 -3 -24 -8 -34
c-6 -13 -14 -23 -25 -30l25 -12z" />
<glyph glyph-name="uniF1A7" unicode="&#xf1a7;" horiz-adv-x="431"
d="M431 336v-33v0c0 -5 -4 -9 -9 -9v0v0h-235v0c-5 0 -9 4 -9 9v0v33v0v0v0v0c0 5 4 9 9 9v0h235v0v0c5 0 9 -4 9 -9v0zM431 259v-32v0c0 -5 -4 -10 -9 -10v0v0h-235v0c-5 0 -9 5 -9 10v0v32v0v0v0v0c0 5 4 9 9 9v0h235v0v0c5 0 9 -4 9 -9v0zM127 336v-109v0v0
c0 -5 -4 -10 -9 -10v0v0h-109v0c-5 0 -9 5 -9 10v0v0v109v0c0 5 4 9 9 9h1h108v0c5 0 9 -4 9 -9v0zM431 157v-32v0c0 -5 -4 -9 -9 -9v0v0h-235v0c-5 0 -9 4 -9 9v0v32v0v0v0v0c0 5 4 9 9 9v1h235v-1v0c5 0 9 -4 9 -9v0zM431 81v-33v0c0 -5 -4 -9 -9 -9v0v0h-235v0
c-5 0 -9 4 -9 9v1v32v0v0v0v0c0 5 4 9 9 9v0h235v0v0c5 0 9 -4 9 -9v0zM127 157v-109v0v0c0 -5 -4 -9 -9 -9v0h-109v0c-5 0 -9 4 -9 9v0v0v109v0c0 5 4 10 9 10l1 -1h108v1c5 0 9 -5 9 -10v0z" />
<glyph glyph-name="uniF1A8" unicode="&#xf1a8;" horiz-adv-x="406"
d="M351 197c-2 -2 -5 -2 -7 -1l-131 42c-3 1 -5 3 -5 6s1 5 3 7l30 23l5 4c-19 14 -42 21 -67 21c-59 -1 -106 -50 -105 -109s51 -106 110 -105h10v0v0c7 0 14 -6 14 -13v0v0l1 -47v0c0 -3 -2 -7 -4 -9v0v0v-1l-2 -1v0c-1 0 -1 -1 -2 -1v0c-3 -1 -5 -2 -5 -2h-11
c-100 -2 -183 78 -185 178s78 182 178 184c50 1 96 -18 129 -50l2 1l30 23c2 2 5 2 8 1s4 -4 4 -7l3 -138c0 -2 -1 -4 -3 -6zM291 142h18l2 -99h-21l-1 72l-16 -17l-13 12zM365 145c28 1 41 -25 41 -50s-11 -51 -39 -52s-42 25 -42 50s12 51 40 52zM366 61c14 0 19 15 19 33
s-6 32 -20 32s-19 -15 -19 -33s6 -32 20 -32z" />
<glyph glyph-name="uniF1A9" unicode="&#xf1a9;" horiz-adv-x="372"
d="M363 313c5 0 9 -3 9 -8v-226v0c0 -5 -4 -8 -9 -8c-2 0 -4 0 -6 2l-145 84v-78v0c0 -5 -4 -8 -9 -8c-2 0 -4 0 -6 2l-192 111v0c-3 1 -5 4 -5 8c0 3 1 5 4 7v1l192 111c2 2 5 2 7 2c5 0 9 -3 9 -8v-78l145 84c2 2 4 2 6 2z" />
<glyph glyph-name="uniF1AA" unicode="&#xf1aa;" horiz-adv-x="339"
d="M48 115c25 0 45 -20 45 -45s-20 -44 -45 -44s-45 19 -45 44s20 45 45 45zM34 239c101 0 183 -81 184 -182v0v-18v0c-1 -8 -8 -14 -16 -15v-1h-31v0c-9 0 -17 7 -18 16v0v18v0c-1 65 -54 118 -119 118h-1v0h-17v0c-8 1 -15 7 -16 15v0v32v0c0 9 7 16 16 17v0h17v0h1z
M339 57v0v0v-18v0c-1 -8 -7 -14 -15 -15v-1h-32v0c-9 0 -16 7 -17 16v0v18v0c-1 132 -109 239 -241 239h-1v0h-17v0c-8 1 -15 8 -16 16v0v31v0c0 9 7 16 16 17v1h17v0h1c168 0 304 -136 305 -304z" />
<glyph glyph-name="uniF1AB" unicode="&#xf1ab;" horiz-adv-x="482"
d="M482 28v-2c0 -7 -6 -12 -13 -12v0v0h-457c-7 0 -12 5 -12 12v1v0v25c0 7 5 12 12 12h39l169 293c4 8 12 13 21 13s17 -5 21 -13v0l169 -293h38v0c7 0 13 -5 13 -12v0v0v-24zM228 319l-29 -51h84l-29 51h-26zM169 217l-29 -51h202l-29 51h-144zM81 64h320l-30 51h-261z
" />
<glyph glyph-name="uniF1AC" unicode="&#xf1ac;" horiz-adv-x="379"
d="M204 251v110h53v-110h-53zM375 350c2 -2 4 -5 4 -9v-1v-324v0v0c0 -7 -5 -12 -12 -12v0h-39v169v0c0 6 -6 11 -12 11v0v0v0v0h-253v0h-1h-1v0c-5 -1 -10 -5 -10 -11v0v-1v0v0v0v-156v0v-12h-39v0c-7 0 -12 5 -12 12v0v168v49v135v0c0 7 5 12 12 12v0v0h67v0c2 0 3 0 5 -2
c1 -1 2 -2 2 -3v0v-130v0c0 -6 6 -12 12 -12v0h175h1c7 0 13 5 13 12v0v130v0c0 1 1 3 2 4s3 1 4 1v0v0v0h46v0c4 0 7 -2 9 -4l27 -26v0z" />
<glyph glyph-name="uniF1AD" unicode="&#xf1ad;" horiz-adv-x="358"
d="M298 252c33 0 60 -27 60 -60s-27 -60 -60 -60c-7 0 -14 2 -21 4l-157 -91v-3c0 -33 -27 -61 -60 -61s-60 28 -60 61s27 60 60 60c13 0 26 -5 36 -12l144 84c-2 6 -2 12 -2 18s0 12 2 18l-145 84c-10 -7 -22 -12 -35 -12c-33 0 -60 27 -60 60s27 61 60 61s60 -28 60 -61
v-4l156 -90c7 3 14 4 22 4z" />
<glyph glyph-name="uniF1AE" unicode="&#xf1ae;" horiz-adv-x="384"
d="M356 130c15 0 28 -12 28 -27s-13 -28 -28 -28c-10 0 -19 6 -24 15h-80l-35 -61c2 -4 3 -7 3 -12c0 -15 -12 -28 -27 -28s-28 13 -28 28c0 5 1 9 3 13l-34 60h-78c-5 -7 -14 -12 -23 -12c-15 0 -27 12 -27 27s12 28 27 28c2 0 5 0 7 -1l35 60l-35 60c-4 -2 -8 -3 -12 -3
c-15 0 -28 13 -28 28s13 27 28 27c10 0 19 -5 24 -14h79l37 63c-3 4 -5 9 -5 14c0 15 13 28 28 28s27 -13 27 -28c0 -6 -1 -11 -4 -15l36 -62h78c5 7 13 12 22 12c15 0 28 -13 28 -28s-13 -27 -28 -27c-2 0 -5 0 -7 1l-34 -60l35 -60c4 2 8 2 12 2z" />
<glyph glyph-name="uniF1AF" unicode="&#xf1af;" horiz-adv-x="344"
d="M172 394l172 -99v0v-118c-1 -98 -76 -178 -172 -188c-96 10 -171 90 -172 188v0v118v0l172 100v-1zM172 41c67 10 120 66 121 136v0v6h-121v152l-121 -70v-82h121v-142z" />
<glyph glyph-name="uniF1B0" unicode="&#xf1b0;" horiz-adv-x="441"
d="M441 250v0v-216c0 -11 -9 -20 -20 -20v0v0h-401v0c-11 0 -20 9 -20 20v0v216v0c1 10 10 18 20 18h31c32 61 97 102 170 102s137 -41 169 -102h31v0c10 0 19 -8 20 -18zM112 268h217c-26 31 -64 51 -108 51s-83 -20 -109 -51z" />
<glyph glyph-name="uniF1B1" unicode="&#xf1b1;" horiz-adv-x="425"
d="M95 33c0 20 10 30 30 30s31 -10 31 -30s-11 -30 -31 -30s-30 10 -30 30zM307 33c0 20 10 30 30 30s30 -10 30 -30s-10 -30 -30 -30s-30 10 -30 30zM333 165v0h-200v-25h270v0c5 0 9 -3 12 -6s5 -7 5 -12v0v-15v0v-1v-2v0c-1 -9 -8 -14 -17 -15v0h-303v0v0
c-5 0 -9 2 -12 5s-6 7 -6 12v0v224h-63v0v0h-1c-5 0 -10 2 -13 5s-5 8 -5 13v0v17v0c1 4 3 9 6 12s8 4 12 4v0h1v0h97v0v0c5 0 9 -2 12 -5s5 -8 5 -13v0v-33h54h146h75v0c5 0 9 -2 12 -5s5 -8 5 -13c0 -3 0 -5 -1 -7v0l-75 -130v0c-3 -7 -9 -10 -16 -10z" />
<glyph glyph-name="uniF1B2" unicode="&#xf1b2;" horiz-adv-x="462"
d="M74 129l44 45l55 -55l-54 -54c-4 -7 -12 -12 -21 -12v0h-87v0c-5 1 -9 5 -10 10h-1v56h1c1 6 6 11 12 11c1 0 2 -1 3 -1h58zM460 290c2 -1 2 -3 2 -5v0c0 -2 0 -4 -2 -5l-95 -69c-2 -1 -5 -1 -7 0s-4 4 -4 6v30h-53l-38 -37l-54 54l54 54v0c4 3 10 6 15 6v0h76v29
c0 2 2 5 4 6s4 0 6 -1zM459 104c2 -1 3 -3 3 -5v0c0 -2 -1 -4 -3 -5l-95 -68c-2 -1 -5 -2 -7 -1s-3 4 -3 6v29h-77v0c-5 0 -10 3 -14 6v0l-189 189h-58c-1 0 -2 -1 -3 -1c-6 0 -12 5 -13 11v0v56v0c1 5 6 9 11 10v0h87v0c9 0 17 -5 21 -12l182 -182h53v30c0 2 1 5 3 6
s5 1 7 0z" />
<glyph glyph-name="uniF1B3" unicode="&#xf1b3;" horiz-adv-x="399"
d="M390 78c12 -12 13 -31 1 -43c-7 -7 -18 -10 -27 -8c2 -9 -1 -19 -8 -26c-12 -12 -30 -11 -42 1s-12 29 -1 41l-45 45v-31c-19 -15 -42 -24 -68 -24s-50 9 -69 24v31l-45 -45c11 -12 11 -30 -1 -42s-30 -12 -42 0c-7 7 -10 17 -8 26c-9 -2 -19 2 -26 9c-12 12 -12 30 0 42
c12 11 30 12 42 1l46 46c-13 19 -20 42 -20 67s7 48 20 67l-46 46c-12 -11 -30 -11 -42 1s-12 31 0 43c7 7 17 10 26 8c-2 9 1 19 8 26c12 12 31 11 43 -1s12 -29 1 -41l46 -46c19 13 42 20 67 20s48 -7 67 -20l46 46c-11 12 -10 30 1 42c12 12 30 12 42 0
c7 -7 11 -17 9 -26c9 2 18 -2 25 -9c12 -12 12 -30 0 -42s-29 -12 -41 -1l-46 -46c13 -19 20 -42 20 -67s-7 -48 -20 -67l46 -46c12 11 29 10 41 -1zM166 146c13 0 24 10 24 23s-11 24 -24 24s-23 -11 -23 -24s10 -23 23 -23zM233 146c13 0 24 10 24 23s-11 24 -24 24
s-23 -11 -23 -24s10 -23 23 -23z" />
<glyph glyph-name="uniF1B4" unicode="&#xf1b4;"
d="M262 227c10 0 17 -3 23 -10s9 -14 9 -23s-3 -18 -8 -24s-13 -9 -23 -9c-6 0 -10 1 -15 3s-10 4 -14 7s-9 6 -13 10s-8 8 -11 12l11 11s8 8 12 11s9 7 14 9s10 3 15 3zM151 204l11 -11c-3 -4 -6 -8 -10 -12s-9 -7 -13 -10s-9 -5 -14 -7s-10 -3 -15 -3c-10 0 -17 3 -23 9
s-8 14 -8 23s3 17 8 24s13 10 22 10c5 0 10 -1 15 -3s9 -6 14 -9s9 -7 13 -11zM333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM326 166c3 9 5 19 5 29s-2 19 -5 28s-7 17 -13 23s-14 11 -22 15s-17 6 -28 6
c-8 0 -17 -1 -24 -4s-14 -7 -20 -11s-12 -9 -17 -15s-11 -12 -16 -18c-5 6 -11 12 -16 18s-11 11 -17 15s-13 8 -20 11s-15 4 -24 4c-11 0 -21 -2 -29 -6s-15 -9 -21 -15s-10 -14 -13 -23s-5 -19 -5 -29s2 -20 5 -29s8 -17 14 -23s13 -11 21 -15s18 -6 29 -6c9 0 17 1 24 4
s13 5 19 9s12 10 17 15l16 16c5 -6 10 -11 16 -16s12 -11 18 -15s13 -6 20 -9s15 -4 23 -4c11 0 19 2 28 6s16 8 22 15s10 15 13 24z" />
<glyph glyph-name="uniF1B5" unicode="&#xf1b5;"
d="M232 355h137v-326zM0 355h136l-136 -326v326zM125 94l59 141l87 -206h-57l-26 65h-63z" />
<glyph glyph-name="uniF1B6" unicode="&#xf1b6;" horiz-adv-x="377"
d="M199 264h7c1 0 1 1 3 1c-1 10 0 21 -2 31c-2 12 -11 20 -24 22c-20 3 -41 -8 -46 -29c-2 -7 -6 -9 -13 -8c-13 2 -26 3 -39 5c-9 1 -11 4 -9 13c6 27 22 47 47 58c38 17 75 18 113 1c25 -11 38 -31 39 -58c1 -35 2 -69 1 -104c0 -19 4 -36 17 -51c5 -6 5 -10 -1 -15
c-11 -9 -22 -20 -33 -29c-6 -5 -12 -5 -17 1c-9 9 -16 18 -25 27c-5 -5 -11 -9 -17 -14c-21 -17 -45 -22 -70 -19c-39 4 -62 30 -63 70c-1 44 22 74 66 87c21 6 44 9 66 11zM198 163c13 20 10 41 10 64c-11 -1 -22 -2 -33 -4c-26 -5 -40 -23 -38 -50c1 -20 15 -32 34 -29
c12 2 21 9 27 19zM318 85c6 2 11 0 14 -5s2 -10 -3 -14c-7 -5 -15 -10 -22 -14c-41 -24 -85 -37 -126 -38c-50 0 -88 14 -123 38c-19 13 -35 28 -53 42c-5 4 -6 9 -3 13s7 5 13 2c18 -9 36 -19 54 -28c28 -14 57 -25 89 -28c26 -2 52 0 77 5c27 5 53 14 78 25c2 1 3 1 5 2z
M357 124c18 -2 21 -6 19 -24c-2 -19 -9 -35 -22 -49c-2 -2 -3 -4 -5 -4c-3 0 -7 -1 -9 1s-3 6 -2 9c2 8 5 15 7 23c1 4 2 9 3 13s0 6 -4 6h-10v0c-9 -1 -17 -2 -26 -3c-5 -1 -8 0 -10 4c-2 5 0 9 4 12c17 12 35 14 55 12z" />
<glyph glyph-name="uniF1B7" unicode="&#xf1b7;" horiz-adv-x="338"
d="M223 355c34 -17 57 -51 57 -89h-222c0 38 23 72 57 89l-18 32c-1 2 0 3 2 4s3 1 4 -1l18 -32c15 6 31 10 48 10s33 -4 48 -10l18 32c1 2 2 2 4 1s3 -2 2 -4zM118 307c5 0 10 4 10 9s-5 9 -10 9s-9 -4 -9 -9s4 -9 9 -9zM220 307c5 0 9 4 9 9s-4 9 -9 9s-10 -4 -10 -9
s5 -9 10 -9zM338 238v-103c0 -14 -11 -25 -25 -25s-24 11 -24 25v103c0 14 10 25 24 25s25 -11 25 -25zM279 258v0v-160c0 -10 -5 -18 -13 -23c-4 -2 -8 -3 -13 -3h-18v-55c0 -14 -11 -25 -25 -25c-2 0 -3 1 -5 1c-11 2 -19 12 -19 24v55h-34v-55c0 -12 -8 -22 -19 -24
c-2 0 -3 -1 -5 -1c-12 0 -22 9 -24 20c0 2 -1 3 -1 5v55h-18c-10 0 -19 5 -23 14c-2 4 -3 8 -3 12v160h220v0zM25 263c14 0 24 -11 24 -25v-103v-5c-2 -11 -12 -20 -24 -20c-5 0 -10 1 -14 4c-7 4 -11 12 -11 21v103c0 14 11 25 25 25z" />
<glyph glyph-name="uniF1B8" unicode="&#xf1b8;" horiz-adv-x="352"
d="M340 259c-69 -38 -58 -137 12 -163c-10 -21 -15 -30 -27 -49c-17 -26 -41 -60 -71 -60c-27 0 -35 18 -71 18s-43 -18 -70 -18c-30 0 -54 30 -71 56c-48 74 -53 160 -23 206c21 33 55 52 86 52c32 0 52 -18 78 -18s41 18 78 18c28 0 58 -16 79 -42zM233 330
c-14 -18 -39 -33 -63 -32c-4 24 7 48 21 65c15 18 40 32 62 34c4 -25 -7 -50 -20 -67z" />
<glyph glyph-name="uniF1B9" unicode="&#xf1b9;" horiz-adv-x="365"
d="M255 160c6 0 11 -1 15 -5s6 -11 6 -14h-45c2 6 7 19 24 19zM140 136c1 0 14 0 14 -18c0 -15 -9 -18 -16 -18h-41v36h43v0zM331 376c16 0 29 -10 34 -24v-320c-4 -12 -14 -21 -26 -24h-312c-13 3 -23 13 -27 25v318c4 15 18 25 34 25h297zM220 220v-19c0 -1 1 -2 2 -2h64
c1 0 3 1 3 2v19c0 1 -2 3 -3 3h-64c-1 0 -2 -2 -2 -3zM193 115c0 1 0 20 -11 32c-3 3 -6 6 -10 7c7 4 15 12 15 29c0 27 -17 43 -46 43h-80c-1 0 -3 -1 -3 -2v-155c0 -1 2 -2 3 -2h81c3 0 15 0 27 6c11 6 24 18 24 42zM312 117c0 1 4 33 -14 53c-10 11 -24 17 -42 17
c-32 0 -48 -17 -55 -31c-8 -15 -7 -31 -7 -31c0 -1 -2 -26 15 -44c11 -12 26 -18 46 -18v0h3c9 0 53 2 53 44c0 1 -1 3 -2 3h-28c-1 0 -2 0 -2 -1c-1 -1 0 -1 0 -2c0 0 0 -4 -4 -8s-10 -6 -19 -6v0c-2 0 -9 1 -14 4c-6 4 -9 10 -10 18h77c1 0 3 1 3 2zM148 181
c0 -15 -5 -16 -11 -16h-40v30h37h6s8 -1 8 -14z" />
<glyph glyph-name="uniF1BA" unicode="&#xf1ba;" horiz-adv-x="388"
d="M95 160c0 46 34 69 100 69s99 -23 99 -69s-33 -70 -99 -70s-100 24 -100 70zM333 252c42 -29 60 -64 54 -105c0 -16 -5 -31 -15 -45s-23 -26 -40 -36c-20 -12 -40 -20 -61 -25c-24 -6 -49 -9 -77 -9c-29 0 -55 3 -79 9c-37 14 -66 30 -86 50s-29 47 -29 82v179h58v-99
c38 26 87 40 149 39c49 -3 91 -16 126 -40zM211 64c32 1 60 12 84 34s35 43 33 66c-1 14 -6 27 -13 38s-16 20 -26 27s-21 12 -33 17s-24 7 -34 9s-20 2 -28 2c-44 -2 -78 -13 -101 -33s-33 -42 -31 -66s12 -43 28 -58s34 -25 54 -30s43 -7 67 -6z" />
<glyph glyph-name="uniF1BB" unicode="&#xf1bb;"
d="M308 376c33 0 61 -28 61 -61v-246c0 -33 -28 -61 -61 -61h-247c-33 0 -61 28 -61 61v246c0 33 28 61 61 61h247zM296 151v58v3l-2 4l-3 2c-4 3 -25 0 -31 5c-4 4 -5 11 -6 20c-2 17 -3 18 -6 24c-10 21 -37 37 -55 39h-50c-39 0 -72 -33 -72 -72v-83c0 -39 33 -71 72 -71
h82c39 0 71 32 71 71zM144 220c-8 0 -14 7 -14 14s6 13 14 13h39c8 0 14 -6 14 -13s-6 -14 -14 -14h-39zM224 166c7 0 14 -7 14 -14s-7 -13 -14 -13h-80c-8 0 -14 6 -14 13s6 14 14 14h80z" />
<glyph glyph-name="uniF1BC" unicode="&#xf1bc;" horiz-adv-x="348"
d="M174 192h174v-174h-174v174h-174v174h174v-174z" />
<glyph glyph-name="uniF1BD" unicode="&#xf1bd;"
d="M270 254h31v-57v-71h-28l-50 78l2 -78h-32v84v44h1h4h23l3 -5l47 -76zM333 376c20 0 36 -16 36 -36v-131l-63 50v0h-5h-31h-5v-5v-29l-39 31v1l-2 2h-3h-28h-5v-5v-40l-13 11c-1 3 -4 5 -6 8c-5 7 -11 12 -17 16c-12 7 -23 10 -43 10h-43h-3h-2h-5v-2v-10v-124l143 -115
h-163c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM137 251v0c1 0 4 -1 5 -2v0v0c1 -1 3 -1 4 -2s3 -1 4 -2s3 -2 4 -3c1 0 0 -1 1 -1l2 -2l2 -2l1 -1l2 -2v0v0c1 -1 2 -3 3 -4c8 -11 12 -24 12 -40c0 -39 -24 -64 -60 -64h-51v123v5h20h5h18h3c11 0 18 -1 25 -3z
M144 189c0 23 -11 36 -31 36h-14v-70h14c20 0 31 12 31 34z" />
<glyph glyph-name="uniF1BE" unicode="&#xf1be;"
d="M166 219c9 -19 45 -93 45 -93l129 35v-118c0 -1 -1 -1 -2 -2s-2 -2 -3 -2h-303c-1 0 -2 1 -3 2s-1 1 -1 2v31l169 48l-48 101c82 18 123 11 165 -23c5 -5 3 -8 0 -9l-67 -16l-25 50c-19 3 -46 -2 -56 -6zM335 348c1 0 2 -1 3 -1c1 -1 2 -2 2 -3v-105l-1 1
c-87 38 -186 21 -206 15c0 1 -15 33 -15 33h-56l20 -46c-23 -7 -48 -25 -54 -30v132c0 1 1 2 2 3c1 0 1 1 2 1h303zM68 131c-13 -3 -12 6 -12 6c-3 55 33 71 41 73l31 -63s-47 -13 -60 -16zM338 376c17 0 31 -14 31 -31v-306c0 -17 -14 -31 -31 -31h-307
c-17 0 -31 14 -31 31v306c0 17 14 31 31 31h307zM350 43v301c0 8 -7 14 -15 14h-303c-8 0 -14 -6 -14 -14v-301c0 -8 6 -14 14 -14h303c8 0 15 6 15 14z" />
<glyph glyph-name="uniF1BF" unicode="&#xf1bf;" horiz-adv-x="436"
d="M436 253v-173c0 -4 -1 -6 -6 -6h-106c-4 0 -5 1 -5 5v23c0 4 1 5 5 5h62c4 0 5 1 5 5v16h-5h-62c-4 0 -5 2 -5 6v120c0 4 1 5 5 5h107h4c0 -2 1 -4 1 -6zM387 161c3 0 4 2 4 5v49v11h-25c-1 0 -2 -3 -2 -4v-57c0 -3 1 -4 4 -4h19zM300 259c4 0 5 -1 5 -5v-175v-5h-5h-106
c-4 0 -5 1 -5 5v28h5h62c4 0 5 1 5 5v11s-1 6 -6 6c-20 0 -40 -1 -61 -1c-4 0 -5 2 -5 6v120c0 4 1 5 5 5h106zM261 164v59c0 1 -2 3 -3 3h-25c0 -21 1 -41 1 -62c0 -1 1 -3 2 -3h22c1 0 3 2 3 3zM72 305v5h44v-193h-4h-107c-4 0 -5 1 -5 5v132c0 4 1 5 5 5h61c7 0 6 -1 6 6
v40zM67 150c4 0 5 1 5 5v66v5h-27v-74c0 -1 2 -2 3 -2h19zM171 259c3 0 4 0 4 -3v-137v-2h-26h-14c-4 0 -4 1 -4 5v94v38c0 4 0 5 4 5h36zM134 276c-1 0 -3 2 -3 3v31h44v-17v-13c0 -3 0 -4 -3 -4h-38z" />
<glyph glyph-name="uniF1C0" unicode="&#xf1c0;" horiz-adv-x="371"
d="M186 378c102 0 185 -84 185 -186s-83 -186 -185 -186s-186 84 -186 186s84 186 186 186zM308 292c-3 -5 -29 -39 -88 -63c4 -8 7 -14 10 -22c1 -3 3 -6 4 -9c53 7 105 -4 110 -5c0 37 -14 72 -36 99zM186 350c-13 0 -26 -1 -38 -4c4 -6 34 -45 60 -93c56 21 80 53 83 57
c-28 25 -65 40 -105 40zM118 335c-44 -21 -78 -62 -88 -111c7 0 73 0 147 20c-26 47 -55 85 -59 91zM27 192c0 -41 16 -78 41 -106c4 6 47 78 129 104c2 1 4 1 6 2c-4 9 -8 18 -13 27c-79 -24 -156 -22 -163 -22v-5zM186 33c22 0 42 5 61 13c-2 14 -11 62 -33 120h-1
c-89 -31 -122 -93 -125 -99c27 -21 61 -34 98 -34zM274 60c36 24 61 63 68 107c-5 2 -49 14 -99 6c21 -57 29 -103 31 -113z" />
<glyph glyph-name="uniF1C1" unicode="&#xf1c1;" horiz-adv-x="384"
d="M144 143h240l-67 -115h-240zM376 149l-132 1l-121 208l133 -1zM120 349l66 -115l-120 -208l-66 115z" />
<glyph glyph-name="uniF1C2" unicode="&#xf1c2;" horiz-adv-x="396"
d="M117 376l81 -68l-117 -72l-81 64zM0 171l81 65l117 -73l-81 -68zM198 163l118 73l80 -65l-116 -76zM396 300l-80 -64l-118 72l82 68zM198 148l82 -68l35 23v-25l-117 -70l-116 70v25l35 -23z" />
<glyph glyph-name="uniF1C3" unicode="&#xf1c3;" horiz-adv-x="335"
d="M33 315c-9 0 -17 -2 -23 -5l-4 -2l1 1l73 72v0l-1 -2c-3 -5 -5 -12 -5 -19v0c0 -9 1 -42 1 -42c0 -2 -2 -3 -4 -3h-38v0zM325 322c5 -27 12 -135 9 -171c-5 -57 -14 -90 -18 -101c-18 -56 -33 -58 -77 -58c-56 0 -73 8 -73 53c0 49 24 50 63 49c6 0 -1 -5 -1 -15
s4 -13 -1 -13c-11 0 -27 2 -27 -14c0 -19 10 -19 34 -19c30 0 35 4 35 31c0 45 -13 51 -30 53c-19 2 -38 6 -47 9c-23 8 -22 38 -22 47c0 1 -2 1 -2 0c0 -12 -1 -29 -7 -48c-2 -5 -3 -9 -3 -9c-7 -15 -20 -10 -39 -8s-61 11 -79 19c-8 4 -11 7 -15 16c-11 22 -22 95 -23 105
c-2 13 -2 20 -2 20c0 8 1 17 6 24c3 3 5 6 10 8s11 4 19 4h38c8 0 15 6 15 14c0 0 -1 9 -1 18v24c0 8 2 13 5 17c4 6 13 11 20 13c9 3 45 4 68 -5c9 -4 16 -13 18 -24c13 0 36 0 55 -2c24 -3 42 -7 51 -10s18 -11 21 -27zM249 203c10 0 19 -3 27 -6c0 11 -2 28 -20 29
c-16 1 -21 -13 -22 -24c5 1 10 1 15 1z" />
<glyph glyph-name="uniF1C4" unicode="&#xf1c4;"
d="M348 376c11 0 21 -9 21 -20v-328c0 -11 -10 -20 -21 -20h-94v142h48l7 56h-55v36c0 16 5 27 28 27h29v49c-5 1 -23 3 -43 3c-42 0 -71 -26 -71 -74v-41h-48v-56h48v-142h-177c-11 0 -20 9 -20 20v328c0 11 9 20 20 20h328z" />
<glyph glyph-name="uniF1C5" unicode="&#xf1c5;"
d="M333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM110 133c33 0 60 27 60 60s-27 60 -60 60s-60 -27 -60 -60s27 -60 60 -60zM261 133c33 0 60 27 60 60s-27 60 -60 60s-59 -27 -59 -60s26 -60 59 -60z" />
<glyph glyph-name="uniF1C6" unicode="&#xf1c6;" horiz-adv-x="350"
d="M350 -18h-65v1h-92v66l73 36l-9 18l-64 -33v25l43 22l-10 18l-33 -18v43h-46v-67l-33 23l-11 -16l44 -31v-73v-13h-147l175 419z" />
<glyph glyph-name="uniF1C7" unicode="&#xf1c7;" horiz-adv-x="415"
d="M137 239l67 -67l155 154c3 3 6 4 10 4s6 -1 9 -4l33 -32c5 -5 5 -14 0 -19l-197 -197c-3 -3 -6 -4 -10 -4v0v0h-1c-3 0 -6 2 -8 4l-110 110c-5 5 -5 14 0 19l33 32c3 3 5 4 9 4s7 -1 10 -4zM399 227v-1c19 -19 19 -49 0 -68l-158 -159c-19 -19 -50 -19 -69 0l-158 159
c-19 19 -19 49 0 68l158 159c19 19 50 19 69 0l72 -72l-108 -107l-50 50c-7 7 -17 12 -27 12s-20 -5 -27 -12l-32 -32c-7 -7 -11 -17 -11 -27s4 -20 11 -27l109 -109c5 -5 11 -8 18 -10l2 -1h7c10 0 20 4 27 11z" />
<glyph glyph-name="uniF1C8" unicode="&#xf1c8;"
d="M333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM215 350c-55 0 -99 -44 -99 -99c0 -36 20 -68 49 -85c14 28 43 47 77 47c20 0 39 -7 54 -19c11 16 18 36 18 57c0 55 -44 99 -99 99zM30 208
c0 -41 22 -77 54 -98c9 22 31 36 56 36c6 0 11 0 17 -2c1 4 3 7 4 11c-33 19 -56 55 -56 96c0 28 11 53 28 72c-58 -7 -103 -55 -103 -115zM140 33c29 0 52 23 52 52s-23 52 -52 52s-52 -23 -52 -52s23 -52 52 -52zM242 50c42 0 77 34 77 76s-35 77 -77 77
c-38 0 -69 -27 -75 -63c20 -10 34 -31 34 -55c0 -7 -2 -14 -4 -21c13 -9 28 -14 45 -14z" />
<glyph glyph-name="uniF1C9" unicode="&#xf1c9;" horiz-adv-x="399"
d="M200 387c110 0 199 -90 199 -200c0 -88 -57 -163 -136 -189c-10 -2 -14 4 -14 9v55c0 19 -6 31 -13 37c44 5 91 22 91 99c0 22 -7 39 -20 53c2 5 9 25 -2 53c0 0 -17 5 -55 -21c-16 4 -33 7 -50 7s-34 -3 -50 -7c-38 26 -55 21 -55 21c-11 -28 -4 -48 -2 -53
c-13 -14 -21 -31 -21 -53c0 -77 47 -94 91 -99c-6 -5 -10 -14 -12 -27c-11 -5 -41 -14 -59 17c0 0 -10 19 -30 20c0 0 -20 0 -2 -12c0 0 14 -6 23 -29c0 0 11 -39 67 -27v-34s-3 -11 -13 -9c-79 26 -137 101 -137 189c0 110 90 200 200 200z" />
<glyph glyph-name="uniF1CA" unicode="&#xf1ca;"
d="M57 184c-9 7 -16 16 -22 26c-12 22 -17 42 -17 62c0 15 4 30 12 42c10 12 22 18 37 18c11 0 21 -4 30 -10c9 -7 16 -15 21 -26c11 -22 17 -45 17 -67c0 -5 0 -11 -1 -18s-4 -15 -9 -22c-10 -10 -22 -15 -37 -16c-12 0 -22 4 -31 11zM91 100c-13 0 -29 -2 -49 -5
c-15 -3 -28 -7 -42 -13v99c15 -15 36 -23 62 -23c6 0 12 0 18 1l-3 -9s-2 -8 -2 -13c0 -8 1 -15 5 -21c3 -6 7 -11 11 -16zM106 84c21 -14 36 -27 46 -37c9 -10 14 -23 14 -37v-1h-140c-14 0 -26 12 -26 26v15c3 4 6 8 9 11c5 4 11 8 16 10s9 4 12 5c12 4 24 5 35 7
c12 1 19 1 22 1h12zM343 375c14 0 26 -12 26 -26v-28v-286c0 -14 -12 -26 -26 -26h-145c2 7 3 15 3 23c0 19 -5 34 -13 46c-9 12 -18 22 -30 32l-19 15c-3 3 -6 6 -9 10s-5 8 -5 14s2 11 5 16c3 4 6 9 9 12c6 5 12 9 17 14s9 10 13 16c8 12 13 28 13 48c0 11 -2 21 -4 29
c-3 8 -6 15 -10 21s-8 12 -12 16s-9 7 -12 9h34l35 20h-111c-15 0 -31 -2 -48 -5c-17 -4 -33 -12 -49 -25c-2 -2 -3 -4 -5 -6v7v28c0 14 12 26 26 26h65h93h93h66zM363 261v29h-58v58h-28v-58h-59v-29h59v-58h28v58h58z" />
<glyph glyph-name="uniF1CB" unicode="&#xf1cb;"
d="M333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM200 178l70 119h-31l-29 -57c-8 -16 -15 -30 -21 -43h-1c-6 14 -12 27 -20 43l-30 57h-30l65 -119v-88h27v88z" />
<glyph glyph-name="uniF1CC" unicode="&#xf1cc;" horiz-adv-x="476"
d="M459 222c13 -16 18 -36 16 -57c-2 -24 -12 -47 -30 -62c-17 -14 -41 -23 -71 -23c-22 0 -45 4 -64 15v-10h-310v76h15v66h-15v77h116v-55c19 7 45 7 62 -6v9h29v40h88v-31l8 43h160c-1 -27 -3 -55 -4 -82zM227 272v-32h48v32h-48zM195 105v0v36h-16v54c0 11 -5 39 -37 39
c-22 0 -36 -12 -46 -28v78h-76v-37h15v-106h-15v-36h83v36h-7v23c0 34 24 42 24 21v-44h-8v-36h83zM290 105v36h-15v90h-76v-36h15v-54h-15v-36h91zM374 100c53 0 81 33 81 67c2 45 -26 62 -60 62c-13 0 -26 -4 -38 -9l2 16h81l2 48h-122l-17 -92l44 -6c6 7 13 9 18 9
c13 0 19 -14 18 -28c-1 -15 -10 -29 -23 -29c-8 0 -18 4 -13 17c4 19 -7 28 -24 28c-26 0 -35 -31 -24 -51c10 -19 40 -32 75 -32z" />
<glyph glyph-name="uniF1CD" unicode="&#xf1cd;"
d="M276 216c0 14 -3 28 -9 40h102v-215c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v215h102c-6 -12 -10 -26 -10 -40c0 -51 41 -92 92 -92s92 41 92 92zM333 379c20 0 36 -16 36 -36v-72h-111c-17 22 -44 37 -74 37s-56 -15 -73 -37h-111v72c0 20 16 36 36 36h297z
M29 288v0v72c-8 -3 -13 -11 -13 -20v-52h13zM51 288v74h-12v-74h12zM73 288v74h-12v-74h12zM95 340v22h-13v-74h13v22v30zM350 310v30c0 12 -10 22 -22 22h-35c-12 0 -22 -10 -22 -22v-30c0 -12 10 -22 22 -22h35c12 0 22 10 22 22zM184 135c-45 0 -81 36 -81 81
s36 81 81 81s81 -36 81 -81s-36 -81 -81 -81zM184 280c-36 0 -64 -28 -64 -64s28 -65 64 -65s65 29 65 65s-29 64 -65 64z" />
<glyph glyph-name="uniF1CE" unicode="&#xf1ce;" horiz-adv-x="357"
d="M340 98c29 -24 22 -67 -13 -81c-2 -1 -3 -2 -5 -3h-24c-17 7 -31 18 -35 38c-31 -7 -59 -1 -81 22c12 12 23 22 33 32c9 -3 18 -7 27 -7c12 0 21 8 25 19c4 12 1 22 -8 31c-24 24 -46 47 -70 71c-2 2 -6 4 -8 6c12 13 23 25 36 39c12 -13 22 -25 33 -36
c12 -12 22 -25 35 -36c25 -23 38 -49 32 -82c8 -4 17 -8 23 -13zM212 186c14 -12 25 -23 36 -33c-28 -28 -54 -56 -80 -82c-17 -17 -39 -24 -63 -21c-8 1 -11 -1 -14 -8c-5 -15 -17 -22 -31 -28h-22c-21 7 -33 21 -38 42v10c4 21 15 36 37 42c-5 30 1 56 23 77l35 -35
c-1 -1 -3 -3 -4 -5c-9 -13 -8 -29 4 -39s27 -11 39 1c24 23 48 47 72 71c3 3 5 6 6 8zM107 228c29 29 56 59 85 87c17 16 40 20 63 15h6c4 15 11 29 27 35c10 3 21 5 31 4c20 -2 36 -21 38 -43c2 -23 -10 -39 -41 -52c6 -30 -1 -56 -23 -78l-34 34c3 5 7 11 9 17
c3 12 -3 25 -14 31c-11 7 -24 6 -35 -4c-12 -11 -23 -23 -35 -35c-15 -14 -29 -29 -44 -44zM38 275c-28 10 -41 30 -35 60c4 19 22 33 41 35c25 2 39 -9 53 -40c29 5 53 -2 73 -22l-35 -35c0 0 -1 2 -3 3c-13 10 -29 8 -40 -4c-10 -12 -9 -27 2 -39c23 -24 47 -48 70 -72
c3 -3 4 -5 7 -8c-12 -11 -22 -22 -35 -35c-11 12 -23 24 -34 36c-12 12 -23 24 -35 35c-25 23 -37 51 -29 86z" />
<glyph glyph-name="uniF1CF" unicode="&#xf1cf;" horiz-adv-x="417"
d="M354 210c41 -10 63 -29 63 -68c0 -48 -40 -66 -99 -66c-83 0 -112 38 -127 84l-15 48c-11 35 -25 62 -67 62c-29 0 -59 -21 -59 -80c0 -46 24 -75 57 -75c37 0 62 28 62 28l15 -42s-26 -25 -80 -25c-67 0 -104 39 -104 112c0 75 37 120 107 120c64 0 96 -23 116 -85
l16 -48c11 -35 32 -60 80 -60c32 0 49 7 49 25c0 14 -8 23 -32 29l-33 8c-40 10 -55 31 -55 63c0 52 42 68 85 68c49 0 78 -18 82 -61l-48 -6c-2 21 -14 30 -37 30c-21 0 -34 -10 -34 -26c0 -14 6 -23 27 -28z" />
<glyph glyph-name="uniF1D0" unicode="&#xf1d0;"
d="M341 376c15 0 28 -11 28 -26v-316c0 -15 -13 -26 -28 -26h-314c-15 0 -27 11 -27 26v316c0 15 12 26 27 26h314zM109 62v176h-54v-176h54zM82 262c17 0 32 14 32 32c0 17 -15 32 -32 32c-18 0 -32 -15 -32 -32c0 -18 14 -32 32 -32zM314 62v0v97c0 47 -10 83 -65 83
c-27 0 -45 -14 -52 -28h-1v24h-52v-176h54v87c0 23 5 45 33 45s28 -26 28 -46v-86h55z" />
<glyph glyph-name="uniF1D1" unicode="&#xf1d1;"
d="M346 376c13 -5 23 -18 23 -33v-299c0 -20 -16 -36 -36 -36h-299c-16 0 -29 11 -34 25v321c3 10 10 18 20 22h326zM276 241v22h-68l-22 -84h-1l-22 84h-68v-22h7c3 0 6 -4 6 -6v-89c0 -2 -3 -6 -6 -6h-7v-21h54v21h-13v94v0l32 -115h24l32 115v0v-94h-12v-21h64v21h-7
c-3 0 -6 4 -6 6v89c0 2 3 6 6 6h7z" />
<glyph glyph-name="uniF1D2" unicode="&#xf1d2;" horiz-adv-x="454"
d="M375 187c-40 0 -73 32 -73 72s33 72 73 72s72 -32 72 -72s-32 -72 -72 -72zM147 238c0 43 22 65 65 65s65 -22 65 -65s-22 -65 -65 -65s-65 22 -65 65zM64 161c-32 0 -58 27 -58 59s26 58 58 58s59 -26 59 -58s-27 -59 -59 -59zM64 148c37 0 65 -32 65 -66v-23
c0 -3 -3 -6 -6 -6h-2h-113h-2c-3 0 -6 3 -6 6v23c0 34 27 66 64 66zM212 159c41 0 71 -37 71 -74v-25c0 -4 -2 -7 -6 -7h-2h-126h-2c-4 0 -7 3 -7 7v25c0 37 31 74 72 74zM375 170c46 0 79 -40 79 -82v-27c0 -4 -3 -8 -7 -8h-3h-139h-2c-4 0 -8 4 -8 8v27c0 42 34 82 80 82z
" />
<glyph glyph-name="uniF1D3" unicode="&#xf1d3;"
d="M185 272c45 0 82 -37 82 -82s-37 -82 -82 -82s-82 37 -82 82s37 82 82 82zM333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM185 66c69 0 124 55 124 124s-55 124 -124 124s-125 -55 -125 -124
s56 -124 125 -124z" />
<glyph glyph-name="uniF1D4" unicode="&#xf1d4;" horiz-adv-x="348"
d="M348 235c0 -83 -67 -136 -171 -137v-23c0 -28 -16 -54 -41 -65c-6 -3 -17 -5 -28 -5c-10 0 -22 2 -35 8v65c21 -15 41 -7 41 11v181h63v-113c30 0 112 8 112 78c0 62 -60 85 -115 85c-57 0 -114 -27 -114 -85c0 -18 9 -45 18 -53l-41 -43c-24 22 -37 66 -37 96
c0 85 72 144 174 144c104 0 174 -58 174 -144z" />
<glyph glyph-name="uniF1D5" unicode="&#xf1d5;" horiz-adv-x="399"
d="M282 373v0v-133c-7 6 -147 133 -152 138c23 8 46 13 70 13c29 0 56 -6 82 -18zM97 21v0c-37 23 -67 57 -83 97c2 2 76 69 83 75v-172zM0 192v0c0 75 42 143 109 177c2 -2 72 -65 75 -68c-3 -3 -172 -156 -177 -161c-5 17 -7 35 -7 52zM118 105v0h261
c-31 -63 -92 -106 -161 -112h-37c-22 2 -43 8 -63 17v95zM303 362v0c59 -36 96 -101 96 -170c0 -22 -4 -45 -11 -66h-85v236z" />
<glyph glyph-name="uniF1D6" unicode="&#xf1d6;" horiz-adv-x="399"
d="M200 392c110 0 199 -90 199 -200s-89 -200 -199 -200c-20 0 -39 3 -57 8c8 12 16 28 20 43c2 9 14 55 14 55c7 -13 27 -25 49 -25c64 0 108 59 108 137c0 59 -51 115 -127 115c-95 0 -142 -68 -142 -125c0 -34 13 -66 41 -77c5 -2 9 0 10 5c1 4 3 13 4 17c1 5 1 7 -3 11
c-8 9 -13 22 -13 39c0 50 37 95 98 95c54 0 83 -32 83 -76c0 -58 -25 -106 -63 -106c-21 0 -37 17 -32 38c6 25 18 53 18 71c0 16 -9 30 -27 30c-21 0 -39 -22 -39 -52c0 -19 7 -31 7 -31s-22 -93 -26 -109c-4 -15 -4 -32 -3 -46c-70 31 -120 101 -120 183
c0 110 90 200 200 200z" />
<glyph glyph-name="uniF1D7" unicode="&#xf1d7;" horiz-adv-x="435"
d="M424 291c27 -2 4 -60 -52 -75c1 -7 1 -15 1 -23v-1c0 -99 -80 -179 -187 -179s-186 79 -186 178v1c0 99 80 179 187 179c19 0 36 -3 53 -7v-105c-3 2 -6 4 -10 5c-46 16 -96 -7 -119 -45l-1 -1c-24 -39 -12 -83 33 -98c46 -16 95 7 119 45l1 1c8 13 12 27 12 40v0v145
c3 -1 6 -3 8 -4s4 -3 6 -4c24 -15 85 -53 135 -52z" />
<glyph glyph-name="uniF1D8" unicode="&#xf1d8;" horiz-adv-x="458"
d="M458 197c0 -18 -10 -35 -25 -45c1 -5 2 -10 2 -15c0 -76 -92 -138 -206 -138s-206 62 -206 138c0 5 0 11 1 16c-15 10 -24 26 -24 44c0 29 24 53 53 53c13 0 24 -5 34 -13c36 23 83 37 136 38l37 105l89 -22c6 16 22 27 40 27c24 0 43 -19 43 -43s-19 -43 -43 -43
s-43 19 -43 43l-75 18l-31 -85c50 -2 97 -16 131 -38h1c10 8 21 13 34 13c29 0 52 -24 52 -53zM299 129c18 0 32 14 32 32s-14 33 -32 33s-33 -15 -33 -33s15 -32 33 -32zM305 73c3 3 3 9 0 12s-9 3 -12 0c0 0 -20 -20 -65 -20c-44 0 -62 19 -62 20c-3 3 -9 4 -12 1
s-4 -9 -1 -12c1 -1 22 -25 75 -25s76 23 77 24zM131 161c0 -18 14 -32 32 -32s33 14 33 32s-15 33 -33 33s-32 -15 -32 -33z" />
<glyph glyph-name="uniF1D9" unicode="&#xf1d9;" horiz-adv-x="390"
d="M103 162c0 0 -20 3 -44 14l275 3c-25 -12 -48 -16 -48 -16h-74s-6 -1 -8 -4s-2 -9 -2 -9v-9c-11 8 -18 21 -24 21h-75zM25 166c-2 1 -4 2 -5 4c2 -1 3 -2 5 -4zM39 368v-182c-11 6 -17 11 -21 13v180c0 6 4 10 10 10h332c6 0 10 -4 10 -10v-180c-4 -3 -9 -7 -20 -13v182
h-311zM388 202c3 -2 1 -6 0 -8s-7 -17 -33 -34s-51 -27 -51 -27s16 -51 1 -89s-48 -48 -64 -48s-39 12 -39 34v77c6 -1 13 -2 21 -2c18 0 31 8 42 19s19 32 10 35s-12 -3 -20 -14c-7 -9 -22 -17 -44 -9c-3 1 -6 3 -9 5v9s0 6 2 9s7 4 8 4h74s23 3 48 15c1 1 3 1 4 2
c4 2 9 4 12 6c11 6 16 10 20 13l6 3c6 2 9 2 12 0zM265 124c-11 -11 -24 -19 -42 -19c-8 0 -15 1 -21 2c-8 2 -14 4 -14 4v-83s-24 -33 -40 -33s-48 9 -63 47s1 89 1 89s-25 11 -51 28c-4 2 -7 5 -10 7c-2 2 -3 3 -5 4c-14 12 -19 21 -19 23c-1 2 -3 6 0 8s7 2 13 0
c1 -1 2 -1 4 -2c4 -2 10 -7 21 -13c4 -2 7 -5 12 -7c2 -1 6 -2 8 -3c24 -11 44 -14 44 -14h75c6 0 13 -13 24 -21c3 -2 6 -4 9 -5c22 -8 37 0 44 9c8 11 11 17 20 14s1 -24 -10 -35zM251 272c26 0 47 -20 47 -46s-21 -47 -47 -47s-46 21 -46 47s20 46 46 46zM141 272
c26 0 47 -20 47 -46s-21 -47 -47 -47s-46 21 -46 47s20 46 46 46z" />
<glyph glyph-name="uniF1DA" unicode="&#xf1da;" horiz-adv-x="394"
d="M383 150c7 -15 11 -32 11 -49c0 -60 -49 -109 -109 -109c-19 0 -36 5 -51 13c-11 -2 -23 -3 -35 -3c-104 0 -188 84 -188 188c0 13 2 26 4 38c-10 16 -15 35 -15 55c0 60 49 109 109 109c21 0 41 -6 58 -17c10 2 21 3 32 3c104 0 188 -84 188 -188c0 -14 -1 -27 -4 -40z
M296 100c9 12 13 27 13 42c0 13 -3 24 -8 33s-12 16 -21 22s-19 11 -32 15c-12 4 -27 8 -42 11c-12 3 -21 5 -26 6s-10 4 -15 6s-8 6 -11 9s-4 7 -4 11c0 7 4 13 12 18s19 8 32 8c14 0 26 -2 32 -7c7 -5 12 -12 17 -21c4 -7 7 -12 11 -15s9 -5 16 -5c8 0 14 3 19 8
s8 11 8 18s-2 14 -6 21s-10 15 -18 21s-19 11 -31 15s-27 6 -44 6c-21 0 -39 -2 -55 -8s-29 -15 -37 -26s-12 -24 -12 -38c0 -15 4 -28 12 -38s19 -17 32 -23s29 -11 49 -15c14 -3 26 -5 35 -8c8 -3 15 -7 20 -12s7 -10 7 -17c0 -9 -5 -18 -14 -24c-10 -7 -22 -10 -38 -10
c-11 0 -20 2 -27 5s-12 7 -16 12s-8 11 -11 19c-3 7 -7 13 -11 17c-5 4 -10 5 -16 5c-8 0 -15 -2 -20 -7s-8 -11 -8 -18c0 -11 4 -22 12 -34c8 -11 18 -20 31 -27c18 -9 41 -14 68 -14c23 0 41 3 58 10s30 17 39 29z" />
<glyph glyph-name="uniF1DB" unicode="&#xf1db;" horiz-adv-x="390"
d="M173 165c98 -37 75 -98 23 -98s-89 32 -89 32l-30 -70c21 -11 43 -19 56 -23l-33 -8c-15 -4 -31 6 -35 21l-64 268c-4 16 6 31 21 35l77 19c-7 -8 -12 -17 -16 -26c0 -1 -1 -1 -1 -2c-1 -2 -1 -4 -2 -6c0 -1 -1 -2 -1 -3c-1 -2 -2 -4 -2 -6v-4c0 -2 -1 -4 -1 -6
c0 -1 -1 -2 -1 -3v-7v-3v-10s1 -6 1 -8v-1c0 -2 1 -6 2 -8v0c1 -2 1 -5 2 -7c0 -1 1 0 1 -1c1 -2 2 -5 3 -7v-1c1 -2 3 -4 4 -6c0 -1 1 0 1 -1c1 -2 3 -4 5 -6v-1c1 -2 3 -4 5 -6c0 -1 1 0 1 -1l6 -6v-1c2 -2 4 -2 6 -4c1 0 0 -2 1 -2c2 -2 5 -3 7 -5l1 -1
c15 -11 33 -20 52 -27zM390 97c4 -15 -7 -31 -22 -35l-56 -14c9 14 17 33 18 56c1 29 -10 60 -39 85v0c-2 1 -3 3 -5 4l-1 1c-2 1 -3 3 -5 4l-1 1c-2 1 -4 3 -6 4h-1c-2 1 -4 3 -6 4c-1 0 -1 1 -2 1l-6 3h-1c-2 1 -5 3 -8 4h-2l-6 3c-1 0 -1 1 -2 1l-9 3
c-100 33 -71 88 -20 85c54 -3 74 -25 74 -25l24 67c-2 1 -5 2 -7 3c-1 0 -1 1 -2 1c-2 1 -3 1 -5 2c-1 0 -1 1 -2 1c-2 1 -5 2 -7 3c-1 0 -1 1 -2 1c-1 1 -3 1 -4 2h-3c-1 1 -3 2 -4 2s-1 1 -2 1c-2 1 -3 0 -5 1c-1 0 -1 1 -2 1s-3 1 -4 1h-2c-2 0 -3 2 -5 2
c-7 2 -13 2 -17 3l56 13c16 4 30 -5 34 -21z" />
<glyph glyph-name="uniF1DC" unicode="&#xf1dc;" horiz-adv-x="379"
d="M302 224c4 1 8 4 12 4c7 0 14 0 20 -3c10 -5 11 -16 2 -22c-7 -5 -16 -8 -24 -11c-18 -7 -21 -13 -12 -30c15 -29 37 -51 70 -59c3 -1 9 -4 9 -6c0 -5 -3 -11 -6 -13c-11 -5 -23 -9 -35 -12c-7 -2 -10 -4 -12 -11c-3 -15 -6 -17 -20 -14c-23 5 -44 0 -63 -14
c-39 -28 -69 -27 -108 1c-19 14 -38 18 -61 13c-15 -3 -17 -1 -21 14c-1 6 -4 10 -11 11c-11 2 -24 6 -34 11c-4 2 -7 8 -8 13c0 2 7 7 11 8c36 10 57 34 72 66c3 8 0 13 -6 17c-6 3 -12 4 -18 7c-4 2 -8 4 -11 6c-7 4 -13 10 -9 19c3 8 14 12 23 9c5 -2 10 -4 15 -5
c7 -1 10 1 10 9c-1 18 -1 36 0 54c3 38 26 65 60 78c50 19 109 4 136 -44c9 -17 10 -35 11 -54c-1 -12 -1 -23 -2 -35c-1 -8 4 -9 10 -7z" />
<glyph glyph-name="uniF1DD" unicode="&#xf1dd;" horiz-adv-x="399"
d="M200 392c110 0 199 -90 199 -200c0 -71 -37 -133 -92 -168c-8 17 -19 32 -33 45c-29 26 -66 41 -105 41c-25 0 -48 -6 -70 -17c-18 -9 -34 -21 -47 -36c-33 36 -52 83 -52 135c0 110 90 200 200 200zM294 114c4 6 3 15 -3 19c-36 25 -77 38 -121 38c-25 0 -51 -4 -74 -13
c-7 -3 -11 -10 -8 -17s11 -11 18 -8c20 8 42 11 64 11c38 0 75 -11 106 -33c2 -2 4 -2 7 -2c4 0 8 1 11 5zM323 176c4 7 3 16 -4 20c-45 28 -96 43 -149 43c-29 0 -58 -4 -86 -13c-8 -3 -13 -11 -10 -19s11 -13 19 -10c25 8 51 12 77 12c47 0 93 -13 133 -38c2 -2 5 -2 8 -2
c5 0 9 2 12 7zM338 229c6 0 11 3 14 8c5 8 2 18 -6 23c-53 31 -114 48 -176 48c-34 0 -67 -5 -99 -14c-9 -3 -15 -12 -12 -21s12 -14 21 -11c29 9 60 13 90 13c56 0 112 -16 160 -44c3 -2 5 -2 8 -2zM225 16c6 -6 11 -13 15 -20c-13 -3 -26 -4 -40 -4c-32 0 -63 7 -90 21
c6 6 13 12 21 16c12 6 25 9 38 9c21 0 41 -8 56 -22z" />
<glyph glyph-name="uniF1DE" unicode="&#xf1de;" horiz-adv-x="425"
d="M420 109c6 -21 7 -44 0 -65c-15 -44 -45 -72 -92 -78c-30 -4 -56 5 -77 28c-17 19 -26 41 -28 66c0 4 0 8 -1 12c-4 21 -18 30 -39 27c-24 -3 -47 -8 -71 -7c-13 0 -26 4 -38 10c-19 10 -28 27 -31 48s0 42 4 63c2 8 3 16 4 25c1 17 -8 29 -21 39c1 1 3 0 4 0
c23 -3 39 -23 38 -46c-1 -22 -2 -43 3 -65c1 -4 2 -8 3 -11c4 -12 15 -14 26 -15c20 -1 40 3 60 6c10 2 18 3 29 5c-9 6 -17 11 -25 16c-40 24 -65 57 -73 104c-1 9 -4 17 -6 26c-5 26 -21 41 -47 45c-13 2 -25 1 -38 -1c-1 0 -3 -1 -4 0c-1 2 1 2 2 3c24 12 49 15 75 8
c14 -4 22 -15 28 -27c6 -13 9 -27 13 -41c1 -4 3 -8 4 -12c6 -20 19 -35 38 -44s39 -15 60 -18c2 0 4 -2 4 2c-1 11 -1 22 -2 33c-2 21 -14 35 -32 45c-13 8 -26 17 -38 27c-30 27 -42 60 -35 100v2h3c-1 -24 5 -45 23 -63c10 -10 22 -15 34 -21c32 -14 58 -35 77 -64
c9 -14 13 -29 16 -44c0 -1 1 -2 1 -4c7 13 18 23 26 34c14 20 12 37 -4 55c-12 13 -28 21 -44 28c-2 1 -5 2 -7 3c-21 8 -31 25 -29 48c0 3 0 5 2 8c1 -5 2 -9 3 -14c4 -17 13 -27 30 -31c25 -6 50 -16 69 -34c12 -11 20 -23 23 -39c2 -14 0 -26 -6 -38
c-4 -9 -10 -18 -14 -27c-5 -10 -4 -20 0 -30c3 -6 7 -9 14 -9c41 -2 75 -28 86 -68z" />
<glyph glyph-name="uniF1DF" unicode="&#xf1df;" horiz-adv-x="337"
d="M247 12v144h34v-179h-281v179h33l-2 -144h216zM53 35v36h169v-36h-169zM53 99l4 37l169 -17l-4 -36zM62 173l10 36l164 -46l-10 -36zM93 260l19 31l145 -87l-19 -32zM293 232l-30 -22l-98 138l29 22zM301 234l-28 167l36 6l28 -167z" />
<glyph glyph-name="uniF1E0" unicode="&#xf1e0;" horiz-adv-x="497"
d="M466 238c0 -20 -16 -36 -36 -36s-37 16 -37 36s17 36 37 36s36 -16 36 -36zM429 306c37 0 68 -31 68 -68s-31 -67 -68 -67l-64 -47c-2 -25 -24 -46 -50 -46c-24 0 -44 17 -49 40l-190 76c-8 -4 -17 -7 -26 -7c-28 0 -50 23 -50 51s22 50 50 50c24 0 44 -17 49 -40
l190 -76c8 4 17 7 26 7h5l42 60c0 37 30 67 67 67zM429 283c-25 0 -45 -20 -45 -45s20 -45 45 -45s45 20 45 45s-20 45 -45 45zM50 275c-20 0 -37 -17 -37 -37s17 -37 37 -37c3 0 5 -1 8 0l-15 7v0c-14 6 -22 23 -16 38s23 21 38 16v0l18 -7c-6 12 -19 20 -33 20zM315 166
c-3 0 -5 0 -8 -1l15 -6c15 -6 23 -24 17 -39s-24 -22 -39 -16c-6 2 -12 5 -18 7c6 -12 19 -19 33 -19c20 0 37 17 37 37s-17 37 -37 37z" />
<glyph glyph-name="uniF1E1" unicode="&#xf1e1;" horiz-adv-x="399"
d="M357 314c26 -34 42 -76 42 -122c0 -110 -89 -200 -199 -200c-78 0 -145 44 -178 109h87c41 0 70 22 70 58c0 76 -87 45 -87 72c0 13 10 18 29 18h32h29c17 0 36 -4 36 -22v-60c0 -44 35 -66 70 -66c36 0 69 22 69 66v147v0zM200 392c42 0 80 -13 112 -35v-191
c0 -13 -11 -24 -24 -24v0c-13 0 -24 11 -24 24v57c0 46 -24 65 -54 65h-98c-36 0 -65 -23 -65 -59c0 -18 8 -45 45 -52c30 -5 42 -4 42 -20s-17 -15 -40 -15h-88c-4 16 -6 33 -6 50c0 110 90 200 200 200v0z" />
<glyph glyph-name="uniF1E2" unicode="&#xf1e2;" horiz-adv-x="394"
d="M193 244c-24 -18 -47 -38 -74 -52c-4 -2 -8 -4 -13 -5c-12 -3 -20 -14 -20 -27c0 -12 9 -24 21 -27s25 2 31 13c7 15 20 25 33 34c5 4 7 3 11 -2c4 9 9 18 13 27c1 -1 1 -1 1 -2c-7 -25 -14 -52 -22 -77c-2 -6 -5 -10 -10 -13c-14 -9 -18 -28 -9 -43c9 -14 27 -19 42 -11
s21 26 14 41c-3 5 -3 11 -2 16c4 14 6 28 14 41c3 6 7 11 13 15c7 4 11 3 16 -3c6 -7 9 -15 8 -25c-1 -13 7 -25 19 -29s25 1 32 11c7 11 7 24 -2 34c-10 12 -21 23 -30 35c-16 21 -17 43 -4 66c7 12 15 25 22 38c6 11 15 21 26 27c10 5 19 6 29 0c6 -4 12 -7 19 -11
c15 -9 23 -22 23 -39v-168c0 -17 -8 -30 -22 -38c-51 -29 -101 -58 -152 -86c-15 -8 -30 -8 -45 0c-51 29 -102 57 -153 86c-14 8 -22 21 -22 37v170c0 16 7 29 21 37c51 29 103 58 155 87c13 7 28 7 42 0c8 -4 15 -8 23 -12c6 -3 8 -9 9 -16c1 -12 -1 -23 -7 -33
c-7 -12 -14 -25 -21 -37c-14 -22 -33 -36 -59 -40c-16 -3 -33 -1 -49 1c-12 1 -23 -5 -27 -16s0 -24 10 -30s23 -4 31 5c5 6 13 5 20 6c5 1 10 2 15 2c2 0 3 0 5 1c8 4 16 9 24 13z" />
<glyph glyph-name="uniF1E3" unicode="&#xf1e3;"
d="M333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM270 68v0v44c-14 -9 -28 -14 -42 -14c-8 0 -15 2 -21 6c-5 3 -8 6 -10 11s-2 15 -2 31v71h66v44h-66v70h-40c-2 -14 -4 -27 -9 -36s-11 -16 -19 -23
s-17 -12 -28 -16v-39h30v-97c0 -13 1 -22 4 -29s8 -13 15 -19s15 -11 25 -14s20 -5 33 -5c11 0 22 1 32 3s20 6 32 12z" />
<glyph glyph-name="uniF1E4" unicode="&#xf1e4;" horiz-adv-x="394"
d="M394 314c-11 -16 -24 -31 -40 -42v-10c0 -107 -81 -230 -230 -230c-46 0 -88 13 -124 36c6 -1 12 -1 19 -1c38 0 73 13 101 35c-35 1 -66 24 -76 56c5 -1 10 -2 15 -2c7 0 15 1 22 3c-37 7 -65 40 -65 79v2c11 -6 23 -11 36 -11c-22 15 -35 40 -35 68c0 15 3 28 10 40
c40 -49 100 -81 167 -84c-1 6 -2 12 -2 18c0 45 36 81 81 81c23 0 44 -9 59 -25c18 4 35 10 51 19c-6 -19 -18 -34 -35 -44c16 2 31 6 46 12z" />
<glyph glyph-name="uniF1E5" unicode="&#xf1e5;"
d="M333 376c20 0 36 -15 36 -35v-298c0 -20 -16 -35 -36 -35h-297c-20 0 -36 15 -36 35v298c0 20 16 35 36 35h297zM309 259c1 7 2 15 0 22c-1 3 -2 6 -4 8c-9 11 -29 11 -42 9c-11 -2 -48 -17 -60 -55h6c14 0 22 -2 25 -12c1 -4 2 -8 1 -14c-1 -10 -6 -20 -12 -31
c-7 -12 -19 -37 -35 -20c-2 2 -4 6 -5 6v0c-10 15 -9 42 -12 59c-2 11 -4 26 -8 37c0 1 0 5 -1 5v0c-4 10 -11 17 -18 19c-9 3 -22 -2 -29 -6c-22 -13 -39 -31 -59 -46v-1c5 -1 4 -2 5 -4c2 -3 4 -5 8 -6c13 -2 25 11 34 -3c1 -2 2 -3 3 -5h-1l1 -1v1v-1c3 -7 4 -15 7 -22
c5 -13 8 -26 12 -41c4 -16 8 -37 17 -52c5 -9 11 -16 19 -19c11 -5 28 2 36 7c23 13 40 32 55 52c35 46 54 99 57 114z" />
<glyph glyph-name="uniF1E6" unicode="&#xf1e6;" horiz-adv-x="368"
d="M368 203h-205v149l205 29v-178zM149 349v-146h-149v125zM0 183h149v-148l-149 22v126zM163 33v150h205v-180z" />
<glyph glyph-name="uniF1E7" unicode="&#xf1e7;" horiz-adv-x="399"
d="M147 277c-131 -136 -103 -210 -103 -210c-27 34 -44 78 -44 125c0 53 21 100 54 136c0 0 34 -15 93 -51zM200 315c-80 58 -130 29 -130 29c35 30 81 48 130 48s94 -18 129 -48c0 0 -49 29 -129 -29v0v0zM199 233c124 -92 145 -179 145 -179c-36 -38 -87 -62 -144 -62
s-109 24 -145 62c0 0 33 97 144 179zM399 192c0 -47 -16 -91 -43 -125c0 0 27 74 -104 210c59 36 94 51 94 51c33 -36 53 -83 53 -136z" />
<glyph glyph-name="uniF1E8" unicode="&#xf1e8;" horiz-adv-x="512"
d="M460 50l-53 6l6 46l53 -6zM512 328l-50 -202l-39 6l-1 207zM332 292c35 -27 53 -61 53 -103c0 -43 -18 -78 -53 -105c-30 -22 -67 -35 -111 -39h-56c-44 4 -82 17 -111 39c-36 27 -54 62 -54 105c0 42 18 76 54 103c35 27 82 41 139 41c56 0 103 -14 139 -41zM305 224
l7 10h-48h-50l2 -10l30 -5c-1 -6 -16 -20 -46 -43c-23 28 -39 51 -50 67l35 4l2 8c-16 1 -36 1 -60 0c-34 1 -52 1 -54 0v-10l33 -5c6 -5 18 -17 37 -40c18 -22 27 -36 28 -39l1 -15v-7c0 -12 -1 -20 -2 -21c-2 -2 -6 -2 -15 -3l-17 -1l-2 -10h52h59l1 11l-36 1l-3 22l1 9
l1 14c2 5 13 16 33 32c19 16 30 24 34 25z" />
<glyph glyph-name="uniF1E9" unicode="&#xf1e9;" horiz-adv-x="344"
d="M212 133c7 7 17 4 17 4l101 -32s14 -2 14 -12c0 -7 -4 -15 -4 -15l-43 -61s-7 -6 -15 -6s-17 12 -17 12l-54 90s-6 13 1 20zM207 179c-5 8 0 17 0 17l57 89s6 12 16 11c9 -1 13 -8 13 -8l48 -57s4 -9 2 -16s-16 -13 -16 -13l-100 -29s-15 -3 -20 6zM159 214
c-11 -3 -19 6 -19 6l-87 118s-12 14 -6 24c4 7 12 10 12 10l84 31c4 1 8 5 20 -3c8 -5 9 -23 9 -23l1 -143s-2 -17 -14 -20zM139 156c0 -15 -8 -15 -12 -18l-105 -23s-15 -6 -20 2c-3 6 -2 18 -2 18l6 73c0 5 5 9 10 12c6 4 20 -1 20 -1l90 -46s13 -6 13 -17zM165 117
c8 -4 9 -15 9 -15l-2 -105s1 -14 -8 -17c-6 -2 -15 0 -15 0l-70 23c-5 2 -9 5 -11 12s7 19 7 19l70 78s11 10 20 5z" />
<glyph glyph-name="uniF1EA" unicode="&#xf1ea;"
d="M160 88v67h16v-88h-16v9c-6 -7 -13 -11 -19 -11c-5 0 -8 3 -10 7c-1 3 -1 7 -1 13v70h16v-65v-6c0 -2 2 -4 4 -4c3 0 6 3 10 8zM71 169v17h56v-17h-19v-102h-18v102h-19zM181 247c-5 0 -8 4 -8 12v38c0 8 3 12 8 12s7 -4 7 -12v-38c0 -8 -2 -12 -7 -12zM222 156
c6 0 11 -3 13 -10c1 -4 2 -9 2 -17v-36c0 -8 -1 -14 -2 -18c-2 -7 -7 -10 -13 -10s-11 3 -16 10v-8h-16v119h16v-39c5 6 10 9 16 9zM221 92v38c0 8 -2 12 -7 12c-3 0 -5 -1 -8 -4v-54c3 -3 5 -4 8 -4c5 0 7 4 7 12zM274 156c8 0 15 -3 19 -9c3 -4 5 -11 5 -20v-19h-33v-16
c0 -8 3 -12 9 -12c4 0 6 3 7 7v10h17v-2c0 -5 -1 -8 -1 -10c-1 -4 -2 -7 -4 -10c-4 -6 -11 -10 -19 -10s-14 4 -19 10c-3 4 -6 11 -6 20v31c0 9 2 17 5 21c5 6 12 9 20 9zM281 122v8c0 8 -3 12 -8 12s-8 -4 -8 -12v-8h16zM333 376c20 0 36 -16 36 -36v-296
c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM218 323v-71c0 -6 0 -11 1 -14c2 -5 6 -6 11 -6c6 0 12 4 18 11v-10h17v90h-17v-69c-4 -5 -7 -7 -10 -7c-2 0 -4 0 -4 3v7v66h-16zM157 293v-31c0 -10 2 -17 5 -21c4 -6 11 -9 19 -9s14 3 19 9
c3 4 5 11 5 21v31c0 10 -2 17 -5 22c-5 6 -11 9 -19 9s-15 -3 -19 -9c-3 -5 -5 -12 -5 -22zM113 353h-19l12 -33c6 -17 9 -29 11 -38v-49h18v49l21 71h-18l-12 -47zM313 61c5 20 4 42 4 63s1 43 -4 63c-3 14 -15 24 -29 26c-33 4 -67 4 -100 4s-66 0 -99 -4
c-14 -2 -26 -12 -29 -26c-5 -20 -5 -42 -5 -63s0 -43 5 -63c3 -14 15 -24 29 -26c33 -4 66 -3 99 -3s67 -1 100 3c14 2 26 12 29 26z" />
<glyph glyph-name="uniF1EB" unicode="&#xf1eb;" horiz-adv-x="281"
d="M76 133c37 -3 66 -23 96 -41c21 -13 44 -20 69 -20c12 0 22 4 31 12c4 3 6 2 7 -3c9 -37 -21 -75 -59 -76c-19 -1 -35 6 -50 16c-17 11 -35 25 -52 36c-32 21 -67 28 -105 24c-11 -1 -12 -1 -13 11c-2 22 6 40 21 56c42 46 83 91 122 140c3 4 7 9 10 13c1 1 3 2 2 4
s-2 1 -4 1c-18 -1 -37 -2 -56 -2c-10 0 -18 2 -27 6c-15 7 -20 17 -14 32c5 12 11 23 19 34c2 3 4 4 7 2c17 -9 36 -11 55 -13c40 -3 80 0 119 8c5 1 6 -1 6 -5c2 -18 -4 -33 -16 -46c-42 -48 -82 -98 -127 -143c-14 -14 -29 -28 -41 -46z" />
<glyph glyph-name="uniF1EC" unicode="&#xf1ec;"
d="M333 376c20 0 36 -16 36 -36v-296c0 -20 -16 -36 -36 -36h-297c-20 0 -36 16 -36 36v296c0 20 16 36 36 36h297zM289 155h-165l135 39c9 3 16 7 21 13s9 15 9 23c0 10 -5 19 -13 26s-18 11 -29 11h-155c-5 -1 -9 -6 -9 -11v-27h164l-135 -38c-8 -3 -16 -7 -21 -14
s-8 -14 -8 -22c0 -10 4 -20 12 -27s18 -11 29 -11h154c5 1 10 6 11 11v27z" />
<glyph glyph-name="uniF1ED" unicode="&#xf1ed;" horiz-adv-x="394"
d="M175 214c12 12 32 12 44 0s12 -32 0 -44s-32 -12 -44 0s-12 32 0 44zM333 43v0v-1h-1v0l-8 -8v0c-4 -4 -11 -3 -15 0v0l-1 1v0v0l-7 7v0v0l-7 7v0v0v0v0c-4 4 -5 11 -1 16v1h1v1v0l7 7h1c64 65 64 171 -1 236v0v0l-8 7v0v0l-1 1v1c-4 4 -3 11 0 15v0l1 1v0v0l14 14v0v0v0
v0c4 4 11 5 16 1v0l9 -9v0v0c82 -82 83 -216 1 -298zM274 102v0h-1v0v0l-8 -9v1c-4 -4 -11 -3 -15 0v-1l-2 1v0v0l-14 15v0c-4 4 -5 11 -1 16v0l1 1v0v0l8 8v0c32 32 31 84 -1 116v0v0l-8 8v0v0l-1 1v0c-4 4 -3 11 0 15v0l1 1v0v0l14 14l1 1v0v0v0c4 4 11 4 16 0v0l9 -8v0
v-1c49 -49 50 -129 1 -179zM219 214c12 -12 12 -32 0 -44s-32 -12 -44 0s-12 32 0 44s32 12 44 0zM162 125c4 -4 3 -11 0 -15v0l-1 -1v0v0l-14 -14v0v-1v0v0c-4 -4 -12 -4 -17 0v0l-8 8v0l-1 1c-49 49 -49 129 0 179v0v0v0v0l7 8v0v0l1 1v-1c4 4 12 3 16 0v1l15 -16v0
c4 -4 5 -11 1 -16v0l-9 -9v0c-32 -32 -31 -84 1 -116v0v0l8 -8v0v0l1 -1v0zM102 65c4 -4 3 -11 0 -15v0l-1 -1v0v0l-14 -14v0v0v0v0c-4 -4 -11 -5 -16 -1v0l-9 9v0v0c-82 82 -83 216 -1 298v0l9 9v0c4 4 11 3 15 0v0l8 -8v0v0l8 -7v0c4 -4 4 -11 0 -16v-1h-1v-1v0l-7 -7v0
c-64 -65 -65 -171 0 -236h1v0l7 -7v0v0l1 -1v-1z" />
<glyph glyph-name="uniF1EE" unicode="&#xf1ee;" horiz-adv-x="426"
d="M426 244c1 -4 0 -8 -3 -11l-113 -90l50 -142c1 -4 0 -8 -3 -11c-2 -2 -4 -3 -6 -3s-4 1 -6 2l-132 79l-132 -79c-4 -2 -9 -2 -12 1s-4 7 -3 11l50 142l-112 90c-3 3 -4 7 -3 11s5 7 9 7h144l50 139c1 4 5 7 9 7s9 -3 10 -7l49 -139h144c4 0 9 -3 10 -7z" />
<glyph glyph-name="uniF1EF" unicode="&#xf1ef;" horiz-adv-x="308"
d="M308 335v0v-286v0c0 -6 -5 -11 -11 -11v0h-285v0h-1c-6 0 -11 5 -11 11v0v0v284v2c0 6 5 11 11 11h1h284v0h1c6 0 11 -5 11 -11z" />
<glyph glyph-name="uniF1F0" unicode="&#xf1f0;" horiz-adv-x="312"
d="M297 193c8 0 15 -7 15 -15s-7 -15 -15 -15h-1v0h-281v0c-8 0 -15 7 -15 15s7 15 15 15v0h281v0h1zM263 144c4 0 8 -4 8 -8v-1v-3c0 -48 -34 -90 -112 -90c-53 0 -91 19 -117 46c-2 1 -4 3 -4 6c0 2 1 4 2 5v0l18 27v0v0v0c1 2 4 4 7 4s5 -2 6 -4c20 -21 50 -39 90 -39
c42 0 58 20 58 40c0 2 -1 5 -1 7v0v2c0 4 4 8 8 8l1 -1v1h36zM63 214v0c-8 11 -12 25 -12 43c0 48 41 85 105 85c45 0 82 -15 108 -41v0c2 -1 3 -4 3 -6s-1 -4 -2 -5v0l-17 -25h-1v-1v0c-1 -2 -3 -3 -6 -3c-2 0 -4 1 -5 2v0c-23 23 -55 34 -85 34s-48 -15 -48 -36
c0 -28 45 -33 88 -46v0c1 0 2 -1 2 -2s-1 -3 -2 -3h-121c-3 0 -6 2 -7 4z" />
<glyph glyph-name="uniF1F1" unicode="&#xf1f1;" horiz-adv-x="315"
d="M313 54c1 -1 2 -3 2 -4v-11c0 -1 -1 -3 -2 -4s-2 -1 -3 -1h-67v0h-1c-1 0 -2 1 -2 2v13v0c0 1 1 2 2 3l1 1v0c37 26 41 30 41 36c0 4 -5 6 -10 6c-8 0 -15 -3 -21 -8v0v0v0v0c-2 -1 -5 -2 -7 0v0l-7 10v0c-1 2 -1 4 0 6v0v0l1 1v0c9 9 23 13 34 13c21 0 35 -12 35 -28
c0 -11 -6 -21 -26 -34h27v0c1 0 2 0 3 -1zM210 277c5 -5 5 -14 0 -19v0l-67 -66l67 -67v0c5 -5 5 -14 0 -19l-17 -17c-5 -5 -14 -5 -19 0v0v0l-67 66l-67 -66v0c-5 -5 -14 -5 -19 0l-17 17c-5 5 -5 14 0 19v0v0l67 67l-67 66v1c-5 5 -5 13 0 18l17 18c5 5 14 5 19 0l67 -67
l67 67v0c5 5 14 5 19 0z" />
<glyph glyph-name="uniF1F2" unicode="&#xf1f2;" horiz-adv-x="315"
d="M313 287c1 -1 2 -2 2 -3v-12c0 -1 -1 -2 -2 -3s-2 -2 -3 -2h-67v0h-1c-1 0 -2 1 -2 2v14v0c0 1 1 2 2 3h1v0c37 26 41 30 41 36c0 4 -5 6 -10 6c-8 0 -15 -3 -21 -8v0v0v0v0c-2 -1 -5 -2 -7 0v0l-7 11v0c-1 2 -1 3 0 5v0v1h1v1c9 9 23 12 34 12c21 0 35 -12 35 -28
c0 -11 -6 -20 -26 -33h27v0c1 0 2 -1 3 -2zM210 277c5 -5 5 -14 0 -19v0l-67 -67l67 -67v0c5 -5 5 -14 0 -19l-17 -17c-5 -5 -14 -5 -19 0v0v0l-67 67l-67 -67v0c-5 -5 -14 -5 -19 0l-17 17c-5 5 -5 14 0 19v0v0l67 67l-67 67v0c-5 5 -5 14 0 19l17 17c5 5 14 5 19 0l67 -67
l67 67v0c5 5 14 5 19 0z" />
<glyph glyph-name="uniF1F3" unicode="&#xf1f3;" horiz-adv-x="436"
d="M436 335v-1v0v-286v0c0 -8 -8 -14 -16 -14h-404c-8 0 -16 6 -16 14v0v286v0v1c0 9 7 15 16 15h404c9 0 16 -6 16 -15zM385 84v0v216h-334v-216h334zM410 179c7 0 13 5 13 12s-6 13 -13 13s-12 -6 -12 -13s5 -12 12 -12z" />
<glyph glyph-name="uniF1F4" unicode="&#xf1f4;" horiz-adv-x="317"
d="M301 410c9 0 16 -7 16 -16v-404c0 -9 -7 -16 -16 -16v0v0h-286v0c-8 0 -15 8 -15 16v404c0 8 7 16 15 16v0h286v0v0zM158 -13c7 0 13 6 13 13s-6 12 -13 12s-13 -5 -13 -12s6 -13 13 -13zM266 25v0v334h-215v-334h215z" />
<glyph glyph-name="uniF1F5" unicode="&#xf1f5;" horiz-adv-x="486"
d="M473 205c7 0 13 -6 13 -13s-6 -13 -13 -13h-38c-6 -96 -83 -173 -179 -179v-38c0 -7 -6 -13 -13 -13s-13 6 -13 13v38c-96 6 -172 83 -178 179h-39c-7 0 -13 6 -13 13s6 13 13 13h39c6 96 82 173 178 179v38c0 7 6 13 13 13s13 -6 13 -13v-38c96 -6 173 -83 179 -179h38z
M230 51v26c-54 6 -96 48 -102 102h-25c6 -68 59 -122 127 -128zM230 307v0v26c-68 -6 -121 -60 -127 -128h25c6 54 48 96 102 102zM256 333v-26c54 -6 96 -48 102 -102h26c-6 68 -60 122 -128 128zM256 51c68 6 122 60 128 128h-26c-6 -54 -48 -96 -102 -102v-26z" />
<glyph glyph-name="uniF1F6" unicode="&#xf1f6;" horiz-adv-x="384"
d="M192 307c64 0 115 -51 115 -115s-51 -115 -115 -115s-116 51 -116 115s52 115 116 115zM192 127c36 0 64 29 64 65s-28 65 -64 65s-65 -29 -65 -65s29 -65 65 -65zM192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51
c78 0 141 63 141 141s-63 141 -141 141s-141 -63 -141 -141s63 -141 141 -141zM153 192c0 26 13 39 39 39s39 -13 39 -39s-13 -39 -39 -39s-39 13 -39 39z" />
<glyph glyph-name="uniF1F7" unicode="&#xf1f7;" horiz-adv-x="333"
d="M12 256c-3 3 -6 6 -6 11v56c0 5 3 12 6 16c0 0 1 3 3 5c11 11 54 45 153 45c117 0 154 -48 156 -50c3 -4 6 -11 6 -16v-56c0 -4 -1 -7 -4 -9c-4 -4 -9 -5 -14 -3l-65 20c-7 2 -12 9 -12 16v21c0 1 0 3 -1 4c0 0 -15 13 -66 13s-66 -13 -66 -13c0 -1 -1 -3 -1 -4v-24
c0 -5 -3 -10 -6 -13c-2 -2 -4 -3 -6 -4h-1l-65 -17c-4 -1 -8 0 -11 2zM35 148c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13zM161 135c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13z
M230 135c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13zM299 135c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13zM11 189c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13
c0 -6 -5 -11 -11 -11h-35zM115 189h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13c0 -6 -5 -11 -11 -11zM184 189h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13c0 -6 -5 -11 -11 -11zM253 224c6 0 11 -5 11 -11v-13
c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35zM322 224c6 0 11 -5 11 -11v-13c0 -6 -5 -11 -11 -11h-35c-6 0 -11 5 -11 11v13c0 6 5 11 11 11h35zM57 70c0 -6 -5 -10 -11 -10h-35c-6 0 -11 4 -11 10v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13zM80 60
c-6 0 -11 4 -11 10v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13c0 -6 -5 -10 -11 -10h-35zM149 60c-6 0 -11 4 -11 10v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13c0 -6 -5 -10 -11 -10h-35zM218 60c-6 0 -11 4 -11 10v13c0 6 5 11 11 11h35c6 0 11 -5 11 -11v-13
c0 -6 -5 -10 -11 -10h-35zM322 94c6 0 11 -5 11 -11v-13c0 -6 -5 -10 -11 -10h-35c-6 0 -11 4 -11 10v13c0 6 5 11 11 11h35zM281 30c6 0 11 -5 11 -11v-13c0 -6 -5 -11 -11 -11h-233c-6 0 -10 5 -10 11v13c0 6 4 11 10 11h233z" />
<glyph glyph-name="uniF1F8" unicode="&#xf1f8;" horiz-adv-x="358"
d="M358 88c1 -5 -1 -11 -5 -15l-50 -50c-5 -5 -13 -9 -20 -10h-7v0c-19 0 -89 7 -179 97c-106 106 -97 183 -97 186c1 7 5 15 10 20l51 50c3 3 7 5 12 5c6 0 12 -4 15 -10l41 -76c4 -8 2 -19 -5 -26l-18 -19c-1 -1 -2 -4 -2 -5c0 0 1 -25 47 -71s72 -48 72 -48c1 0 3 2 4 3
l22 21c4 4 10 7 16 7c4 0 7 -1 10 -3h1l73 -43c5 -3 8 -8 9 -13z" />
<glyph glyph-name="uniF1F9" unicode="&#xf1f9;" horiz-adv-x="379"
d="M364 45c8 0 15 -8 15 -16s-7 -15 -15 -15h-1v0h-348v0c-8 0 -15 7 -15 15s7 16 15 16v0h348v0h1zM63 80c-7 0 -13 6 -13 13c0 2 1 4 1 5v0l103 263v0c2 5 7 9 13 9h45c6 0 11 -4 13 -9v0l103 -262v-1v-1v0c0 -1 1 -3 1 -4c0 -7 -7 -13 -14 -13h-1v0h-29v0
c-5 0 -9 4 -11 8v0l-18 48h-133l-18 -47c-2 -5 -7 -9 -13 -9h-29zM189 319l-52 -138h104z" />
<glyph glyph-name="uniF1FA" unicode="&#xf1fa;" horiz-adv-x="332"
d="M65 358c6 0 12 -5 12 -11v0v0v-54v0c0 -6 -6 -12 -12 -12v0h-53v0v0c-6 0 -12 6 -12 12v0v54v0v0c0 6 6 11 12 11v0v0h53v0zM193 358c6 0 12 -5 12 -11v0v0v-54v0c0 -6 -6 -12 -12 -12v0h-54v0v0c-6 0 -11 6 -11 12v0v54v0v0c0 6 5 11 11 11v0v0h54v0zM332 347v0v0v-54v0
c0 -6 -5 -12 -11 -12v0h-54v0v0c-6 0 -12 6 -12 12v0v54v0c0 6 6 11 12 11v0v0h54v0c6 0 11 -5 11 -11zM65 230c6 0 12 -5 12 -11v0v0v-54v0c0 -6 -6 -11 -12 -11v0h-53v0v0c-6 0 -12 5 -12 11v0v54v0v0c0 6 6 11 12 11v0v0h53v0zM193 230c6 0 12 -5 12 -11v0v0v-54v0
c0 -6 -6 -11 -12 -11v0h-54v0v0c-6 0 -11 5 -11 11v0v54v0v0c0 6 5 11 11 11v0v0h54v0zM321 230c6 0 11 -5 11 -11v0v0v-54v0c0 -6 -5 -11 -11 -11v0h-54v0v0c-6 0 -12 5 -12 11v0v54v0c0 6 6 11 12 11v0v0h54v0zM65 103c6 0 12 -6 12 -12v0v0v-54v0c0 -6 -6 -11 -12 -11v0
h-53v0v0c-6 0 -12 5 -12 11v0v54v0v0c0 6 6 12 12 12v0v0h53v0zM193 103c6 0 12 -6 12 -12v0v0v-54v0c0 -6 -6 -11 -12 -11v0h-54v0v0c-6 0 -11 5 -11 11v0v54v0v0c0 6 5 12 11 12v0v0h54v0zM321 103c6 0 11 -6 11 -12v0v0v-54v0c0 -6 -5 -11 -11 -11v0h-54v0v0
c-6 0 -12 5 -12 11v0v54v0c0 6 6 12 12 12v0v0h54v0z" />
<glyph glyph-name="uniF1FB" unicode="&#xf1fb;" horiz-adv-x="512"
d="M509 276c4 -4 4 -9 0 -13v0l-324 -324v0c-4 -4 -9 -4 -13 0v1l-63 62c8 12 7 28 -4 39s-27 12 -39 4l-63 63v0v0c-4 4 -4 9 0 13v0l324 324v0c4 4 9 4 13 0l63 -63c-8 -12 -7 -28 4 -39s27 -12 39 -4l63 -63v0zM438 263c4 4 4 9 0 13l-98 98v0c-4 4 -9 4 -13 0v0
l-253 -253v0c-4 -4 -4 -9 0 -13v0l98 -98v0v0c4 -4 9 -4 13 0v0v0zM317 184c1 0 2 -1 2 -2s-1 -2 -1 -2l-1 -1l-39 -9l-9 -39c0 -1 -2 -2 -3 -2s-2 1 -2 2l-17 35l-36 -4c-1 0 -3 0 -3 1s-1 2 0 3l27 26l-17 34c0 1 0 2 1 3s2 1 3 1l34 -17l26 27c1 1 2 0 3 0s1 -2 1 -3
l-4 -36z" />
<glyph glyph-name="uniF1FC" unicode="&#xf1fc;" horiz-adv-x="332"
d="M321 139c7 -3 11 -12 11 -21v-77v-14c0 -12 -9 -22 -19 -22h-123v70v2v0l-20 34v0v1v0c-1 1 -2 2 -4 2s-2 -1 -3 -2v0l-21 -35h1c0 -1 -1 -1 -1 -2v-70h-123c-10 0 -19 10 -19 22v14v77c0 9 5 18 12 21l83 38l32 15c-15 9 -27 22 -35 39c-7 14 -11 31 -11 49
c0 10 2 20 4 29c11 40 43 70 81 70c39 0 72 -30 82 -72c2 -9 3 -18 3 -27c0 -17 -4 -32 -10 -46c-8 -17 -19 -32 -34 -41l33 -16zM190 162v2c0 2 -2 4 -4 4h-40c-2 0 -4 -2 -4 -4c0 -1 1 -1 1 -2v0l19 -35v0h1v0c1 -1 1 -2 3 -2s3 1 4 2v0l20 35v0z" />
<glyph glyph-name="uniF1FD" unicode="&#xf1fd;" horiz-adv-x="332"
d="M321 139c7 -3 11 -12 11 -21v-77v-14c0 -12 -9 -22 -19 -22h-294c-10 0 -19 10 -19 22v14v77c0 9 5 18 12 21l83 38l32 15c-1 1 -3 2 -4 3h-44c-7 0 -13 5 -13 12v33v0c1 46 18 87 42 112c13 14 29 23 47 26h2s2 1 3 1h6v0v0v0h6c1 0 2 -1 3 -1h3c18 -3 34 -13 47 -27
c24 -25 40 -65 41 -111v0v-33c0 -7 -5 -12 -12 -12h-45l-2 -2l33 -16z" />
<glyph glyph-name="uniF1FE" unicode="&#xf1fe;" horiz-adv-x="332"
d="M321 139c7 -3 11 -12 11 -21v-77v-14c0 -12 -9 -22 -19 -22h-294c-10 0 -19 10 -19 22v14v77c0 9 5 18 12 21l83 38l32 15c-15 9 -27 22 -35 39c-7 14 -11 31 -11 49c0 10 2 20 4 29c11 40 43 70 81 70c39 0 72 -30 82 -72c2 -9 3 -18 3 -27c0 -17 -4 -32 -10 -46
c-8 -17 -19 -32 -34 -41l33 -16z" />
<glyph glyph-name="uniF1FF" unicode="&#xf1ff;" horiz-adv-x="488"
d="M382 145c4 -2 7 -5 9 -9c2 -3 3 -7 3 -11v-69v-13c0 -11 -8 -20 -17 -20h-266c-9 0 -17 9 -17 20v13v69v3c1 7 5 14 11 17l74 34l29 14c-1 1 -2 0 -3 1h-40c-6 0 -11 5 -11 11v30v0c1 37 12 69 30 92c14 21 36 34 60 34c22 0 42 -11 56 -29c20 -23 33 -58 34 -97v0v-30
c0 -6 -5 -11 -11 -11h-40c-1 0 -1 -1 -2 -1l29 -14zM119 179l-25 -11c-15 -7 -25 -24 -25 -42v-69h-55c-8 0 -14 7 -14 16v66c0 7 4 13 9 15l83 39c-20 12 -33 36 -33 64c0 40 28 71 62 71c10 0 20 -3 28 -8c-17 -30 -29 -68 -30 -110v0v-31zM479 153c5 -2 9 -8 9 -15v-66
c0 -9 -6 -16 -14 -16h-55v69c0 18 -11 35 -26 42l-24 11v31h-1c-1 42 -12 80 -29 110c8 5 18 9 28 9c34 0 62 -32 62 -72c0 -28 -14 -52 -34 -64z" />
<glyph glyph-name="uniF200" unicode="&#xf200;" horiz-adv-x="489"
d="M481 153c5 -3 8 -8 8 -15v-66c0 -9 -5 -16 -13 -16h-58v70c0 18 -9 34 -24 41l-54 25v0c-5 3 -10 7 -14 12c12 19 19 43 19 67c0 16 -2 32 -8 46c9 7 20 11 32 11c34 0 61 -32 61 -72c0 -27 -13 -51 -32 -63zM150 193l-56 -26c-15 -7 -25 -23 -25 -41v-70h-55
c-8 0 -14 7 -14 16v66c0 7 4 13 9 15l83 39c-20 12 -33 36 -33 64c0 40 28 72 62 72c11 0 21 -4 30 -10c-6 -14 -9 -30 -9 -47c0 -25 7 -49 20 -68c-4 -4 -8 -7 -12 -10zM383 144c6 -3 10 -10 10 -18v-70v-12c0 -11 -8 -20 -17 -20h-265c-9 0 -17 9 -17 20v12v70
c0 8 5 15 11 18l75 35l29 13c-13 8 -25 20 -32 35c-6 13 -10 28 -10 44c0 9 2 18 4 26c10 36 39 63 73 63c35 0 64 -28 73 -65c2 -8 3 -16 3 -24c0 -15 -3 -29 -9 -41c-7 -16 -18 -29 -31 -37l31 -15z" />
<glyph glyph-name="uniF201" unicode="&#xf201;" horiz-adv-x="442"
d="M140 207v0v-24l-39 -18c-16 -8 -27 -25 -27 -44v-74h-59c-8 0 -15 8 -15 17v71c0 7 3 13 9 16l90 41c-21 13 -36 38 -36 68c0 42 30 77 66 77c12 0 22 -4 32 -10c-1 -4 -3 -7 -4 -11c-10 -22 -16 -48 -17 -76v0v-28v-5zM430 139c7 -3 12 -12 12 -21v-77v-14
c0 -12 -9 -22 -19 -22h-295c-10 0 -19 10 -19 22v14v77c0 9 5 18 12 21l83 38l33 15c-1 1 -3 2 -4 3h-45c-7 0 -12 5 -12 12v33v0c1 46 18 87 42 112c13 14 28 23 46 26h3s2 1 3 1h6h6c1 0 2 -1 3 -1h2c18 -3 34 -13 47 -27c24 -25 40 -65 41 -111h1v-33
c0 -7 -6 -12 -13 -12h-44c-1 -1 -2 -1 -3 -2l34 -16z" />
<glyph glyph-name="uniF202" unicode="&#xf202;" horiz-adv-x="420"
d="M419 124c0 -1 1 -2 1 -3v-74v-13c0 -12 -9 -21 -19 -21h-282c-10 0 -18 9 -18 21v13v74c0 2 0 4 1 6c2 6 5 12 10 14l80 37l31 14c-14 8 -26 22 -34 38c-6 12 -9 25 -10 40v6v8c1 7 2 13 4 20c1 4 2 8 3 11c13 33 41 56 74 56v0v0c37 0 68 -29 78 -69c2 -8 4 -17 4 -26
c0 -16 -4 -31 -10 -44c-8 -17 -19 -30 -33 -39l32 -16l77 -36c6 -3 10 -10 11 -17zM155 190l-54 -25c-16 -8 -27 -25 -27 -44v-74h-59c-8 0 -15 8 -15 17v71c0 7 3 13 9 16l90 41l-2 1h-36c-5 0 -10 5 -10 10v26v0c2 62 37 111 80 111c9 0 17 -2 25 -6
c-8 -17 -13 -37 -13 -58c0 -30 10 -56 26 -78z" />
<glyph glyph-name="uniF203" unicode="&#xf203;" horiz-adv-x="420"
d="M160 193l-59 -28c-16 -8 -27 -25 -27 -44v-74h-59c-8 0 -15 8 -15 17v71c0 7 3 13 9 16l90 41c-21 13 -36 38 -36 68c0 42 30 77 66 77c12 0 22 -4 32 -10c-6 -15 -9 -33 -9 -51c0 -27 7 -51 21 -72c-4 -4 -8 -8 -13 -11zM408 141c7 -3 12 -11 12 -20v-74v-13
c0 -12 -9 -21 -19 -21h-282c-10 0 -18 9 -18 21v13v74c0 9 4 17 11 20l80 37l31 14c-14 8 -26 22 -34 38c-7 14 -10 29 -10 46c0 10 2 19 4 28c10 39 40 67 77 67s68 -29 78 -69c2 -8 4 -17 4 -26c0 -16 -4 -31 -10 -44c-8 -17 -19 -30 -33 -39l32 -16z" />
<glyph glyph-name="uniF204" unicode="&#xf204;" horiz-adv-x="321"
d="M293 277c7 0 12 -5 12 -12v-256c0 -7 -5 -12 -12 -12h-265c-7 0 -12 5 -12 12v256c0 7 5 12 12 12h265zM309 359c7 0 12 -5 12 -12v-35c0 -7 -5 -13 -12 -13h-297c-7 0 -12 6 -12 13v35c0 7 5 12 12 12h101v16c0 7 5 12 12 12h72c7 0 12 -5 12 -12v-16h100z" />
<glyph glyph-name="uniF205" unicode="&#xf205;" horiz-adv-x="431"
d="M431 33c1 -1 0 -2 0 -3c0 -4 -2 -7 -6 -7v0h-72v-20c0 -3 -3 -5 -6 -5h-26c-3 0 -6 2 -6 5v20h-72v0c-4 0 -6 3 -6 7c0 1 0 2 1 3v0l8 16h-82v-44c0 -4 -4 -7 -8 -7h-38c-4 0 -7 3 -7 7v44h-101v0c-5 0 -10 4 -10 9c0 2 1 4 2 6l52 90h-21v0c-4 0 -8 4 -8 8c0 2 1 4 2 5
l48 83h-12v0c-3 0 -6 2 -6 5c0 1 1 2 1 3v0l71 123c2 3 4 5 8 5s7 -2 9 -5v0l71 -123v0c0 -1 1 -2 1 -3c0 -3 -3 -5 -6 -5v0h-12l49 -84v-1c1 -1 1 -2 1 -3c0 -4 -4 -8 -8 -8v0h-21l43 -75l11 19h-15v0c-3 0 -5 3 -5 6v2v0l35 60h-9v0c-2 0 -4 2 -4 4c0 1 1 1 1 2v0l50 87v0
c1 2 3 4 6 4s5 -2 6 -4v0l50 -87v0c0 -1 1 -1 1 -2c0 -2 -2 -4 -4 -4v0h-8l34 -60v0c0 -1 1 -1 1 -2c0 -3 -3 -6 -6 -6v0h-15l38 -65v0z" />
<glyph glyph-name="uniF206" unicode="&#xf206;" horiz-adv-x="331"
d="M331 325v0v-133v0c0 -5 -5 -10 -10 -10v0h-43c-7 -47 -42 -84 -87 -94v-65h51v0c7 0 13 -6 13 -13s-6 -13 -13 -13v0v0h-153v0c-7 0 -13 6 -13 13s6 13 13 13h51v65c-45 10 -81 47 -88 94h-42v0c-5 0 -10 5 -10 10v0v0v0v0v133v0v1v0v0c0 5 5 9 10 9h41v36v1
c0 8 6 14 14 15v0h199v0h1c8 0 15 -7 15 -15v-1v-36h41v0c5 0 10 -5 10 -10zM51 208v102h-25v-102h25zM305 208v102h-25v-102h25z" />
<glyph glyph-name="uniF207" unicode="&#xf207;" horiz-adv-x="312"
d="M297 61c8 0 15 -7 15 -15s-7 -16 -15 -16l-1 1v-1h-281v1c-8 0 -15 7 -15 15s7 15 15 15v0h281v0h1zM156 79c-81 0 -121 46 -121 115v145c0 8 7 15 15 15h20c8 0 15 -7 15 -15v-1v-143c0 -44 25 -73 71 -73s71 29 71 73v143v1c0 8 7 15 15 15h20c8 0 15 -7 15 -15v-145
c0 -69 -40 -115 -121 -115z" />
<glyph glyph-name="uniF208" unicode="&#xf208;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM192 51c78 0 141 63 141 141s-63 141 -141 141s-141 -63 -141 -141s63 -141 141 -141zM166 281c0 16 8 25 24 25s24 -9 24 -25s-8 -24 -24 -24s-24 8 -24 24zM273 201v0
c2 -2 3 -4 3 -7c0 -6 -4 -10 -10 -10c-3 0 -5 1 -7 3v0l-34 34v0h-1v0c-1 0 -1 1 -2 1c-2 0 -3 -1 -3 -3v-1v0v-30v-32v-63c0 -7 -5 -12 -12 -12s-12 5 -12 12v63v0c0 2 -1 4 -3 4s-3 -2 -3 -4v0v-63c0 -7 -5 -12 -12 -12s-12 5 -12 12v63v32v31v0c0 2 -1 3 -3 3
c-1 0 -2 0 -3 -1v0l-34 -34v0c-2 -2 -4 -3 -7 -3c-6 0 -10 4 -10 10c0 3 1 5 3 7v0l46 46v1v0v0c2 2 5 3 8 3v0h53h1c3 0 6 -1 8 -3v0v0v-1z" />
<glyph glyph-name="uniF209" unicode="&#xf209;" horiz-adv-x="463"
d="M59 344v0c-6 6 -6 14 0 20s14 6 20 0v0v0v0h1l49 -49c6 -6 6 -15 0 -21s-15 -6 -21 0zM144 363v0c-2 8 2 16 10 18s16 -2 18 -10v0v0v0v0l19 -68c2 -8 -3 -16 -11 -18s-16 2 -18 10zM58 246c-8 2 -12 10 -10 18s9 12 17 10v0h1v0v0l67 -18c8 -2 13 -10 11 -18
s-10 -12 -18 -10l-68 18v0v0v0v0zM405 40v0c6 -6 5 -14 -1 -20s-14 -6 -20 0v0v0v0v0l-50 49c-6 6 -6 15 0 21s15 6 21 0zM319 21v0c2 -8 -2 -16 -10 -18s-16 2 -18 10v0v0v0v0l-18 68c-2 8 2 16 10 18s16 -2 18 -10zM405 138c8 -2 13 -10 11 -18s-10 -12 -18 -10v0v0v0v0
l-68 18c-8 2 -13 10 -11 18s10 12 18 10l68 -18v0v0v0v0zM222 183c39 -39 40 -101 4 -141v0l-51 -52c-40 -40 -105 -40 -145 0s-40 105 0 145l52 52v0c40 36 101 35 140 -4zM189 77v0c17 20 16 50 -3 69s-50 20 -70 3v0l-3 -3v0v0l-46 -46v0c-20 -20 -20 -53 0 -73
s53 -20 73 0v0l46 46v0v0zM433 394c39 -39 40 -101 4 -141v0l-52 -52c-40 -40 -104 -40 -144 0s-40 105 0 145l51 51h1c40 36 101 36 140 -3zM400 287v0c17 20 16 51 -3 70s-50 20 -70 3v0l-3 -3v0v0l-46 -46h-1c-20 -20 -20 -53 0 -73s53 -20 73 0v0l47 46v0v0z" />
<glyph glyph-name="uniF20A" unicode="&#xf20a;" horiz-adv-x="356"
d="M342 215c7 0 14 -6 14 -13v-192c0 -7 -7 -13 -14 -13h-329c-7 0 -13 6 -13 13v192c0 7 6 13 13 13h19h29v54c0 65 55 118 122 118c66 0 120 -52 121 -116v-2c0 -5 -4 -10 -10 -10v0h-51c-6 0 -10 5 -10 10c0 27 -22 48 -50 48s-50 -21 -50 -48v-54h123h67h19z" />
<glyph glyph-name="uniF20B" unicode="&#xf20b;" horiz-adv-x="473"
d="M387 259c46 6 86 -34 86 -83c0 -18 -6 -35 -16 -50c-3 -4 -7 -7 -12 -7h-138c-1 47 -39 86 -87 86s-86 -39 -87 -86h-102c-5 0 -10 3 -13 8c-12 20 -18 42 -18 66c0 66 49 121 110 121c8 0 15 -1 23 -3c27 39 70 61 115 61c65 0 121 -47 139 -113zM274 88c1 -2 1 -3 0 -5
s-2 -3 -4 -3h-24v-64c0 -3 -2 -4 -5 -4h-44c-3 0 -4 1 -4 4v64h-24c-2 0 -4 1 -5 3s0 4 1 5l50 71c1 1 2 2 4 2v0c2 0 3 -1 4 -2z" />
<glyph glyph-name="uniF20C" unicode="&#xf20c;" horiz-adv-x="420"
d="M394 194c14 0 26 -11 26 -25v-144c0 -14 -12 -25 -26 -25h-368c-14 0 -26 11 -26 25v144c0 14 12 25 26 25h93c11 0 22 -7 25 -17c9 -28 36 -46 66 -46s57 18 66 46c3 10 13 17 24 17h94zM137 273c-3 0 -5 1 -6 3s-1 5 1 7l72 98c1 2 4 3 6 3v0c2 0 4 -1 5 -3l73 -98
c2 -2 2 -5 1 -7s-3 -3 -6 -3h-35v-88c0 -4 -3 -7 -7 -7h-63c-4 0 -7 3 -7 7v88h-34z" />
<glyph glyph-name="uniF20D" unicode="&#xf20d;" horiz-adv-x="150"
d="M150 266v0v-233v0c0 -8 -7 -15 -15 -15v0h-121v0c-8 0 -14 7 -14 15v0v233v0c0 8 6 14 14 14h1h11v77v0c0 4 3 7 7 8v1h83c5 0 8 -4 8 -9v0v0v-77h11v0c8 0 15 -6 15 -14zM99 280v60h-48v-60h48zM62 294v11h26v-11h-26z" />
<glyph glyph-name="uniF20E" unicode="&#xf20e;" horiz-adv-x="410"
d="M288 134v-54c0 -13 -10 -23 -23 -23h-242c-13 0 -23 10 -23 23v224c0 13 10 23 23 23h242c13 0 23 -10 23 -23v-53v0l122 57v-232z" />
<glyph glyph-name="uniF20F" unicode="&#xf20f;" horiz-adv-x="243"
d="M243 328v-270h-1l1 -1c0 -6 -5 -11 -11 -11c-2 0 -4 1 -6 2l-85 49v0l-59 34h-74v0v0c-4 0 -8 4 -8 8v106c0 4 4 8 8 8v0v0h74l40 23v0l105 60v0c2 1 3 2 5 2c5 0 9 -5 10 -10h1z" />
<glyph glyph-name="uniF210" unicode="&#xf210;" horiz-adv-x="436"
d="M271 268c-4 5 -4 12 0 17v0l1 1v0v0l16 16v0v0v0v0c5 5 14 5 19 1v0l10 -10v0v0c43 -43 53 -106 31 -159l-41 41c5 29 -4 60 -26 82v1v0l-10 10v0zM366 361c77 -77 90 -194 40 -285l-37 37c31 70 18 155 -39 212v0h-1l-8 9v0v0l-1 1v0c-4 5 -4 12 0 17v0l17 18v0
c5 5 13 5 18 1v0l10 -10v0h1zM243 316v0v-77l-60 60l44 25v0c2 1 3 2 5 2c5 0 9 -5 10 -10h1zM82 241l9 5l152 -151v-49h-1l1 -1c0 -6 -5 -10 -11 -10c-2 0 -4 0 -6 1l-85 49v0l-59 34h-74v0v0c-4 0 -8 4 -8 8v106c0 4 4 8 8 8v0v0h74zM401 45v0c5 -5 5 -13 0 -18l-1 -1
l-17 -18v0c-5 -5 -13 -5 -18 0v0l-331 331c-5 5 -5 13 0 18v0l18 18v1c5 5 13 5 18 0v0v0z" />
<glyph glyph-name="uniF211" unicode="&#xf211;" horiz-adv-x="436"
d="M366 361c93 -93 93 -245 0 -338v0l-8 -9v0v0l-1 -1h-1c-5 -4 -12 -4 -17 0v0l-17 17v0c-5 5 -5 14 -1 19v0l1 1v0v0l9 9v-1c73 74 73 193 -1 267v1l-1 -1l-8 9v0v0l-1 1v0c-4 5 -4 13 0 18v0l17 17v0c5 5 13 5 18 1v0l10 -10v0h1zM317 293c56 -56 56 -147 1 -203v0
l-10 -10v0c-5 -4 -12 -4 -17 0v0l-18 18v0c-5 5 -5 13 -1 18v0l1 1v0v0l9 9v0c36 37 35 96 -1 132v0v0l-10 10v0c-4 5 -4 12 0 17v0l1 1v0v0l16 16v1v0v0v0c5 5 14 5 19 1v0l10 -10v0v-1zM232 326c5 0 9 -4 10 -9h1v-270h-1l1 -1c0 -6 -5 -11 -11 -11c-2 0 -4 1 -6 2l-85 49
v0l-59 34h-74v0v0c-4 0 -8 4 -8 8v105c0 4 4 8 8 8v0v0h74l40 23v0l105 61v0c2 1 3 1 5 1z" />
<glyph glyph-name="uniF212" unicode="&#xf212;" horiz-adv-x="384"
d="M192 384c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192zM53 167c8 -44 37 -81 75 -101c-24 28 -40 63 -45 101h-30zM83 217c5 38 21 73 45 101c-38 -20 -67 -57 -75 -101h30zM167 100v67h-33c5 -25 17 -48 33 -67zM167 217v67
c-16 -19 -28 -42 -33 -67h33zM331 217c-8 44 -37 81 -75 101c24 -28 40 -63 45 -101h30zM217 100c16 19 28 42 33 67h-33v-67zM217 217h33c-5 25 -17 48 -33 67v-67zM256 66c38 20 67 57 75 101h-30c-5 -38 -21 -73 -45 -101z" />
<glyph glyph-name="uniF213" unicode="&#xf213;" horiz-adv-x="285"
d="M152 62l29 -29c-19 -15 -44 -25 -70 -25c-61 0 -111 50 -111 111c0 26 10 51 25 70l27 -28c-8 -12 -13 -25 -13 -40c0 -39 33 -72 72 -72c15 0 29 5 41 13zM202 340c0 24 13 36 37 36s37 -12 37 -36s-13 -37 -37 -37s-37 13 -37 37zM262 215c13 0 23 -10 23 -23v-117
c0 -13 -10 -23 -23 -23s-23 10 -23 23v94h-29c8 -15 12 -32 12 -50c0 -26 -8 -49 -23 -68l-29 29c8 12 12 26 12 41c0 39 -32 71 -71 71c-15 0 -29 -5 -41 -13l-27 27c10 8 22 15 35 19l67 66l-28 17l-33 -33h-1v-1v0c-4 -4 -10 -6 -16 -6c-13 0 -23 10 -23 23
c0 6 3 12 7 16v0l45 45l1 1v1v-1c4 4 10 6 16 6c3 0 6 -1 9 -2v1l103 -60v0c7 -4 11 -11 11 -19c0 -5 -1 -10 -4 -14v0l-1 -1c-1 -1 -3 -2 -4 -3l-46 -46h81z" />
<glyph glyph-name="uniF214" unicode="&#xf214;" horiz-adv-x="415"
d="M405 226c6 -1 10 -5 10 -11v-46c0 -6 -4 -10 -10 -11l-53 -5c-3 -13 -8 -25 -15 -36l34 -41c4 -4 3 -11 -1 -15l-32 -32c-2 -2 -5 -3 -8 -3c-2 0 -5 1 -7 3l-41 33c-11 -7 -23 -12 -36 -15l-5 -52c-1 -6 -5 -10 -11 -10h-45c-6 0 -10 4 -11 10l-5 52c-13 3 -26 8 -37 15
l-40 -33c-2 -2 -5 -3 -7 -3c-3 0 -6 1 -8 3l-32 32c-4 4 -5 11 -1 15l34 41c-7 11 -12 23 -15 36l-53 5c-6 1 -10 5 -10 11v46c0 6 4 10 10 11l53 5c3 13 8 25 15 36l-34 41c-4 4 -3 11 1 15l32 32c2 2 5 3 8 3c2 0 5 -1 7 -3l40 -33c11 7 24 12 37 15l5 52c1 6 5 10 11 10
h45c6 0 10 -4 11 -10l5 -52c13 -3 25 -8 36 -15l41 33c2 2 5 3 7 3c3 0 6 -1 8 -3l32 -32c4 -4 5 -11 1 -15l-34 -41c7 -11 12 -23 15 -36zM207 131c34 0 62 27 62 61s-28 61 -62 61s-61 -27 -61 -61s27 -61 61 -61z" />
<glyph glyph-name="uniF215" unicode="&#xf215;" horiz-adv-x="401"
d="M386 328c1 1 4 1 5 0v0v0l1 -1v0c6 -14 9 -29 9 -45c0 -61 -49 -111 -110 -111c-12 0 -23 3 -34 6l-115 -116c-1 -39 -32 -70 -71 -70s-71 32 -71 71s31 70 70 71l115 116c-3 11 -5 21 -5 33c0 61 50 111 111 111c16 0 30 -4 44 -10h1v0v0l1 -1c1 -1 1 -3 0 -4l-20 -20
l-19 -19l-24 -25c-1 -13 3 -26 13 -36s23 -14 36 -13l24 24l20 19zM100 62c0 16 -13 30 -29 30s-29 -14 -29 -30s13 -29 29 -29s29 13 29 29z" />
<glyph glyph-name="uniF216" unicode="&#xf216;" horiz-adv-x="384"
d="M284 142c2 -2 2 -5 0 -7l-35 -35c-1 -1 -2 -2 -3 -2s-3 1 -4 2l-50 50l-50 -50c-1 -1 -3 -2 -4 -2s-2 1 -3 2l-35 35c-1 1 -2 2 -2 3s1 3 2 4l50 50l-50 50c-1 1 -2 3 -2 4s1 2 2 3l35 35c2 2 5 2 7 0l50 -50l50 50c2 2 5 2 7 0l35 -35c2 -2 2 -5 0 -7l-50 -50zM192 333
c-78 0 -141 -63 -141 -141s63 -141 141 -141s141 63 141 141s-63 141 -141 141zM192 384v0c106 0 192 -86 192 -192s-86 -192 -192 -192s-192 86 -192 192s86 192 192 192z" />
<glyph glyph-name="uniF217" unicode="&#xf217;" horiz-adv-x="361"
d="M358 96c4 -4 4 -10 0 -14l-67 -68c-2 -2 -4 -3 -7 -3s-5 1 -7 3l-96 96l-96 -96c-2 -2 -5 -3 -8 -3s-5 1 -7 3l-67 68c-2 2 -3 4 -3 7s1 5 3 7l96 96l-96 96c-2 2 -3 4 -3 7s1 5 3 7l67 68c4 4 11 4 15 0l96 -96l96 96c4 4 10 4 14 0l67 -68c4 -4 4 -10 0 -14l-96 -96z
" />
<glyph glyph-name="uniF218" unicode="&#xf218;" horiz-adv-x="270"
d="M269 331h1l-85 -130h74v0v0c3 0 6 -2 6 -5v0v-21c0 -3 -3 -6 -6 -6v0v0h-95v-33h95v0v0c3 0 6 -3 6 -6v-20c0 -3 -3 -6 -6 -6v0v0h-95v-48v0c0 -3 -2 -6 -5 -6v0h-47v0v0c-3 0 -6 3 -6 6v1v47h-94v0v0c-3 0 -6 3 -6 6v20c0 3 3 6 6 6v0v0h94v33h-94v0v0c-3 0 -6 2 -6 5v0
v1v0v0v20v0c0 3 3 6 6 6v0v0h72l-84 130v0v1c0 1 0 2 1 2h3h2h57c2 0 3 -2 4 -3v0l68 -110l68 110v0c1 1 2 3 4 3h57h2h3v-1c1 0 1 0 1 -1z" />
<glyph glyph-name="uniF219" unicode="&#xf219;" horiz-adv-x="397"
d="M233 395c91 0 164 -74 164 -164s-73 -164 -164 -164c-26 0 -51 6 -73 17l-82 -82v1c-8 -8 -20 -14 -33 -14c-25 0 -45 20 -45 45c0 13 6 25 14 33h-1l80 79c-15 25 -24 54 -24 85c0 90 73 164 164 164zM234 132c57 0 103 45 103 102s-46 102 -103 102s-102 -45 -102 -102
s45 -102 102 -102zM295 258c4 0 7 -4 7 -8v-32c0 -4 -4 -8 -8 -8v0v0h-36v-36v0c0 -4 -4 -8 -8 -8v0h-32v0v0c-4 0 -8 4 -8 8v0v0v36h-35h-1c-4 0 -8 4 -8 8v32c0 4 4 8 8 8h36v35v1c0 4 4 8 8 8h1h31v0c4 0 8 -4 8 -8v-36h37v0z" />
<glyph glyph-name="uniF21A" unicode="&#xf21a;" horiz-adv-x="397"
d="M233 395c91 0 164 -74 164 -164s-73 -164 -164 -164c-26 0 -51 6 -73 17l-82 -82v1c-8 -8 -20 -14 -33 -14c-25 0 -45 20 -45 45c0 13 6 25 14 33h-1l80 79c-15 25 -24 54 -24 85c0 90 73 164 164 164zM234 132c57 0 103 45 103 102s-46 102 -103 102s-102 -45 -102 -102
s45 -102 102 -102zM294 258c4 0 9 -4 9 -8v0v-32c0 -4 -5 -8 -9 -8h-120c-4 0 -8 4 -8 8v32v0c0 4 4 8 8 8h120z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,157 +0,0 @@
<!doctype html>
<html lang="en" ng-app="copayApp" ng-csp>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="msapplication-tap-highlight" content="no">
<title>Copay - Multisignature Wallet</title>
<style type="text/css">
.loadingpage {
height:100%;
overflow-y: auto;
overflow-x: none;
background: #2C3E50;
padding-top: 20%;
text-align: center;
}
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide:not(.ng-hide-animate) {
display: none !important;
}
ng\:form {
display: block;
}
</style>
<link rel="shortcut icon" href="img/favicon.ico">
</head>
<body
ng-controller="IndexController"
ng-swipe-disable-mouse
ng-swipe-left="closeMenu()"
ng-swipe-right="openMenu()">
<div id="loading" class="loadingpage">
<img src="img/ajax-loader.gif" alt="Loading...">
</div>
<div ng-cloak class="page ng-cloak">
<div ng-show="signingOut">
<div ng-include="'views/includes/loading.html'" ng-init="title = 'Signing out'"></div>
</div>
<div ng-show="sessionExpired" class="session-expired">
<i class="fi-clock size-72 text-gray"></i>
<p class="text-gray size-18" translate>Your session is about to expire due to inactivity in {{countdown}} seconds</p>
</div>
<div class="off-canvas-wrap" id="off-canvas-wrap" ng-show="!signingOut">
<div class="inner-wrap">
<div class="status" ng-if="$root.needsEmailConfirmation && !$root.pleaseConfirmEmailAck">
<a class="close-notification text-white" ng-click="$root.pleaseConfirmEmailAck=true">&#215;</a>
<div class="row">
<div class="large-10 medium-9 small-12 columns m5b">
<i class="fi-alert size-36 left m20r"></i>
<strong class="size-16" translate>Email not confirmed</strong>.<br>
<span translate>
Please confirm your email address using the confirmation link at the message we sent you
</span>
</div>
<div class="large-2 medium-3 small-12 columns text-center">
<button class="text-white warning tiny m0"
ng-click="resendVerificationEmail()"
ng-disabled="loading"
ng-show="!hideReSendButton">
{{ loading ? 'Resending...' : 'Resend' }}
</button>
</div>
</div>
</div>
<div class="status" ng-if="$root.pleaseConfirmEmail">
<a class="close-notification text-white" ng-click="$root.pleaseConfirmEmail=null">&#215;</a>
<i class="fi-alert size-36 left m20r"></i>
<strong class="size-16" translate>Confirm your email address</strong>.<br>
<span translate>An email was sent to</span> {{$root.iden.getName()}}.
<span translate>Please follow the link on it to confirm it. Unconfirmed profiles could be deleted from server.</span>
</div>
<div class="status" ng-if="$root.reconnecting">
<i class="fi-loop icon-rotate"></i>
<strong class="size-16" translate>Network Error</strong>.<br>
<span translate>Attempting to reconnect...</span>
</div>
<div ng-if="$root.iden">
<div ng-controller="SidebarController" ng-show="!$root.hideNavigation && !$root.wpInputFocused">
<nav class="tab-bar">
<section class="left-small">
<a class="p10"
ng-click="openMenu()"><i class="fi-list size-24"></i></a>
</section>
<section class="right-small"
ng-show="$root.wallet.isComplete() && !$root.hideWalletNavigation && isCordova">
<a class="p10"
ng-click="openScanner()"><i class="fi-camera size-24"></i></a>
</section>
<section class="middle tab-bar-section">
<h1 class="title ellipsis" ng-show="$root.wallet && !$root.hideWalletNavigation">
{{$root.wallet.getName()}}
</h1>
</section>
</nav>
<nav class="left-off-canvas-menu">
<div ng-include="'views/includes/sidebar-mobile.html'"></div>
</nav>
<div ng-include="'views/includes/sidebar.html'"
role='navigation'
class="sidebar"></div>
<div class="bottom-bar" ng-if="$root.wallet &&
$root.wallet.isComplete() && !$root.wallet.isLocked && !$root.hideWalletNavigation">
<div ng-include="'views/includes/bottombar-mobile.html'"></div>
</div>
</div>
</div>
<div notifications="right top"></div>
<div
ng-controller="HeadController"
class="head show-for-large-up"
ng-include="'views/includes/head.html'"
ng-if="$root.iden"
ng-class="{'dni':$root.hideNavigation || $root.wpInputFocused}"
></div>
<section
ng-class="{'main':$root.iden && !$root.starting && !$root.hideNavigation && !$root.wpInputFocused}"
ng-view></section>
<a class="close-menu" ng-click="closeMenu()"></a>
</div>
</div>
</div>
<link rel="stylesheet" href="css/vendors.min.css">
<link rel="stylesheet" href="css/copay.min.css">
<script src="lib/vendors.js"></script>
<script src="lib/angularjs-all.js"></script>
<!-- DO NOT DELETE THIS COMMET -->
<!-- PLACEHOLDER: CORDOVA SRIPT -->
<script src="init.js"></script>
<script src="config.js"></script>
<script src="js/copayBundle.js"></script>
<script src="js/copayMain.js"></script>
</body>
</html>

29
init.js
View File

@ -1,29 +0,0 @@
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
var ld;
if (!isChromeApp) {
ld = (document.all);
}
var ns4 = document.layers;
var ns6 = !isChromeApp && document.getElementById && !document.all;
var ie4 = !isChromeApp && document.all;
if (ns4) {
ld = document.loading;
} else if (ns6) {
ld = document.getElementById("loading").style;
} else if (ie4) {
ld = document.all.loading.style;
}
function init() {
if (ns4) {
ld.visibility = "hidden";
} else if (ns6 || ie4) {
ld.display = "none";
} else {
ld = document.getElementById("loading").style;
ld.visibility = "hidden";
ld.display = "none";
}
}
init();

View File

@ -1,8 +0,0 @@
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', {
'bounds': {
'width': 1200,
'height': 800
}
});
});

View File

@ -1,69 +0,0 @@
'use strict';
var copay = require('copay');
var _ = require('lodash');
var LS = require('../js/plugins/LocalStorage');
var ls = new LS();
// TODO move this to configService !
var config = copay.defaultConfig;
ls.getItem('config', function(err, data) {
var localConfig;
try {
localConfig = JSON.parse(data);
} catch(e) {};
if (localConfig) {
var cmv = copay.version.split('.')[1];
var lmv = localConfig.version ? localConfig.version.split('.')[1] : '-1';
if (cmv === lmv) {
_.each(localConfig, function(value, key) {
config[key] = value;
});
}
}
});
var modules = [
'ngRoute',
'angularMoment',
'mm.foundation',
'monospaced.qrcode',
'ngIdle',
'gettext',
'ui.gravatar',
'ngTouch',
'copayApp.filters',
'copayApp.services',
'copayApp.controllers',
'copayApp.directives',
];
var copayApp = window.copayApp = angular.module('copayApp', modules);
var defaults = JSON.parse(JSON.stringify(copay.defaultConfig));
copayApp.value('defaults', defaults);
copayApp.config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'mailto:**'
]);
});
angular.module('ui.gravatar').config([
'gravatarServiceProvider',
function(gravatarServiceProvider) {
gravatarServiceProvider.defaults = {
size: 35
};
// Use https endpoint
gravatarServiceProvider.secure = true;
}
]);
angular.module('copayApp.filters', []);
angular.module('copayApp.services', []);
angular.module('copayApp.controllers', []);
angular.module('copayApp.directives', []);

View File

@ -1,72 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('CopayersController',
function($scope, $rootScope, $timeout, go, identityService, notification, isCordova) {
var w = $rootScope.wallet;
$scope.init = function() {
$rootScope.title = 'Share this secret with your copayers';
$scope.loading = false;
$scope.secret = $rootScope.wallet.getSecret();
$scope.isCordova = isCordova;
w.on('publicKeyRingUpdated', $scope.updateList);
w.on('ready', $scope.updateList);
$scope.updateList();
};
$scope.updateList = function() {
var w = $rootScope.wallet;
$scope.copayers = $rootScope.wallet.getRegisteredPeerIds();
if (w.isComplete()) {
w.removeListener('publicKeyRingUpdated', $scope.updateList);
w.removeListener('ready', $scope.updateList);
go.walletHome();
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
$scope.deleteWallet = function() {
$rootScope.starting = true;
$timeout(function() {
identityService.deleteWallet(w, function(err) {
$rootScope.starting = false;
if (err) {
$scope.error = err.message || err;
copay.logger.warn(err);
$timeout(function () { $scope.$digest(); });
} else {
if ($rootScope.wallet) {
go.walletHome();
}
$timeout(function() {
notification.success('Success', 'The wallet "' + (w.name || w.id) + '" was deleted');
});
}
});
}, 100);
};
$scope.copySecret = function(secret) {
if (isCordova) {
window.cordova.plugins.clipboard.copy(secret);
window.plugins.toast.showShortCenter('Copied to clipboard');
}
};
$scope.shareSecret = function(secret) {
if (isCordova) {
if (isMobile.Android() || isMobile.Windows()) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share(secret, null, null, null);
}
};
});

View File

@ -1,78 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('CreateController',
function($scope, $rootScope, $location, $timeout, identityService, backupService, notification, defaults, isMobile, isCordova) {
$rootScope.fromSetup = true;
$scope.loading = false;
$scope.walletPassword = $rootScope.walletPassword;
$scope.isMobile = isMobile.any();
$scope.hideAdv = true;
$scope.networkName = config.networkName;
$rootScope.title = 'Create new wallet';
$rootScope.hideWalletNavigation = true;
$scope.isWindowsPhoneApp = isMobile.Windows() && isCordova;
// ng-repeat defined number of times instead of repeating over array?
$scope.getNumber = function(num) {
return new Array(num);
}
$scope.totalCopayers = config.wallet.totalCopayers;
$scope.TCValues = _.range(1, config.limits.totalCopayers + 1);
var updateRCSelect = function(n) {
var maxReq = copay.Wallet.getMaxRequiredCopayers(n);
$scope.RCValues = _.range(1, maxReq + 1);
$scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
};
updateRCSelect($scope.totalCopayers);
$scope.$watch('totalCopayers', function(tc) {
updateRCSelect(tc);
});
$scope.$watch('networkName', function(tc) {
$scope.networkUrl = config.network[$scope.networkName].url;
});
$scope.showNetwork = function() {
return $scope.networkUrl != defaults.network.livenet.url && $scope.networkUrl != defaults.network.testnet.url;
};
$scope.create = function(form) {
if (form && form.$invalid) {
$scope.error = 'Please enter the required fields';
return;
}
var opts = {
requiredCopayers: $scope.requiredCopayers,
totalCopayers: $scope.totalCopayers,
name: $scope.walletName,
privateKeyHex: $scope.private,
networkName: $scope.networkName,
};
$rootScope.starting = true;
identityService.createWallet(opts, function(err, wallet){
$rootScope.starting = false;
if (err || !wallet) {
copay.logger.debug(err);
if (err.match('OVERQUOTA')){
$scope.error = 'Could not create wallet: storage limits on remove server exceeded';
} else {
$scope.error = 'Could not create wallet: ' + err;
}
}
$timeout(function(){
$rootScope.$digest();
},1);
});
};
$scope.$on("$destroy", function () {
$rootScope.hideWalletNavigation = false;
});
});

View File

@ -1,202 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('CreateProfileController', function($scope, $rootScope, $location, $timeout, $window, notification, pluginManager, identityService, pinService, isMobile, isCordova, configService, go) {
var _credentials;
$scope.init = function() {
if ($rootScope.wallet)
go.walletHome();
$scope.isMobile = isMobile.any();
$scope.isWindowsPhoneApp = isMobile.Windows() && isCordova;
$scope.hideForWP = 0;
$scope.digits = [];
$scope.defined = [];
$scope.askForPin = 0;
$scope.createStep = 'storage';
$scope.useLocalstorage = false;
$scope.minPasswordStrength = _.isUndefined(config.minPasswordStrength) ?
4 : config.minPasswordStrength;
};
$scope.clear = function() {
pinService.clearPin($scope);
};
$scope.press = function(digit) {
pinService.pressPin($scope, digit, true);
};
$scope.skip = function () {
pinService.skipPin($scope, true);
};
$scope.formFocus = function() {
if (!$scope.isWindowsPhoneApp) return
$scope.hideForWP = true;
$timeout(function() {
$scope.$digest();
}, 1);
};
$scope.createPin = function(pin) {
preconditions.checkArgument(pin);
preconditions.checkState($rootScope.iden);
preconditions.checkState(_credentials && _credentials.email);
$rootScope.starting = true;
$timeout(function() {
pinService.save(pin, _credentials.email, _credentials.password, function(err) {
_credentials.password = '';
_credentials = null;
$scope.askForPin = 0;
$rootScope.hasPin = true;
$scope.createDefaultWallet();
});
}, 100);
};
$scope.setStep = function(step) {
$scope.error = null;
$scope.createStep = step;
$scope.hideForWP = false;
$timeout(function() {
$scope.$digest();
}, 1);
};
$scope.selectStorage = function(storage) {
$scope.useLocalstorage = storage == 'local';
$scope.hideForWP = false;
$timeout(function() {
$scope.$digest();
}, 1);
};
$scope.goToEmail = function() {
$scope.createStep = 'email';
$scope.useEmail = !$scope.useLocalstorage;
};
$scope.setEmailOrUsername = function(form) {
$scope.userOrEmail = $scope.useLocalstorage ? form.username.$modelValue : form.email.$modelValue;
preconditions.checkState($scope.userOrEmail);
$scope.error = null;
$scope.hideForWP = false;
$scope.createStep = 'pass';
$timeout(function() {
$scope.$digest();
}, 1);
};
/* Last step. Will emit after creation so the UX gets updated */
$scope.createDefaultWallet = function() {
$rootScope.hideNavigation = false;
$rootScope.starting = true;
identityService.createDefaultWallet(function(err) {
$scope.askForPin = 0;
$rootScope.starting = null;
if (err) {
var msg = err.toString();
$scope.error = msg;
} else {
if (!$scope.useLocalstorage) {
$rootScope.pleaseConfirmEmail = true;
}
}
});
};
$scope._doCreateProfile = function(emailOrUsername, password, cb) {
preconditions.checkArgument(_.isString(emailOrUsername));
preconditions.checkArgument(_.isString(password));
$rootScope.hideNavigation = false;
identityService.create(emailOrUsername, password, function(err) {
if (err) {
var msg = err.toString();
$scope.createStep = 'email';
if (msg.indexOf('EEXIST') >= 0 || msg.indexOf('BADC') >= 0) {
msg = 'This profile already exists'
}
if (msg.indexOf('EMAILERROR') >= 0) {
msg = 'Could not send verification email. Please check your email address.';
}
return cb(msg);
} else {
// mobile
if ($scope.isMobile) {
$rootScope.starting = null;
_credentials = {
email: emailOrUsername,
password: password,
};
$scope.askForPin = 1;
$scope.hideForWP = 0;
$rootScope.hideNavigation = true;
$timeout(function() {
$rootScope.$digest();
}, 1);
return;
} else {
$scope.createDefaultWallet();
}
}
return cb();
});
};
$scope.saveSettings = function(cb) {
var plugins = config.plugins;
plugins.EncryptedLocalStorage = false;
plugins.EncryptedInsightStorage = false;
var pluginName = $scope.useLocalstorage ? 'EncryptedLocalStorage' : 'EncryptedInsightStorage';
plugins[pluginName] = true;
configService.set({
plugins: plugins
}, cb);
};
$scope.createProfile = function(form) {
if (form && form.$invalid) {
$scope.error = 'Please enter the required fields';
return;
}
$scope.saveSettings(function(err) {
preconditions.checkState(!err, err);
$rootScope.starting = true;
$scope._doCreateProfile($scope.userOrEmail, form.password.$modelValue, function(err) {
if (err) {
$scope.error = err;
$scope.passwordStrength = null;
$rootScope.starting = false;
}
form.password.$setViewValue('');
form.password.$render();
form.repeatpassword.$setViewValue('');
form.repeatpassword.$render();
form.$setPristine();
$timeout(function() {
$rootScope.$digest();
}, 1);
});
});
};
});

View File

@ -1,204 +0,0 @@
'use strict';
var bitcore = require('bitcore');
angular.module('copayApp.controllers').controller('HistoryController',
function($scope, $rootScope, $filter, $timeout, $modal, rateService, notification, go) {
var w = $rootScope.wallet;
$rootScope.title = 'History';
$scope.loading = false;
$scope.generating = false;
$scope.lastShowed = false;
$scope.currentPage = 1;
$scope.itemsPerPage = 10;
$scope.nbPages = 0;
$scope.totalItems = 0;
$scope.blockchain_txs = [];
$scope.alternativeCurrency = [];
$scope.selectPage = function(page) {
$scope.paging = true;
$scope.currentPage = page;
$scope.update();
};
$scope.downloadHistory = function() {
var w = $rootScope.wallet;
if (!w) return;
var filename = "copay_history.csv";
var descriptor = {
columns: [{
label: 'Date',
property: 'ts',
type: 'date'
}, {
label: 'Amount (' + w.settings.unitName + ')',
property: 'amount',
type: 'number'
}, {
label: 'Amount (' + w.settings.alternativeIsoCode + ')',
property: 'alternativeAmount'
}, {
label: 'Action',
property: 'action'
}, {
label: 'AddressTo',
property: 'addressTo'
}, {
label: 'Comment',
property: 'comment'
}, ],
};
if (w.isShared()) {
descriptor.columns.push({
label: 'Signers',
property: function(obj) {
if (!obj.actionList) return '';
return _.map(obj.actionList, function(action) {
return w.publicKeyRing.nicknameForCopayer(action.cId);
}).join('|');
}
});
}
$scope.generating = true;
$scope._getTransactions(w, null, function(err, res) {
if (err) {
$scope.generating = false;
logger.error(err);
notification.error('Could not get transaction history');
return;
}
$scope._addRates(w, res.items, function(err) {
copay.csv.toCsv(res.items, descriptor, function(err, res) {
if (err) {
$scope.generating = false;
logger.error(err);
notification.error('Could not generate csv file');
return;
}
var csvContent = "data:text/csv;charset=utf-8," + res;
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
link.click();
$scope.generating = false;
$scope.$digest();
});
});
});
};
$scope.update = function() {
$scope.getTransactions();
};
$scope.show = function() {
$scope.loading = true;
setTimeout(function() {
$scope.update();
}, 1);
};
$scope._getTransactions = function(w, opts, cb) {
w.getTransactionHistory(opts, function(err, res) {
if (err) return cb(err);
if (!res) return cb();
var now = new Date();
var items = res.items;
_.each(items, function(tx) {
tx.ts = tx.minedTs || tx.sentTs;
tx.rateTs = Math.floor((tx.ts || now) / 1000);
tx.amount = $filter('noFractionNumber')(tx.amount);
});
return cb(null, res);
});
};
$scope._addRates = function(w, txs, cb) {
if (!txs || txs.length == 0) return cb();
var index = _.groupBy(txs, 'rateTs');
rateService.getHistoricRates(w.settings.alternativeIsoCode, _.keys(index), function(err, res) {
if (err || !res) return cb(err);
_.each(res, function(r) {
_.each(index[r.ts], function (tx) {
var alternativeAmount = (r.rate != null ? tx.amountSat * rateService.SAT_TO_BTC * r.rate : null);
tx.alternativeAmount = alternativeAmount ? $filter('noFractionNumber')(alternativeAmount, 2) : null;
});
});
return cb();
});
};
$scope.openTxModal = function(btx) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.btx = btx;
$scope.getShortNetworkName = function() {
var w = $rootScope.wallet;
return w.getNetworkName().substring(0, 4);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/tx-details.html',
windowClass: 'medium',
controller: ModalInstanceCtrl,
});
};
$scope.getTransactions = function() {
var w = $rootScope.wallet;
if (!w) return;
$scope.blockchain_txs = w.cached_txs || [];
$scope.loading = true;
$scope._getTransactions(w, {
currentPage: $scope.currentPage,
itemsPerPage: $scope.itemsPerPage,
}, function(err, res) {
if (err) throw err;
if (!res) {
$scope.loading = false;
$scope.lastShowed = false;
return;
}
var items = res.items;
$scope._addRates(w, items, function(err) {
$timeout(function() {
$scope.$digest();
}, 1);
})
$scope.blockchain_txs = w.cached_txs = items;
$scope.nbPages = res.nbPages;
$scope.totalItems = res.nbItems;
$scope.loading = false;
$scope.paging = false;
setTimeout(function() {
$scope.$digest();
}, 1);
});
};
$scope.hasAction = function(actions, action) {
return actions.hasOwnProperty('create');
};
});

View File

@ -1,216 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('HomeController', function($scope, $rootScope, $timeout, $window, go, notification, identityService, Compatibility, pinService, applicationService, isMobile, isCordova, localstorageService) {
var KEY = 'CopayDisclaimer';
var ls = localstorageService;
var _credentials;
$scope.init = function() {
$scope.isMobile = isMobile.any();
$scope.isWindowsPhoneApp = isMobile.Windows() && isCordova;
$scope.hideForWP = 0;
$scope.attempt = 0;
$scope.digits = [];
$scope.defined = [];
$scope.askForPin = 0;
// This is only for backwards compat, insight api should link to #!/confirmed directly
if (getParam('confirmed')) {
var hashIndex = window.location.href.indexOf('/?');
window.location = window.location.href.substr(0, hashIndex) + '#!/confirmed';
return;
}
if ($rootScope.fromEmailConfirmation) {
$scope.confirmedEmail = true;
$rootScope.fromEmailConfirmation = false;
}
if ($rootScope.wallet) {
go.walletHome();
}
Compatibility.check($scope);
pinService.check(function(err, value) {
$rootScope.hasPin = value;
});
$scope.usingLocalStorage = config.plugins.EncryptedLocalStorage;
if (isCordova) {
ls.getItem(KEY, function(err, value) {
$scope.showDisclaimer = value ? null : true;
});
}
};
$scope.clear = function() {
pinService.clearPin($scope);
};
$scope.press = function(digit) {
pinService.pressPin($scope, digit);
};
$scope.skip = function () {
pinService.skipPin($scope);
};
$scope.agreeDisclaimer = function() {
ls.setItem(KEY, true, function(err) {
$scope.showDisclaimer = null;
});
};
$scope.formFocus = function() {
if ($scope.isWindowsPhoneApp) {
$scope.hideForWP = true;
$timeout(function() {
$scope.$digest();
}, 1);
}
};
$scope.openWithPin = function(pin) {
if (!pin) {
$scope.error = 'Please enter the required fields';
return;
}
$rootScope.starting = true;
$timeout(function() {
var credentials = pinService.get(pin, function(err, credentials) {
if (err || !credentials) {
$rootScope.starting = null;
$scope.error = 'Wrong PIN';
$scope.clear();
$timeout(function() {
$scope.error = null;
}, 2000);
return;
}
$scope.open(credentials.email, credentials.password);
});
}, 100);
};
$scope.openWallets = function() {
preconditions.checkState($rootScope.iden);
var iden = $rootScope.iden;
$rootScope.hideNavigation = false;
$rootScope.starting = true;
iden.openWallets();
};
$scope.createPin = function(pin) {
preconditions.checkArgument(pin);
preconditions.checkState($rootScope.iden);
preconditions.checkState(_credentials && _credentials.email);
$rootScope.starting = true;
$timeout(function() {
pinService.save(pin, _credentials.email, _credentials.password, function(err) {
_credentials.password = '';
_credentials = null;
$scope.askForPin = 0;
$rootScope.hasPin = true;
$rootScope.starting = null;
$scope.openWallets();
});
}, 100);
};
$scope.openWithCredentials = function(form) {
if (form && form.$invalid) {
$scope.error = 'Please enter the required fields';
return;
}
$timeout(function() {
$scope.open(form.email.$modelValue, form.password.$modelValue);
}, 100);
};
$scope.pinLogout = function() {
pinService.clear(function() {
copay.logger.debug('PIN erased');
delete $rootScope['hasPin'];
applicationService.restart();
});
};
$scope.open = function(email, password) {
$rootScope.starting = true;
identityService.open(email, password, function(err, iden) {
if (err) {
$rootScope.starting = false;
copay.logger.warn(err);
var identifier = $scope.usingLocalStorage ? 'username' : 'email';
if ((err.toString() || '').match('PNOTFOUND')) {
$scope.error = 'Invalid ' + identifier + ' or password';
if ($scope.attempt++ > 1) {
var storage = $scope.usingLocalStorage ? 'this device storage' : 'cloud storage';
$scope.error = 'Invalid ' + identifier + ' or password. You are trying to sign in using ' + storage + '. Change it on settings if necessary.';
};
$rootScope.hasPin = false;
pinService.clear(function() {});
} else if ((err.toString() || '').match('Connection')) {
$scope.error = 'Could not connect to Insight Server';
} else if ((err.toString() || '').match('Unable')) {
$scope.error = 'Unable to read data from the Insight Server';
} else {
$scope.error = 'Unknown error';
}
$timeout(function() {
$rootScope.$digest();
}, 1)
return;
}
// Open successfully?
if (iden) {
$scope.error = null;
$scope.confirmedEmail = false;
// mobile
if ($scope.isMobile && !$rootScope.hasPin) {
_credentials = {
email: email,
password: password,
};
$scope.askForPin = 1;
$rootScope.starting = false;
$rootScope.hideNavigation = true;
$timeout(function() {
$rootScope.$digest();
}, 1);
return;
}
// no mobile
else {
$scope.openWallets();
}
}
});
};
function getParam(sname) {
var params = location.search.substr(location.search.indexOf("?") + 1);
var sval = "";
params = params.split("&");
// split param and value into individual pieces
for (var i = 0; i < params.length; i++) {
var temp = params[i].split("=");
if ([temp[0]] == sname) {
sval = temp[1];
}
}
return sval;
}
});

View File

@ -1,103 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('HomeWalletController', function($scope, $rootScope, $timeout, $filter, $modal, rateService, notification, txStatus, identityService, isCordova) {
$scope.openTxModal = function(tx) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
var w = $rootScope.wallet;
$scope.error = null;
$scope.tx = tx;
$scope.registeredCopayerIds = w.getRegisteredCopayerIds();
$scope.loading = null;
$scope.getShortNetworkName = function() {
var w = $rootScope.wallet;
return w.getNetworkName().substring(0, 4);
};
$scope.sign = function(ntxid) {
if (isCordova) {
window.plugins.spinnerDialog.show(null, 'Signing transaction...', true);
}
$scope.loading = true;
$scope.error = null;
$timeout(function() {
w.signAndSend(ntxid, function(err, id, status) {
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
$scope.loading = false;
if (err) {
$scope.error = 'Transaction could not send. Please try again.';
$scope.$digest();
}
else {
$modalInstance.close(status);
}
});
}, 100);
};
$scope.reject = function(ntxid) {
if (isCordova) {
window.plugins.spinnerDialog.show(null, 'Rejecting transaction...', true);
}
$scope.loading = true;
$scope.error = null;
$timeout(function() {
w.reject(ntxid, function(err, status) {
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
$scope.loading = false;
if (err) {
$scope.error = err;
$scope.$digest();
}
else {
$modalInstance.close(status);
}
});
}, 100);
};
$scope.broadcast = function(ntxid) {
if (isCordova) {
window.plugins.spinnerDialog.show(null, 'Sending transaction...', true);
}
$scope.loading = true;
$scope.error = null;
$timeout(function() {
w.issueTx(ntxid, function(err, txid, status) {
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
$scope.loading = false;
if (err) {
$scope.error = 'Transaction could not send. Please try again.';
$scope.$digest();
}
else {
$modalInstance.close(status);
}
});
}, 100);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
var modalInstance = $modal.open({
templateUrl: 'views/modals/txp-details.html',
windowClass: 'medium',
controller: ModalInstanceCtrl,
});
modalInstance.result.then(function(status) {
txStatus.notify(status);
});
};
});

View File

@ -1,110 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('ImportController',
function($scope, $rootScope, $location, $timeout, identityService, notification, isMobile, isCordova, Compatibility) {
$rootScope.title = 'Import wallet';
$scope.importStatus = 'Importing wallet - Reading backup...';
$scope.hideAdv = true;
$scope.isSafari = isMobile.Safari();
$scope.isCordova = isCordova;
$scope.importOpts = {};
$rootScope.hideWalletNavigation = true;
window.ignoreMobilePause = true;
$scope.$on('$destroy', function() {
$timeout(function(){
window.ignoreMobilePause = false;
}, 100);
});
Compatibility.check($scope);
var reader = new FileReader();
var updateStatus = function(status) {
$scope.importStatus = status;
}
$scope.getFile = function() {
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
var encryptedObj = evt.target.result;
updateStatus('Importing wallet - Procesing backup...');
identityService.importWallet(encryptedObj, $scope.password, {}, function(err) {
if (err) {
$rootScope.starting = false;
$scope.error = 'Could not read wallet. Please check your password';
$timeout(function() {
$rootScope.$digest();
}, 1);
}
});
}
}
};
$scope.import = function(form) {
if (form.$invalid) {
$scope.error = 'There is an error in the form';
return;
}
var backupFile = $scope.file;
var backupText = form.backupText.$modelValue;
var backupOldWallet = form.backupOldWallet.$modelValue;
var password = form.password.$modelValue;
if (backupOldWallet) {
backupText = backupOldWallet.value;
}
if (!backupFile && !backupText) {
$scope.error = 'Please, select your backup file';
return;
}
$rootScope.starting = true;
$timeout(function() {
$scope.importOpts = {};
var skipFields = [];
if ($scope.skipPublicKeyRing)
skipFields.push('publicKeyRing');
if ($scope.skipTxProposals)
skipFields.push('txProposals');
if (skipFields)
$scope.importOpts.skipFields = skipFields;
if (backupFile) {
reader.readAsBinaryString(backupFile);
} else {
updateStatus('Importing wallet - Procesing backup...');
identityService.importWallet(backupText, $scope.password, $scope.importOpts, function(err) {
if (err) {
$rootScope.starting = false;
$scope.error = 'Could not read wallet. Please check your password';
$timeout(function() {
$rootScope.$digest();
}, 1);
}
});
}
}, 100);
};
$scope.$on("$destroy", function () {
$rootScope.hideWalletNavigation = false;
});
});

View File

@ -1,34 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('IndexController', function($scope, $timeout, go, isCordova, identityService, notification) {
$scope.init = function() {
};
$scope.resendVerificationEmail = function() {
$scope.loading = true;
identityService.resendVerificationEmail(function(err) {
if (err) {
notification.error('Could not send email', 'There was a problem sending the verification email.');
}
else {
notification.success('Email sent', 'Check your inbox and confirms the email');
$scope.hideReSendButton = true;
}
$scope.loading = null;
$timeout(function() {
$scope.$digest();
}, 1);
return;
});
};
$scope.openMenu = function() {
go.swipe(true);
};
$scope.closeMenu = function() {
go.swipe();
};
});

View File

@ -1,160 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('JoinController',
function($scope, $rootScope, $timeout, isMobile, notification, identityService) {
$rootScope.fromSetup = false;
$scope.loading = false;
$scope.isMobile = isMobile.any();
$rootScope.title = 'Join shared wallet';
$rootScope.hideWalletNavigation = true;
// QR code Scanner
var cameraInput;
var video;
var canvas;
var $video;
var context;
var localMediaStream;
$scope.hideAdv = true;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (!window.cordova && !navigator.getUserMedia)
$scope.disableScanner = 1;
var _scan = function(evt) {
if (localMediaStream) {
context.drawImage(video, 0, 0, 300, 225);
try {
qrcode.decode();
} catch (e) {
//qrcodeError(e);
}
}
$timeout(_scan, 500);
};
var _successCallback = function(stream) {
video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
localMediaStream = stream;
video.play();
$timeout(_scan, 1000);
};
var _scanStop = function() {
$scope.showScanner = false;
if (!$scope.isMobile) {
if (localMediaStream && localMediaStream.stop) localMediaStream.stop();
localMediaStream = null;
video.src = '';
}
};
var _videoError = function(err) {
_scanStop();
};
qrcode.callback = function(data) {
_scanStop();
$scope.$apply(function() {
$scope.connectionId = data;
$scope.joinForm.connectionId.$setViewValue(data);
$scope.joinForm.connectionId.$render();
});
};
$scope.cancelScanner = function() {
_scanStop();
};
$scope.openScanner = function() {
if (window.cordova) return $scope.scannerIntent();
$scope.showScanner = true;
// Wait a moment until the canvas shows
$timeout(function() {
canvas = document.getElementById('qr-canvas');
context = canvas.getContext('2d');
if ($scope.isMobile) {
cameraInput = document.getElementById('qrcode-camera');
cameraInput.addEventListener('change', _scan, false);
} else {
video = document.getElementById('qrcode-scanner-video');
$video = angular.element(video);
canvas.width = 300;
canvas.height = 225;
context.clearRect(0, 0, 300, 225);
navigator.getUserMedia({
video: true
}, _successCallback, _videoError);
}
}, 500);
};
$scope.scannerIntent = function() {
window.ignoreMobilePause = true;
cordova.plugins.barcodeScanner.scan(
function onSuccess(result) {
$timeout(function(){
window.ignoreMobilePause = false;
}, 100);
if (result.cancelled) return;
$scope.connectionId = result.text;
$rootScope.$digest();
},
function onError(error) {
$timeout(function(){
window.ignoreMobilePause = false;
}, 100);
alert('Scanning error');
});
}
$scope.join = function(form) {
if (form && form.$invalid) {
notification.error('Error', 'Please enter the required fields');
return;
}
$rootScope.starting = true;
identityService.joinWallet({
secret: $scope.connectionId,
nickname: $scope.nickname,
privateHex: $scope.private,
}, function(err) {
$rootScope.starting = false;
if (err) {
if (err === 'joinError')
notification.error('Fatal error connecting to Insight server');
else if (err === 'walletFull')
notification.error('The wallet is full');
else if (err === 'walletAlreadyExists')
notification.error('Wallet already exists', 'Cannot join again from the same profile');
else if (err === 'badNetwork')
notification.error('Network Error', 'Wallet network configuration missmatch');
else if (err === 'badSecret')
notification.error('Bad secret', 'The secret string you entered is invalid');
else {
notification.error('Error', err.message || err);
}
}
$timeout(function () { $scope.$digest(); }, 1);
});
}
$scope.$on("$destroy", function () {
$rootScope.hideWalletNavigation = false;
});
});

View File

@ -1,183 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('MoreController',
function($scope, $rootScope, $location, $filter, $timeout, balanceService, notification, rateService, backupService, identityService, isMobile, isCordova, go, pendingTxsService) {
var w = $rootScope.wallet;
var max = $rootScope.quotaPerItem;
$scope.isSafari = isMobile.Safari();
$scope.isCordova = isCordova;
$scope.wallet = w;
$scope.error = null;
$scope.success = null;
var bits = w.sizes().total;
w.kb = $filter('noFractionNumber')(bits / 1000, 1);
if (max) {
w.usage = $filter('noFractionNumber')(bits / max * 100, 0);
}
$rootScope.title = 'Settings';
$scope.unitOpts = [{
name: 'Satoshis (100,000,000 satoshis = 1BTC)',
shortName: 'SAT',
value: 1,
decimals: 0
}, {
name: 'bits (1,000,000 bits = 1BTC)',
shortName: 'bits',
value: 100,
decimals: 2
}, {
name: 'mBTC (1,000 mBTC = 1BTC)',
shortName: 'mBTC',
value: 100000,
decimals: 5
}, {
name: 'BTC',
shortName: 'BTC',
value: 100000000,
decimals: 8
}];
$scope.selectedAlternative = {
name: w.settings.alternativeName,
isoCode: w.settings.alternativeIsoCode
};
$scope.alternativeOpts = rateService.isAvailable() ?
rateService.listAlternatives() : [$scope.selectedAlternative];
rateService.whenAvailable(function() {
$scope.alternativeOpts = rateService.listAlternatives();
for (var ii in $scope.alternativeOpts) {
if (w.settings.alternativeIsoCode === $scope.alternativeOpts[ii].isoCode) {
$scope.selectedAlternative = $scope.alternativeOpts[ii];
}
}
});
for (var ii in $scope.unitOpts) {
if (w.settings.unitName === $scope.unitOpts[ii].shortName) {
$scope.selectedUnit = $scope.unitOpts[ii];
break;
}
}
$scope.hideAdv = true;
$scope.hidePriv = true;
$scope.hideSecret = true;
if (w) {
$scope.priv = w.privateKey.toObj().extendedPrivateKeyString;
$scope.secret = w.getSecret();
}
setTimeout(function() {
$scope.$digest();
}, 1);
$scope.save = function() {
var w = $rootScope.wallet;
w.changeSettings({
unitName: $scope.selectedUnit.shortName,
unitToSatoshi: $scope.selectedUnit.value,
unitDecimals: $scope.selectedUnit.decimals,
alternativeName: $scope.selectedAlternative.name,
alternativeIsoCode: $scope.selectedAlternative.isoCode,
});
notification.success('Success', $filter('translate')('settings successfully updated'));
balanceService.update(w, function() {
pendingTxsService.update();
$rootScope.$digest();
});
};
$scope.purge = function(deleteAll) {
var removed = w.purgeTxProposals(deleteAll);
if (removed) {
balanceService.update(w, function() {
$rootScope.$digest();
}, true);
}
notification.info('Transactions Proposals Purged', removed + ' ' + $filter('translate')('transaction proposal purged'));
};
$scope.updateIndexes = function() {
var w = $rootScope.wallet;
notification.info('Scaning for transactions', 'Using derived addresses from your wallet');
w.updateIndexes(function(err) {
notification.info('Scan Ended', 'Updating balance');
if (err) {
notification.error('Error', $filter('translate')('Error updating indexes: ') + err);
}
balanceService.update(w, function() {
notification.info('Finished', 'The balance is updated using the derived addresses');
w.sendIndexes();
$rootScope.$digest();
}, true);
});
};
$scope.deleteWallet = function() {
$scope.loading = true;
$timeout(function() {
identityService.deleteWallet(w, function(err) {
$scope.loading = false;
if (err) {
$scope.error = err.message || err;
copay.logger.warn(err);
$timeout(function () { $scope.$digest(); });
} else {
if ($rootScope.wallet) {
go.walletHome();
}
$timeout(function() {
notification.success('Success', 'The wallet "' + (w.name || w.id) + '" was deleted');
});
}
});
}, 100);
};
$scope.copyText = function(text) {
if (isCordova) {
window.cordova.plugins.clipboard.copy(text);
window.plugins.toast.showShortCenter('Copied to clipboard');
}
};
$scope.downloadWalletBackup = function() {
backupService.walletDownload(w);
};
$scope.viewWalletBackup = function() {
$scope.loading = true;
$timeout(function() {
$scope.backupWalletPlainText = backupService.walletEncrypted(w);
}, 100);
};
$scope.copyWalletBackup = function() {
var ew = backupService.walletEncrypted(w);
window.cordova.plugins.clipboard.copy(ew);
window.plugins.toast.showShortCenter('Copied to clipboard');
};
$scope.sendWalletBackup = function() {
if (isMobile.Android() || isMobile.Windows()) {
window.ignoreMobilePause = true;
}
window.plugins.toast.showShortCenter('Preparing backup...');
var name = (w.name || w.id);
var ew = backupService.walletEncrypted(w);
var properties = {
subject: 'Copay Wallet Backup: ' + name,
body: 'Here is the encrypted backup of the wallet '
+ name + ': \n\n' + ew
+ '\n\n To import this backup, copy all text between {...}, including the symbols {}',
isHtml: false
};
window.plugin.email.open(properties);
};
});

View File

@ -1,20 +0,0 @@
var bitcore = require('bitcore');
angular.module('copayApp.controllers').controller('paymentUriController', function($rootScope, $scope, $routeParams, $location, go) {
// Build bitcoinURI with querystring
var query = [];
angular.forEach($location.search(), function(value, key) {
query.push(key + "=" + value);
});
var queryString = query ? query.join("&") : null;
var bitcoinURI = $routeParams.data + ( queryString ? '?' + queryString : '');
var uri = new bitcore.BIP21(bitcoinURI);
if (uri && uri.address && (_.isString(uri.address) || uri.address.isValid()) ) {
copay.logger.debug('Payment Intent:', bitcoinURI);
$rootScope.pendingPayment = bitcoinURI;
}
go.home();
});

View File

@ -1,106 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('ReceiveController',
function($scope, $rootScope, $timeout, $modal, isCordova, isMobile) {
$scope.newAddr = function() {
var w = $rootScope.wallet;
var lastAddr = w.generateAddress(null);
$scope.setAddressList();
$scope.addr = lastAddr;
};
$scope.copyAddress = function(addr) {
if (isCordova) {
window.cordova.plugins.clipboard.copy('bitcoin:' + addr);
window.plugins.toast.showShortCenter('Copied to clipboard');
}
};
$scope.shareAddress = function(addr) {
if (isCordova) {
if (isMobile.Android() || isMobile.Windows()) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null);
}
};
$scope.init = function() {
$rootScope.title = 'Receive';
$scope.showAll = false;
$scope.isCordova = isCordova;
var w = $rootScope.wallet;
var lastAddr = _.first(w.getAddressesOrdered());
var balance = w.balanceInfo.balanceByAddr;
$scope.setAddressList();
while (balance && balance[lastAddr] > 0) {
$scope.loading = true;
lastAddr = w.generateAddress(null);
};
$scope.loading = false;
$scope.addr = lastAddr;
};
$scope.openAddressModal = function(address) {
var scope = $scope;
var ModalInstanceCtrl = function($scope, $modalInstance, address) {
$scope.address = address;
$scope.isCordova = isCordova;
$scope.copyAddress = function(addr) {
scope.copyAddress(addr);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/qr-address.html',
windowClass: 'small',
controller: ModalInstanceCtrl,
resolve: {
address: function() {
return address;
}
}
});
};
$scope.toggleShowAll = function() {
$scope.showAll = !$scope.showAll;
$scope.setAddressList();
};
$scope.setAddressList = function() {
if ($scope.showAll) {
var w = $rootScope.wallet;
var balance = w.balanceInfo.balanceByAddr;
var addresses = w.getAddressesOrdered();
if (addresses) {
$scope.addrLength = addresses.length;
if (!$scope.showAll)
addresses = addresses.slice(0, 3);
var list = [];
_.each(addresses, function(address, index) {
list.push({
'index': index,
'address': address,
'balance': balance ? balance[address] : null,
'isChange': w.addressIsChange(address),
});
});
$scope.addresses = list;
}
} else {
$scope.addresses = [];
}
};
}
);

View File

@ -1,602 +0,0 @@
'use strict';
var bitcore = require('bitcore');
var preconditions = require('preconditions').singleton();
angular.module('copayApp.controllers').controller('SendController',
function($scope, $rootScope, $window, $timeout, $modal, $filter, notification, isMobile, rateService, txStatus, isCordova) {
$scope.init = function() {
var w = $rootScope.wallet;
preconditions.checkState(w);
preconditions.checkState(w.settings.unitToSatoshi);
$scope.isMobile = isMobile.any();
$scope.isWindowsPhoneApp = isMobile.Windows() && isCordova;
$rootScope.wpInputFocused = false;
$scope.isShared = w.isShared();
$scope.requiresMultipleSignatures = w.requiresMultipleSignatures();
$rootScope.title = $scope.requiresMultipleSignatures ? 'Send Proposal' : 'Send';
$scope.loading = false;
$scope.error = $scope.success = null;
$scope.alternativeName = w.settings.alternativeName;
$scope.alternativeIsoCode = w.settings.alternativeIsoCode;
$scope.isRateAvailable = false;
$scope.rateService = rateService;
$scope.showScanner = false;
$scope.myId = w.getMyCopayerId();
$scope.isMobile = isMobile.any();
if ($rootScope.pendingPayment) {
$timeout(function() {
$scope.setFromUri($rootScope.pendingPayment)
$rootScope.pendingPayment = null;
}, 100);
}
$scope.setInputs();
$scope.setScanner();
rateService.whenAvailable(function() {
$scope.isRateAvailable = true;
$scope.$digest();
});
};
if (isCordova) {
var openScannerCordova = $rootScope.$on('dataScanned', function(event, data) {
$scope.sendForm.address.$setViewValue(data);
$scope.sendForm.address.$render();
});
$scope.$on('$destroy', function() {
openScannerCordova();
});
}
$scope.formFocus = function(what) {
if (!$scope.isWindowsPhoneApp) return
if (!what) {
$rootScope.wpInputFocused = false;
$scope.hideAddress = false;
$scope.hideAmount = false;
} else {
$rootScope.wpInputFocused = true;
if (what == 'amount') {
$scope.hideAddress = true;
} else if (what == 'msg') {
$scope.hideAddress = true;
$scope.hideAmount = true;
}
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
$scope.setInputs = function() {
var w = $rootScope.wallet;
var unitToSat = w.settings.unitToSatoshi;
var satToUnit = 1 / unitToSat;
/**
* Setting the two related amounts as properties prevents an infinite
* recursion for watches while preserving the original angular updates
*
*/
Object.defineProperty($scope,
"_alternative", {
get: function() {
return this.__alternative;
},
set: function(newValue) {
this.__alternative = newValue;
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
this._amount = parseFloat(
(rateService.fromFiat(newValue, $scope.alternativeIsoCode) * satToUnit).toFixed(w.settings.unitDecimals), 10);
} else {
this._amount = 0;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_amount", {
get: function() {
return this.__amount;
},
set: function(newValue) {
this.__amount = newValue;
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
this.__alternative = parseFloat(
(rateService.toFiat(newValue * unitToSat, $scope.alternativeIsoCode)).toFixed(2), 10);
} else {
this.__alternative = 0;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty($scope,
"_address", {
get: function() {
return this.__address;
},
set: function(newValue) {
this.__address = $scope.onAddressChange(newValue);
},
enumerable: true,
configurable: true
});
};
$scope.setScanner = function() {
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL ||
window.mozURL || window.msURL;
if (!window.cordova && !navigator.getUserMedia)
$scope.disableScanner = 1;
};
$scope.setError = function(err) {
var w = $rootScope.wallet;
copay.logger.warn(err);
var msg = err.toString();
if (msg.match('BIG'))
msg = 'The transaction have too many inputs. Try creating many transactions for smaller amounts'
if (msg.match('totalNeededAmount') || msg.match('unspent not set'))
msg = 'Insufficient funds'
if (msg.match('expired'))
msg = 'The payment request has expired';
if (msg.match('XMLHttpRequest'))
msg = 'Error when sending to the blockchain. Resend it from Home';
var message = 'The transaction' + ($scope.requiresMultipleSignatures ? ' proposal' : '') +
' could not be created: ' + msg;
$scope.error = message;
$timeout(function() {
$scope.$digest();
}, 1);
};
$scope.submitForm = function(form) {
var w = $rootScope.wallet;
var unitToSat = w.settings.unitToSatoshi;
if (form.$invalid) {
$scope.error = 'Unable to send transaction proposal';
return;
}
if (isCordova) {
window.plugins.spinnerDialog.show(null, 'Creating transaction...', true);
}
$scope.loading = true;
if ($scope.isWindowsPhoneApp)
$rootScope.wpInputFocused = true;
$timeout(function () {
var comment = form.comment.$modelValue;
var merchantData = $scope._merchantData;
var address, amount;
if (!merchantData) {
address = form.address.$modelValue;
amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0));
}
w.spend({
merchantData: merchantData,
toAddress: address,
amountSat: amount,
comment: comment,
}, function (err, txid, status) {
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
$scope.loading = false;
if ($scope.isWindowsPhoneApp)
$rootScope.wpInputFocused = false;
if (err) {
$scope.setError(err);
}
else {
txStatus.notify(status);
$scope.resetForm();
}
});
}, 100);
};
// QR code Scanner
var cameraInput;
var video;
var canvas;
var $video;
var context;
var localMediaStream;
var _scan = function(evt) {
if ($scope.isMobile) {
$scope.scannerLoading = true;
var files = evt.target.files;
if (files.length === 1 && files[0].type.indexOf('image/') === 0) {
var file = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var mpImg = new MegaPixImage(file);
mpImg.render(canvas, {
maxWidth: 200,
maxHeight: 200,
orientation: 6
});
$timeout(function() {
qrcode.width = canvas.width;
qrcode.height = canvas.height;
qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height);
try {
qrcode.decode();
} catch (e) {
// error decoding QR
}
}, 1500);
};
})(file);
// Read in the file as a data URL
reader.readAsDataURL(file);
}
} else {
if (localMediaStream) {
context.drawImage(video, 0, 0, 300, 225);
try {
qrcode.decode();
} catch (e) {
//qrcodeError(e);
}
}
$timeout(_scan, 500);
}
};
var _successCallback = function(stream) {
video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
localMediaStream = stream;
video.play();
$timeout(_scan, 1000);
};
var _scanStop = function() {
$scope.scannerLoading = false;
$scope.showScanner = false;
if (!$scope.isMobile) {
if (localMediaStream && localMediaStream.stop) localMediaStream.stop();
localMediaStream = null;
video.src = '';
}
};
var _videoError = function(err) {
_scanStop();
};
qrcode.callback = function(data) {
_scanStop();
$scope.$apply(function() {
$scope.sendForm.address.$setViewValue(data);
$scope.sendForm.address.$render();
});
};
$scope.cancelScanner = function() {
_scanStop();
};
$scope.openScanner = function() {
$scope.showScanner = true;
// Wait a moment until the canvas shows
$timeout(function() {
canvas = document.getElementById('qr-canvas');
context = canvas.getContext('2d');
if ($scope.isMobile) {
cameraInput = document.getElementById('qrcode-camera');
cameraInput.addEventListener('change', _scan, false);
} else {
video = document.getElementById('qrcode-scanner-video');
$video = angular.element(video);
canvas.width = 300;
canvas.height = 225;
context.clearRect(0, 0, 300, 225);
navigator.getUserMedia({
video: true
}, _successCallback, _videoError);
}
}, 500);
};
$scope.setTopAmount = function() {
var w = $rootScope.wallet;
var form = $scope.sendForm;
if (form) {
form.amount.$setViewValue(w.balanceInfo.topAmount);
form.amount.$render();
form.amount.$isValid = true;
}
};
$scope.setForm = function(to, amount, comment) {
var form = $scope.sendForm;
if (to) {
form.address.$setViewValue(to);
form.address.$isValid = true;
form.address.$render();
$scope.lockAddress = true;
}
if (amount) {
form.amount.$setViewValue("" + amount);
form.amount.$isValid = true;
form.amount.$render();
$scope.lockAmount = true;
}
if (comment) {
form.comment.$setViewValue(comment);
form.comment.$isValid = true;
form.comment.$render();
}
};
$scope.resetForm = function() {
var form = $scope.sendForm;
$scope.fetchingURL = null;
$scope._merchantData = $scope._domain = null;
$scope.lockAddress = false;
$scope.lockAmount = false;
$scope._amount = $scope._address = null;
form.amount.$pristine = true;
form.amount.$setViewValue('');
form.amount.$render();
form.comment.$setViewValue('');
form.comment.$render();
form.$setPristine();
if (form.address) {
form.address.$pristine = true;
form.address.$setViewValue('');
form.address.$render();
}
$timeout(function() {
$rootScope.$digest();
}, 1);
};
var $oscope = $scope;
$scope.openPPModal = function(merchantData) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
var w = $rootScope.wallet;
var satToUnit = 1 / w.settings.unitToSatoshi;
$scope.md = merchantData;
$scope.alternative = $oscope._alternative;
$scope.alternativeIsoCode = $oscope.alternativeIsoCode;
$scope.isRateAvailable = $oscope.isRateAvailable;
$scope.unitTotal = (merchantData.total * satToUnit).toFixed(w.settings.unitDecimals);
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/paypro.html',
windowClass: 'medium',
controller: ModalInstanceCtrl,
});
};
$scope.setFromPayPro = function(uri) {
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
if (isChromeApp) {
$scope.error = 'Payment Protocol not yet supported on ChromeApp';
return;
}
var w = $rootScope.wallet;
var satToUnit = 1 / w.settings.unitToSatoshi;
$scope.fetchingURL = uri;
$scope.loading = true;
// Payment Protocol URI (BIP-72)
w.fetchPaymentRequest({
url: uri
}, function(err, merchantData) {
$scope.loading = false;
$scope.fetchingURL = null;
if (err) {
copay.logger.warn(err);
$scope.resetForm();
var msg = err.toString();
if (msg.match('HTTP')) {
msg = 'Could not fetch payment information';
}
$scope.error = msg;
} else {
$scope._merchantData = merchantData;
$scope._domain = merchantData.domain;
$scope.setForm(null, (merchantData.total * satToUnit).toFixed(w.settings.unitDecimals));
}
});
};
$scope.setFromUri = function(uri) {
function sanitizeUri(uri) {
// Fixes when a region uses comma to separate decimals
var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
var match = regex.exec(uri);
if (!match || match.length === 0) {
return uri;
}
var value = match[0].replace(',', '.');
var newUri = uri.replace(regex, value);
return newUri;
};
var w = $rootScope.wallet;
var satToUnit = 1 / w.settings.unitToSatoshi;
var form = $scope.sendForm;
uri = sanitizeUri(uri);
var parsed = new bitcore.BIP21(uri);
if (!parsed.isValid() || !parsed.address.isValid()) {
$scope.error = 'Invalid bitcoin URL';
form.address.$isValid = false;
return uri;
};
var addr = parsed.address.toString();
if (parsed.data.merchant)
return $scope.setFromPayPro(parsed.data.merchant);
var amount = (parsed.data && parsed.data.amount) ?
((parsed.data.amount * 100000000).toFixed(0) * satToUnit).toFixed(w.settings.unitDecimals) : 0;
$scope.setForm(addr, amount, parsed.data.message, true);
return addr;
};
$scope.onAddressChange = function(value) {
$scope.error = $scope.success = null;
if (!value) return '';
if (value.indexOf('bitcoin:') === 0) {
return $scope.setFromUri(value);
} else if (/^https?:\/\//.test(value)) {
return $scope.setFromPayPro(value);
}
return value;
};
$scope.openAddressBook = function() {
var w = $rootScope.wallet;
var modalInstance = $modal.open({
templateUrl: 'views/modals/address-book.html',
windowClass: 'large',
controller: function($scope, $modalInstance) {
$scope.showForm = null;
$scope.addressBook = w.addressBook;
$scope.hasEntry = function() {
return _.keys($scope.addressBook).length > 0 ? true : false;
};
$scope.toggleAddressBookEntry = function(key) {
w.toggleAddressBookEntry(key);
};
$scope.copyToSend = function(addr) {
$modalInstance.close(addr);
};
$scope.cancel = function(form) {
$scope.error = $scope.success = $scope.newaddress = $scope.newlabel = null;
clearForm(form);
$scope.toggleForm();
};
$scope.toggleForm = function() {
$scope.showForm = !$scope.showForm;
};
var clearForm = function(form) {
form.newaddress.$pristine = true;
form.newaddress.$setViewValue('');
form.newaddress.$render();
form.newlabel.$pristine = true;
form.newlabel.$setViewValue('');
form.newlabel.$render();
form.$setPristine();
};
// TODO change to modal
$scope.submitAddressBook = function(form) {
if (form.$invalid) {
return;
}
$scope.loading = true;
$timeout(function() {
var errorMsg;
var entry = {
"address": form.newaddress.$modelValue,
"label": form.newlabel.$modelValue
};
try {
w.setAddressBook(entry.address, entry.label);
} catch (e) {
copay.logger.warn(e);
errorMsg = e.message;
}
if (errorMsg) {
$scope.error = errorMsg;
} else {
clearForm(form);
$scope.toggleForm();
notification.success('Entry created', 'New addressbook entry created')
}
$scope.loading = false;
$rootScope.$digest();
}, 100);
return;
};
$scope.close = function() {
$modalInstance.dismiss('cancel');
};
},
});
modalInstance.result.then(function(addr) {
$scope.setForm(addr);
});
};
});

View File

@ -1,86 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('SettingsController', function($scope, $rootScope, $window, $route, $location, notification, configService) {
$scope.title = 'Settings';
$scope.insightLivenet = config.network.livenet.url;
$scope.insightTestnet = config.network.testnet.url;
$scope.defaultLogLevel = config.logLevel || 'log';
var logLevels = copay.logger.getLevels();
$scope.availableLogLevels = [];
for (var key in logLevels) {
$scope.availableLogLevels.push({
'name': key
});
}
$scope.availableStorages = [{
name: 'In the cloud (Insight server)',
pluginName: 'EncryptedInsightStorage',
}, {
name: 'On this device (localstorage)',
pluginName: 'EncryptedLocalStorage',
},
// {
// name: 'GoogleDrive',
// pluginName: 'GoogleDrive',
// }
];
_.each($scope.availableStorages, function(v) {
if (config.plugins[v.pluginName])
$scope.selectedStorage = v;
});
for (var ii in $scope.availableLogLevels) {
if ($scope.defaultLogLevel === $scope.availableLogLevels[ii].name) {
$scope.selectedLogLevel = $scope.availableLogLevels[ii];
break;
}
}
$scope.save = function() {
$scope.insightLivenet = copay.Insight.setCompleteUrl($scope.insightLivenet);
$scope.insightTestnet = copay.Insight.setCompleteUrl($scope.insightTestnet);
var insightSettings = {
livenet: {
url: $scope.insightLivenet,
transports: ['polling'],
},
testnet: {
url: $scope.insightTestnet,
transports: ['polling'],
},
}
var plugins = {};
plugins[$scope.selectedStorage.pluginName] = true;
configService.set({
network: insightSettings,
plugins: plugins,
logLevel: $scope.selectedLogLevel.name,
EncryptedInsightStorage: _.extend(config.EncryptedInsightStorage, {
url: insightSettings.livenet.url + '/api/email'
}),
rates: _.extend(config.rates, {
url: insightSettings.livenet.url + '/api/rates'
}),
},
function() {
notification.success('Settings saved',"Settings were saved");
$location.path('/');
});
};
$scope.reset = function() {
configService.reset(function() {
notification.success('Settings reseted',"Settings were reseted");
$location.path('/');
});
};
});

View File

@ -1,121 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('SidebarController', function($scope, $rootScope, $location, $timeout, identityService, isMobile, isCordova, go) {
$scope.isMobile = isMobile.any();
$scope.isCordova = isCordova;
$scope.username = $rootScope.iden ? $rootScope.iden.getName() : '';
$scope.menu = [{
'title': 'Home',
'icon': 'icon-home',
'link': 'homeWallet'
}, {
'title': 'Receive',
'icon': 'icon-receive',
'link': 'receive'
}, {
'title': 'Send',
'icon': 'icon-paperplane',
'link': 'send'
}, {
'title': 'History',
'icon': 'icon-history',
'link': 'history'
}];
$scope.signout = function() {
identityService.signout();
};
$scope.isActive = function(item) {
return item.link && item.link == $location.path().split('/')[1];
};
$scope.switchWallet = function(wid) {
$scope.walletSelection = false;
identityService.setFocusedWallet(wid);
go.walletHome();
};
$scope.toggleWalletSelection = function() {
$scope.walletSelection = !$scope.walletSelection;
if (!$scope.walletSelection) return;
$scope.setWallets();
};
$scope.openScanner = function() {
window.ignoreMobilePause = true;
cordova.plugins.barcodeScanner.scan(
function onSuccess(result) {
$timeout(function() {
window.ignoreMobilePause = false;
}, 100);
if (result.cancelled) return;
$timeout(function() {
var data = result.text;
$scope.$apply(function() {
$rootScope.$emit('dataScanned', data);
});
}, 1000);
},
function onError(error) {
$timeout(function() {
window.ignoreMobilePause = false;
}, 100);
alert('Scanning error');
}
);
go.send();
};
$scope.init = function() {
// This should be called only once.
// focused wallet change
if ($rootScope.wallet) {
$rootScope.$watch('wallet', function() {
$scope.walletSelection = false;
$scope.setWallets();
});
}
// wallet list change
if ($rootScope.iden) {
var iden = $rootScope.iden;
iden.on('newWallet', function() {
$scope.walletSelection = false;
$scope.setWallets();
});
iden.on('walletDeleted', function(wid) {
if (wid == $rootScope.wallet.id) {
copay.logger.debug('Deleted focused wallet:', wid);
// new focus
var newWid = $rootScope.iden.getLastFocusedWalletId();
if (newWid && $rootScope.iden.getWalletById(newWid)) {
identityService.setFocusedWallet(newWid);
} else {
copay.logger.debug('No wallets');
identityService.noFocusedWallet(newWid);
}
}
$scope.walletSelection = false;
$scope.setWallets();
});
}
};
$scope.setWallets = function() {
if (!$rootScope.iden) return;
var ret = _.filter($rootScope.iden.getWallets(), function(w) {
return w;
});
$scope.wallets = _.sortBy(ret, 'name');
};
$scope.openMenu = function() {
go.swipe(true);
};
});

View File

@ -1,9 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('UnsupportedController',
function($scope, $location) {
if (localStorage && localStorage.length > 0) {
$location.path('/');
}
}
);

View File

@ -1,34 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('VersionController',
function($scope, $rootScope, $http, $filter, notification) {
var w = $rootScope.wallet;
$scope.version = copay.version;
$scope.commitHash = copay.commitHash;
$scope.networkName = w ? w.getNetworkName() : '';
if (_.isUndefined($rootScope.checkVersion))
$rootScope.checkVersion = true;
if ($rootScope.checkVersion) {
$rootScope.checkVersion = false;
$http.get('https://api.github.com/repos/bitpay/copay/tags').success(function(data) {
var toInt = function(s) {
return parseInt(s);
};
var latestVersion = data[0].name.replace('v', '').split('.').map(toInt);
var currentVersion = copay.version.split('.').map(toInt);
var title = 'Copay ' + data[0].name + ' ' + $filter('translate')('available.');
var content;
if (currentVersion[0] < latestVersion[0]) {
content = 'It\'s important that you update your wallet at https://copay.io';
notification.version(title, content, true);
} else if (currentVersion[0] == latestVersion[0] && currentVersion[1] < latestVersion[1]) {
var content = 'Please update your wallet at https://copay.io';
notification.version(title, content, false);
}
});
}
});

View File

@ -1,432 +0,0 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var bitcore = require('bitcore');
var log = require('../util/log');
var AuthMessage = bitcore.AuthMessage;
var util = bitcore.util;
var nodeUtil = require('util');
var extend = nodeUtil._extend;
var io = require('socket.io-client');
var preconditions = require('preconditions').singleton();
function Network(opts) {
preconditions.checkArgument(opts);
preconditions.checkArgument(opts.url);
opts = opts || {};
this.maxPeers = opts.maxPeers || 12;
this.url = opts.url;
this.secretNumber = opts.secretNumber;
this.cleanUp();
this.socketOptions = {
reconnection: true,
'force new connection': true,
'secure': this.url.indexOf('https') === 0,
};
if (opts.transports) {
this.socketOptions['transports'] = opts.transports;
}
}
nodeUtil.inherits(Network, EventEmitter);
Network.prototype.cleanUp = function() {
this.started = false;
this.connectedPeers = [];
this.peerId = null;
this.privkey = null;
this.key = null;
this.copayerId = null;
this.allowedCopayerIds = null;
this.isInboundPeerAuth = [];
this.copayerForPeer = {};
this.criticalErr = '';
if (this.socket) {
log.info('Async DISCONNECT');
this.socket.disconnect();
this.socket.removeAllListeners();
this.socket = null;
}
this.removeAllListeners();
};
Network.parent = EventEmitter;
// Array helpers
Network._inArray = function(el, array) {
return array.indexOf(el) > -1;
};
Network._arrayPushOnce = function(el, array) {
var ret = false;
if (!Network._inArray(el, array)) {
array.push(el);
ret = true;
}
return ret;
};
Network._arrayRemove = function(el, array) {
var pos = array.indexOf(el);
if (pos >= 0) array.splice(pos, 1);
return array;
};
Network.prototype.connectedCopayers = function() {
var ret = [];
for (var i in this.connectedPeers) {
var copayerId = this.copayerForPeer[this.connectedPeers[i]];
if (copayerId) ret.push(copayerId);
}
return ret;
};
Network.prototype._sendHello = function(copayerId, secretNumber) {
this.send(copayerId, {
type: 'hello',
copayerId: this.copayerId,
secretNumber: secretNumber
});
};
Network.prototype._sendRejectConnection = function(copayerId) {
this.send(copayerId, {
type: 'rejectConnection',
copayerId: this.copayerId,
});
};
Network.prototype._deletePeer = function(peerId) {
delete this.isInboundPeerAuth[peerId];
delete this.copayerForPeer[peerId];
this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers);
};
Network.prototype._addCopayer = function(copayerId) {
var peerId = this.peerFromCopayer(copayerId);
this._addCopayerMap(peerId, copayerId);
Network._arrayPushOnce(peerId, this.connectedPeers);
};
Network.prototype._addConnectedCopayer = function(copayerId) {
this._addCopayer(copayerId);
this.emit('connect', copayerId);
};
Network.prototype.getKey = function() {
preconditions.checkState(this.privkey || this.key);
if (!this.key) {
var key = new bitcore.Key();
key.private = new Buffer(this.privkey, 'hex');
key.regenerateSync();
this.key = key;
}
return this.key;
};
//hex version of one's own nonce
Network.prototype.setHexNonce = function(networkNonce) {
if (networkNonce) {
if (networkNonce.length !== 16)
throw new Error('incorrect length of hex nonce');
this.networkNonce = new Buffer(networkNonce, 'hex');
} else
this.iterateNonce();
};
//hex version of copayers' nonces
Network.prototype.setHexNonces = function(networkNonces) {
for (var i in networkNonces) {
if (!this.networkNonces)
this.networkNonces = {};
if (networkNonces[i].length === 16)
this.networkNonces[i] = new Buffer(networkNonces[i], 'hex');
}
};
//for oneself
Network.prototype.getHexNonce = function() {
return this.networkNonce.toString('hex');
};
//for copayers
Network.prototype.getHexNonces = function() {
var networkNoncesHex = [];
for (var i in this.networkNonces) {
networkNoncesHex[i] = this.networkNonces[i].toString('hex');
}
return networkNoncesHex;
};
Network.prototype.iterateNonce = function() {
if (!this.networkNonce || this.networkNonce.length !== 8) {
this.networkNonce = new Buffer(8);
this.networkNonce.fill(0);
}
//the first 4 bytes of a nonce is a unix timestamp in seconds
//the second 4 bytes is just an iterated "sub" nonce
//the whole thing is interpreted as one big endian number
var noncep1 = this.networkNonce.slice(0, 4);
noncep1.writeUInt32BE(Math.floor(Date.now() / 1000), 0);
var noncep2uint = this.networkNonce.slice(4, 8).readUInt32BE(0);
var noncep2 = this.networkNonce.slice(4, 8);
noncep2.writeUInt32BE(noncep2uint + 1, 0);
this.networkNonce = Buffer.concat([noncep1, noncep2], 8);
return this.networkNonce;
};
Network.prototype.decode = function(enc) {
var sender = enc.pubkey;
var key = this.getKey();
var prevnonce = this.networkNonces ? this.networkNonces[sender] : undefined;
var opts = {
prevnonce: prevnonce
};
var decoded = AuthMessage.decode(key, enc, opts);
//if no error thrown in the last step, we can set the copayer's nonce
if (!this.networkNonces)
this.networkNonces = {};
this.networkNonces[sender] = decoded.nonce;
var payload = decoded.payload;
return payload;
};
Network.prototype._onMessage = function(enc) {
var sender = enc.pubkey;
try {
var payload = this.decode(enc);
} catch (e) {
this._deletePeer(sender);
return;
}
if (this.ignoreMessageFromTs && this.ignoreMessageFromTs === enc.ts) {
log.debug('Ignoring trailing message. Ts:', enc.ts);
return;
}
var self = this;
switch (payload.type) {
case 'hello':
if (typeof payload.secretNumber === 'undefined' || payload.secretNumber !== this.secretNumber) {
this._sendRejectConnection(sender);
this._deletePeer(enc.pubkey, 'incorrect secret number');
return;
}
// if we locked allowed copayers, check if it belongs
if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) {
this._sendRejectConnection(sender);
this._deletePeer(sender);
return;
}
//ensure claimed public key is actually the public key of the peer
//e.g., their public key should hash to be their peerId
if (sender !== payload.copayerId) {
this._sendRejectConnection(sender);
this._deletePeer(enc.pubkey, 'incorrect pubkey for peerId');
return;
}
this._addConnectedCopayer(payload.copayerId);
break;
default:
this.emit('data', sender, payload, enc.ts);
}
};
Network.prototype._setupSocketHandlers = function(opts, cb) {
preconditions.checkState(this.socket);
log.debug('setting up connection', opts);
var self = this;
self.socket.on('connect_error', function(m) {
// If socket is not started, destroy it and emit and error
// If it is started, socket.io will try to reconnect.
if (!self.started) {
self.emit('connect_error');
self.cleanUp();
}
});
self.socket.on('subscribed', function(m) {
var fromTs = opts.syncedTimestamp || 0;
// We ask for this message, and then ignore it, only to see if the
// server has erased our old messages.
if (fromTs) {
self.ignoreMessageFromTs = fromTs;
}
log.info('Async: synchronizing from: ', fromTs);
self.socket.emit('sync', fromTs);
self.started = true;
});
self.socket.on('message', function(m) {
// delay execution, to improve error handling
setTimeout(function() {
self._onMessage(m);
}, 1);
});
self.socket.on('error', self._onError.bind(self));
self.socket.on('no_messages', self.emit.bind(self, 'no_messages'));
self.socket.on('no messages', self.emit.bind(self, 'no_messages'));
self.socket.on('connect', function() {
var pubkey = self.getKey().public.toString('hex');
log.debug('Async subscribing to pubkey:', pubkey);
self.socket.emit('subscribe', pubkey);
self.socket.on('disconnect', function() {
self.socket.emit('subscribe', pubkey);
});
if (typeof cb === 'function') cb();
});
};
Network.prototype._onError = function(err) {
log.debug('RECV ERROR: ', err);
log.debug(err.stack);
this.criticalError = err.message;
};
Network.prototype.greet = function(copayerId, secretNumber) {
this._sendHello(copayerId, secretNumber);
var peerId = this.peerFromCopayer(copayerId);
this._addCopayerMap(peerId, copayerId);
};
Network.prototype._addCopayerMap = function(peerId, copayerId) {
if (!this.copayerForPeer[peerId]) {
if (Object.keys(this.copayerForPeer).length < this.maxPeers) {
this.copayerForPeer[peerId] = copayerId;
}
}
};
Network.prototype._setInboundPeerAuth = function(peerId) {
this.isInboundPeerAuth[peerId] = true;
};
Network.prototype.setCopayerId = function(copayerId) {
preconditions.checkState(!this.started, 'network already started: can not change peerId');
this.copayerId = copayerId;
this.copayerIdBuf = new Buffer(copayerId, 'hex');
this.peerId = this.peerFromCopayer(this.copayerId);
this._addCopayerMap(this.peerId, copayerId);
};
// TODO cache this.
Network.prototype.peerFromCopayer = function(hex) {
var SIN = bitcore.SIN;
return new SIN(new Buffer(hex, 'hex')).toString();
};
Network.prototype.start = function(opts, openCallback) {
preconditions.checkArgument(opts);
preconditions.checkArgument(opts.privkey);
preconditions.checkArgument(opts.copayerId);
if (this.started) {
log.debug('Async: Networing already started for this wallet.')
return openCallback();
}
this.privkey = opts.privkey;
this.setCopayerId(opts.copayerId);
this.maxPeers = opts.maxPeers || this.maxPeers;
this.socket = this.createSocket();
this._setupSocketHandlers(opts, openCallback);
};
Network.prototype.createSocket = function() {
log.debug('Async: Connecting to socket:', this.url);
return io.connect(this.url, this.socketOptions);
};
Network.prototype.getOnlinePeerIDs = function() {
return this.connectedPeers;
};
Network.prototype.getCopayerIds = function() {
if (this.allowedCopayerIds) {
return Object.keys(this.allowedCopayerIds);
} else {
var copayerIds = [];
for (var peerId in this.copayerForPeer) {
copayerIds.push(this.copayerForPeer[peerId]);
}
return copayerIds;
}
};
Network.prototype.send = function(dest, payload, cb) {
preconditions.checkState(this.socket);
preconditions.checkArgument(payload);
var self = this;
if (!dest) {
dest = this.getCopayerIds();
payload.isBroadcast = 1;
}
if (typeof dest === 'string')
dest = [dest];
var l = dest.length;
var i = 0;
for (var ii in dest) {
var to = dest[ii];
if (to == this.copayerId)
continue;
var message = this.encode(to, payload);
this.socket.emit('message', message);
}
if (typeof cb === 'function') cb();
};
Network.prototype.encode = function(copayerId, payload, nonce) {
this.iterateNonce();
var opts = {
nonce: nonce || this.networkNonce
};
var copayerIdBuf = new Buffer(copayerId, 'hex');
var message = AuthMessage.encode(copayerIdBuf, this.getKey(), payload, opts);
return message;
};
Network.prototype.isOnline = function() {
return !!this.socket;
};
Network.prototype.lockIncommingConnections = function(allowedCopayerIdsArray) {
this.allowedCopayerIds = {};
for (var i in allowedCopayerIdsArray) {
this.allowedCopayerIds[allowedCopayerIdsArray[i]] = true;
}
};
Network.prototype.setCopayers = function(copayersIdsArray) {
for (var i in copayersIdsArray) {
this._addCopayer(copayersIdsArray[i]);
}
};
module.exports = Network;

View File

@ -1,256 +0,0 @@
'use strict';
var Identity = require('./Identity');
var Wallet = require('./Wallet');
var cryptoUtils = require('../util/crypto');
var CryptoJS = require('node-cryptojs-aes').CryptoJS;
var sjcl = require('../../lib/sjcl');
var log = require('../util/log');
var preconditions = require('preconditions').instance();
var _ = require('lodash');
var Compatibility = {};
Compatibility.iterations = 100;
Compatibility.salt = 'mjuBtGybi/4=';
/**
* Reads from localstorage wallets saved previously to 0.8
*/
Compatibility._getWalletIds = function(cb) {
preconditions.checkArgument(cb);
var walletIds = [];
var uniq = {};
var key;
for (key in localStorage) {
var split = key.split('::');
if (split.length == 2) {
var walletId = split[0];
if (!walletId || walletId === 'nameFor' || walletId === 'lock' || walletId === 'wallet') {
continue;
}
if (typeof uniq[walletId] === 'undefined') {
walletIds.push(walletId);
uniq[walletId] = 1;
}
}
}
return cb(walletIds);
};
/**
* @param {string} encryptedWallet - base64-encoded encrypted wallet
* @param {string} password
* @returns {Object}
*/
Compatibility.importLegacy = function(encryptedWallet, password) {
var passphrase = this.kdf(password);
var ret = Compatibility._decrypt(encryptedWallet, passphrase);
if (!ret) return null;
return ret;
};
/**
* Decrypts using the CryptoJS library (unknown encryption schema)
*
* Don't use CryptoJS to encrypt. This still exists for compatibility reasons only.
*/
Compatibility._decrypt = function(base64, passphrase) {
var decryptedStr = null;
try {
var decrypted = CryptoJS.AES.decrypt(base64, passphrase);
if (decrypted)
decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
} catch (e) {
// Error while decrypting
return null;
}
return decryptedStr;
};
/**
* Reads an item from localstorage, decrypts it with passphrase
*/
Compatibility._read = function(k, passphrase, cb) {
preconditions.checkArgument(cb);
var ret = localStorage.getItem(k);
if (!ret) return cb(null);
var ret = self._decrypt(ret, passphrase);
if (!ret) return cb(null);
ret = ret.toString(CryptoJS.enc.Utf8);
ret = JSON.parse(ret);
return ret;
};
Compatibility.getWallets_Old = function(cb) {
preconditions.checkArgument(cb);
var wallets = [];
var self = this;
this._getWalletIds(function(ids) {
if (!ids.length) {
return cb([]);
}
_.each(ids, function(id) {
var name = localStorage.getItem('nameFor::' + id);
if (name) {
wallets.push({
id: id,
name: name,
});
}
});
return cb(wallets);
});
};
Compatibility.getWallets2 = function(cb) {
var self = this;
var re = /wallet::([^_]+)(_?(.*))/;
var va = /^{+/;
var key;
var keys = [];
for (key in localStorage) {
keys.push(key);
}
var wallets = _.compact(_.map(keys, function(key) {
if (key.indexOf('wallet::') !== 0)
return null;
var match = key.match(re);
var matchValue = localStorage[key].match(va);
if (match.length != 4)
return null;
if (matchValue)
return null;
return {
id: match[1],
name: match[3] ? match[3] : undefined,
value: localStorage[key]
};
}));
return cb(wallets);
};
/**
* Lists all wallets in localstorage
*/
Compatibility.listWalletsPre8 = function(cb) {
var self = this;
self.getWallets2(function(wallets) {
self.getWallets_Old(function(wallets2) {
var ids = _.pluck(wallets, 'id');
_.each(wallets2, function(w) {
if (!_.contains(ids, w.id))
wallets.push(w);
});
return cb(wallets);
});
})
};
/**
* Retrieves a wallet that predates the 0.8 release
*/
Compatibility.readWalletPre8 = function(walletId, password, cb) {
var self = this;
var passphrase = cryptoUtils.kdf(password);
var obj = {};
var key;
for (key in localStorage) {
if (key.indexOf('wallet::' + walletId) !== -1) {
var ret = self._read(localStorage.getItem(key), passphrase);
if (err) return cb(err);
_.each(Wallet.PERSISTED_PROPERTIES, function(p) {
obj[p] = ret[p];
});
if (!_.any(_.values(obj)))
return cb(new Error('Wallet not found'));
var w, err;
obj.id = walletId;
try {
w = self.fromObj(obj);
} catch (e) {
if (e && e.message && e.message.indexOf('MISSOPTS')) {
err = new Error('Could not read: ' + walletId);
} else {
err = e;
}
w = null;
}
return cb(err, w);
}
}
};
Compatibility.importEncryptedWallet = function(identity, cypherText, password, opts, cb) {
var crypto = (opts && opts.cryptoUtil) || cryptoUtils;
var obj = crypto.decrypt(password, cypherText);
if (!obj) {
// 0.7.3 broken KDF
log.debug('Trying legacy encryption 0.7.2...');
var passphrase = crypto.kdf(password, 'mjuBtGybi/4=', 100);
obj = crypto.decrypt(passphrase, cypherText);
}
if (!obj) {
log.info("Could not decrypt, trying legacy..");
obj = Compatibility.importLegacy(cypherText, password);
};
if (!obj) {
return cb('Could not decrypt', null);
}
try {
obj = JSON.parse(obj);
} catch (e) {
return cb('Could not read encrypted wallet', null);
}
return identity.importWalletFromObj(obj, opts, cb);
};
/**
* @desc Generate a WordArray expanding a password
*
* @param {string} password - the password to expand
* @returns WordArray 512 bits with the expanded key generated from password
*/
Compatibility.kdf = function(password) {
var hash = sjcl.hash.sha256.hash(sjcl.hash.sha256.hash(password));
var salt = sjcl.codec.base64.toBits(this.salt);
var crypto2 = function(key, salt, iterations, length, alg) {
return sjcl.codec.hex.fromBits(sjcl.misc.pbkdf2(key, salt, iterations, length * 8,
alg == 'sha1' ? function(key) {
return new sjcl.misc.hmac(key, sjcl.hash.sha1)
} : null
))
};
var key512 = crypto2(hash, salt, this.iterations, 64, 'sha1');
var sbase64 = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(key512));
return sbase64;
};
Compatibility.deleteOldWallet = function(walletObj) {
console.log('[Compatibility.js:249]',walletObj); //TODO
localStorage.removeItem('wallet::' + walletObj.id + '_' + walletObj.name);
log.info('Old wallet ' + walletObj.name + ' deleted: ' + walletObj.id);
};
module.exports = Compatibility;

View File

@ -1,274 +0,0 @@
'use strict';
// 83.8% typed (by google's closure-compiler account)
var preconditions = require('preconditions').singleton();
var HDPath = require('./HDPath');
var _ = require('lodash');
/**
* @desc
* HDParams is a class that encapsulates information about the current indexes
* of a copayer
*
* When a copayer creates a new wallet, his receiveIndex gets updated, and an
* address is generated from everybody's public key, using this BIP32 path:
* <pre> m/copay'/{copayer}/0/{index} </pre>
*
* When a copayer generates a transaction proposal, his changeIndex gets
* updated, and all funds from that transaction proposal go to the multisig
* address generated from this BIP32 path for all the copayers:
* <pre> m/copay'/{copayer}/1/{changeIndex} </pre>
*
* There's a shared index, <tt>HDPath.SHARED_INDEX</tt>, that serves to
* generate addresses common to everybody.
*
* @TODO: Should opts.cosigner go?
*
* @constructor
*
* @param {Object} opts - options for the construction of this object
* @param {number=} opts.cosigner - backwards compatible index of a copayer
* @param {number} opts.copayerIndex - the copayer that generated this branch
* of addresses
* @param {number} opts.receiveIndex - the current index for a the last receive
* address generated for this copayer
* @param {number} opts.changeIndex - the current index for a the last change
* address generated for this copayer
*/
function HDParams(opts) {
opts = opts || {};
//opts.cosigner is for backwards compatibility only
/**
* @public
* @type number
*/
this.copayerIndex = _.isUndefined(opts.copayerIndex) ? opts.cosigner : opts.copayerIndex;
/**
* @public
* @type number
*/
this.changeIndex = opts.changeIndex || 0;
/**
* @public
* @type number
*/
this.receiveIndex = opts.receiveIndex || 0;
if (_.isUndefined(this.copayerIndex)) {
this.copayerIndex = HDPath.SHARED_INDEX;
}
}
/**
* @desc
* Creates a set of HDParams, with one HDParams structure for each copayer and
* a shared path.
*
* @static
* @param {number} totalCopayers - the number of copayers in a wallet
* @returns {HDParams[]} a list of HDParams generated for a new empty wallet
*/
HDParams.init = function(totalCopayers) {
preconditions.shouldBeNumber(totalCopayers);
var ret = [new HDParams({receiveIndex: 1})];
for (var i = 0 ; i < totalCopayers ; i++) {
ret.push(new HDParams({copayerIndex: i}));
}
return ret;
};
/**
* @desc
* Generates a set of HDParams from a list with a object-serialized version of
* HDParams.
*
* @static
* @param {Object[]} hdParams - a list with objects
* @returns {HDParams[]} builds a HDParams for each object literal found in the list
*/
HDParams.fromList = function(hdParams) {
return hdParams.map(function(i) { return HDParams.fromObj(i); });
};
/**
* @desc
* Generate a HDParams from an object.
*
* This essentialy only calls new HDParams(data), but it's the interface being
* used everywhere to encode/decode.
*
* @TODO: This should be clarified - Or abstracted away - as it's a pattern
* used in multiple places.
*
* @static
* @param {Object} data - a serialized version of HDParams
* @return {HDParams}
* @throws {BADDATA} - when the parameter <tt>data</tt> already is an instance of
* HDParams.
*/
HDParams.fromObj = function(data) {
if (data instanceof HDParams) {
throw new Error('BADDATA', 'bad data format: Did you use .toObj()?');
}
return new HDParams(data);
};
/**
* @desc
* Serializes a list of HDParams to a list of "plain" objects, according to each
* element's <tt>toObj()</tt> method.
*
* @TODO: There should be a list of Classes that share this behaviour.
*
* @static
* @param {HDParams[]} hdParams - a list of HDParams objects.
* @returns {Array} an array with the <tt>toObj()</tt> serialization of each
* element in hdParams
*/
HDParams.serialize = function(hdParams) {
return hdParams.map(function(i) { return i.toObj(); });
};
/**
* @desc
* Creates a new HDParams set with <tt>totalCopayers+1</tt> elements.
*
* Sets the first (corresponding to the parameters for the shared addresses)
* HDParams object to match <tt>shared</tt>'s values. Returns a serialized
* version of this set
*
* <pre>
* var updateResult = HDParams.update({changeIndex: 1, receiveIndex: 2}, 5);
* // All the following asserts succeed
* assert(_.isArray(updateResult));
* assert(_.all(updateResult, function (hd) { return !(hd instanceOf HDParams); }));
* assert(_.size(updateResult) === 6);
* assert(updateResult[0].changeIndex === 1);
* assert(updateResult[0].receiveIndex === 2);
* </pre>
*
* @TODO: This method is badly coded, it does something that is very specific
* and kind of strange. I couldn't figure out why would it be needed.
*
* @static
* @param {HDParams} shared - an instance of HDParams
* @param {number} totalCopayers
* @return {Object[]}
*/
HDParams.update = function(shared, totalCopayers) {
var hdParams = this.init(totalCopayers);
hdParams[0].changeIndex = shared.changeIndex;
hdParams[0].receiveIndex = shared.receiveIndex;
return this.serialize(hdParams);
};
/**
* @desc
* Serializes this object
*
* @TODO: I couldn't realize why would this be needed - calling, for example,
* JSON.stringify would have the same result on this object than on the
* original instance
*
* @returns {Object} a serialized version that should be equal (in a deep object
* comparison) to the <tt>this</tt> instance if passed to the
* <tt>HDParams()</tt> constructor.
*/
HDParams.prototype.toObj = function() {
return {
copayerIndex: this.copayerIndex,
changeIndex: this.changeIndex,
receiveIndex: this.receiveIndex
};
};
/**
* @desc
* Throws an error if a given index falls out of the range for known addresses.
*
* @TODO: This is not a good pattern, exceptions should be for exceptional things.
*
* @param {number} index the index to check for
* @param {boolean} isChange whether to check for the change index or the
* receive address index
*/
HDParams.prototype.checkRange = function(index, isChange) {
if ((isChange && index > this.changeIndex) ||
(!isChange && index > this.receiveIndex)) {
throw new Error('Out of bounds at index ' + index + ' isChange: ' + isChange);
}
};
/**
* @desc
* Return this instance's changeIndex value
*
* @TODO: Somebody did a lot of java. Not sure if we need to be so verbose. If
* anything, let's just declare changeIndex as a read only variable
* @returns {number} this HDParams current index to generate a change address
*/
HDParams.prototype.getChangeIndex = function() {
return this.changeIndex;
};
/**
* @desc
* Return this instance's receiveIndex value
*
* @TODO: Somebody did a lot of java. Not sure if we need to be so verbose. If
* anything, let's just declare changeIndex as a read only variable
* @returns {number} this HDParams current index to generate a receive address
*/
HDParams.prototype.getReceiveIndex = function() {
return this.receiveIndex;
};
/**
* @desc
* Increment this instance's changeIndex or receiveIndex value
*
* @TODO: Somebody did a lot of java. Not sure if we need to be so verbose.
*
* @param {boolean} isChange - if true, change <tt>changeIndex</tt>
*/
HDParams.prototype.increment = function(isChange) {
if (isChange) {
this.changeIndex++;
} else {
this.receiveIndex++;
}
};
/**
* @desc
* Merge this instance with another HDParams instance.
*
* @TODO: Device a general approach to merges.
*
* @param {Object} inHDParams - the object to merge to
* @param {number} inHDParams.copayerIndex - the object to merge to
* @returns {boolean} true if this object has changed
*/
HDParams.prototype.merge = function(inHDParams) {
preconditions.shouldBeObject(inHDParams);
preconditions.checkArgument(this.copayerIndex == inHDParams.copayerIndex);
var hasChanged = false;
if (inHDParams.changeIndex > this.changeIndex) {
this.changeIndex = inHDParams.changeIndex;
hasChanged = true;
}
if (inHDParams.receiveIndex > this.receiveIndex) {
this.receiveIndex = inHDParams.receiveIndex;
hasChanged = true;
}
return hasChanged;
};
module.exports = HDParams;

View File

@ -1,116 +0,0 @@
'use strict';
// 90.2% typed (by google's closure-compiler account)
var preconditions = require('preconditions').singleton();
var _ = require('lodash');
/**
* @namespace
* @desc
* HDPath contains helper functions to handle BIP32 branches as
* Copay uses them.
* Based on https://github.com/maraoz/bips/blob/master/bip-NNNN.mediawiki
* <pre>
* m / purpose' / copayerIndex / change:boolean / addressIndex
* </pre>
*/
var HDPath = {};
/**
* @desc Copay's BIP45 purpose code
* @const
* @type number
*/
HDPath.PURPOSE = 45;
/**
* @desc Maximum number for non-hardened values (BIP32)
* @const
* @type number
*/
HDPath.MAX_NON_HARDENED = 0x80000000 - 1;
/**
* @desc Shared Index: used for creating addresses for no particular purpose
* @const
* @type number
*/
HDPath.SHARED_INDEX = HDPath.MAX_NON_HARDENED - 0;
/**
* @desc ???
* @const
* @type number
*/
HDPath.ID_INDEX = HDPath.MAX_NON_HARDENED - 1;
/**
* @desc BIP45 prefix for COPAY
* @const
* @type string
*/
HDPath.BIP45_PUBLIC_PREFIX = 'm/' + HDPath.PURPOSE + '\'';
/**
* @desc Retrieve a string to be used with bitcore representing a Copay branch
* @param {number} addressIndex - the last value of the HD derivation
* @param {boolean} isChange - whether this is a change address or a receive
* @param {number} copayerIndex - the index of the copayer in the pubkeyring
* @return {string} - the path for the HD derivation
*/
HDPath.Branch = function(addressIndex, isChange, copayerIndex) {
preconditions.checkArgument(_.isNumber(addressIndex));
preconditions.checkArgument(_.isBoolean(isChange));
var ret = 'm/' +
(typeof copayerIndex !== 'undefined' ? copayerIndex : HDPath.SHARED_INDEX) + '/' +
(isChange ? 1 : 0) + '/' +
addressIndex;
return ret;
};
/**
* @desc ???
* @param {number} addressIndex - the last value of the HD derivation
* @param {boolean} isChange - whether this is a change address or a receive
* @param {number} copayerIndex - the index of the copayer in the pubkeyring
* @return {string} - the path for the HD derivation
*/
HDPath.FullBranch = function(addressIndex, isChange, copayerIndex) {
preconditions.checkArgument(_.isNumber(addressIndex));
preconditions.checkArgument(_.isBoolean(isChange));
var sub = HDPath.Branch(addressIndex, isChange, copayerIndex);
sub = sub.substring(2);
return HDPath.BIP45_PUBLIC_PREFIX + '/' + sub;
};
/**
* @desc
* Decompose a string and retrieve its arguments as if it where a Copay address.
* @param {string} path - the HD path
* @returns {Object} an object with three keys: addressIndex, isChange, and
* copayerIndex
*/
HDPath.indexesForPath = function(path) {
preconditions.checkArgument(_.isString(path));
var s = path.split('/');
return {
isChange: s[3] === '1',
addressIndex: parseInt(s[4], 10),
copayerIndex: parseInt(s[2], 10)
};
};
/**
* @desc The ID for a shared branch
*/
HDPath.IdFullBranch = HDPath.FullBranch(0, false, HDPath.ID_INDEX);
/**
* @desc Partial ID for a shared branch
*/
HDPath.IdBranch = HDPath.Branch(0, false, HDPath.ID_INDEX);
module.exports = HDPath;

View File

@ -1,905 +0,0 @@
'use strict';
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
var inherits = require('inherits');
var events = require('events');
var async = require('async');
var bitcore = require('bitcore');
var TxProposals = require('./TxProposals');
var PublicKeyRing = require('./PublicKeyRing');
var PrivateKey = require('./PrivateKey');
var Wallet = require('./Wallet');
var PluginManager = require('./PluginManager');
var Async = require('./Async');
var cryptoUtil = require('../util/crypto');
var log = require('../util/log');
var version = require('../../version').version;
/**
* @desc
* Identity - stores the state for a wallet in creation
*
* @param {Object} opts - configuration for this wallet
* @param {string} opts.fullName
* @param {string} opts.email
* @param {string} opts.password
* @param {string} opts.storage
* @param {string} opts.pluginManager
* @param {Object} opts.walletDefaults
* @param {string} opts.version
* @param {Object} opts.wallets
* @param {Object} opts.network
* @param {string} opts.network.testnet
* @param {string} opts.network.livenet
* @constructor
*/
function Identity(opts) {
preconditions.checkArgument(opts);
opts = _.extend({}, opts);
this.networkOpts = {
'livenet': opts.network.livenet,
'testnet': opts.network.testnet,
};
this.blockchainOpts = {
'livenet': opts.network.livenet,
'testnet': opts.network.testnet,
};
this.fullName = opts.fullName || opts.email;
this.email = opts.email;
this.password = opts.password;
this.storage = opts.storage || opts.pluginManager.get('DB');
this.storage.setCredentials(this.email, this.password, {});
this.walletDefaults = opts.walletDefaults || {};
this.version = opts.version || version;
this.walletIds = opts.walletIds || [];
this.wallets = opts.wallets || {};
this.focusedTimestamps = opts.focusedTimestamps || {};
this.backupNeeded = opts.backupNeeded || false;
};
inherits(Identity, events.EventEmitter);
Identity.getStoragePrefix = function() {
return 'profile::';
};
Identity.getKeyForEmail = function(email) {
return Identity.getStoragePrefix() + bitcore.util.sha256ripe160(email).toString('hex');
};
Identity.prototype.getChecksumForStorage = function() {
return JSON.stringify(_.sortBy(this.walletIds));
};
Identity.prototype.getId = function() {
return Identity.getKeyForEmail(this.email);
};
Identity.prototype.getName = function() {
return this.fullName || this.email;
};
/**
* Creates an Identity
*
* @param opts
* @param cb
* @return {undefined}
*/
Identity.create = function(opts, cb) {
opts = _.extend({
backupNeeded: true
}, opts);
var iden = new Identity(opts);
iden.store(_.extend(opts, {
failIfExists: true
}), function(err) {
if (err) return cb(err);
return cb(null, iden);
});
};
Identity.prototype.resendVerificationEmail = function(cb) {
var self = this;
preconditions.checkArgument(_.isFunction(cb));
preconditions.checkState(_.isFunction(self.storage.resendVerificationEmail));
self.storage.resendVerificationEmail(cb);
};
/**
* Open an Identity from the given storage.
*
* After opening a profile, and setting its wallet event handlers,
* the client must run .netStart on each
* (probably on iden's newWallet handler
*
* @param {Object} opts
* @param {Object} opts.storage
* @param {string} opts.email
* @param {string} opts.password
* @param {Function} cb
*/
Identity.open = function(opts, cb) {
preconditions.checkArgument(_.isObject(opts));
preconditions.checkArgument(_.isFunction(cb));
var storage = opts.storage || opts.pluginManager.get('DB');
storage.setCredentials(opts.email, opts.password, opts);
storage.getItem(Identity.getKeyForEmail(opts.email), function(err, data, headers) {
var exported;
if (err) {
return cb(err);
}
try {
exported = JSON.parse(data);
} catch (e) {
return cb(e);
}
return cb(null, new Identity(_.extend(opts, exported)), headers);
});
};
Identity.prototype.verifyChecksum = function(cb) {
var self = this;
self.storage.getItem(Identity.getKeyForEmail(self.email), function(err, data, headers) {
var iden;
if (err) return cb(err);
try {
iden = JSON.parse(data);
} catch (e) {
return cb(e);
}
return cb(null, self.getChecksumForStorage() == self.getChecksumForStorage.call(iden));
});
};
/**
* @param {string} walletId
* @returns {Wallet}
*/
Identity.prototype.getWalletById = function(walletId) {
return this.wallets[walletId];
};
/**
* @returns {Wallet[]}
*/
Identity.prototype.getWallets = function() {
return _.values(this.wallets);
};
/**
* addWallet
*
* @param w
*/
Identity.prototype.addWallet = function(w) {
this.wallets[w.getId()] = w;
this.walletIds = _.union(this.walletIds, [w.getId()]);
};
/**
* @desc Deletes a wallet. This involves removing it from the storage instance
*
* @param {string} walletId
* @callback cb
* @return {err}
*/
Identity.prototype.deleteWallet = function(walletId, cb) {
preconditions.checkArgument(_.isString(walletId));
var self = this;
self.verifyChecksum(function(err, match) {
if (err) return cb(err);
if (!match) return cb('The profile is out of sync. Please re-login to get the latest changes.');
var w = self.getWalletById(walletId);
w.close();
delete self.wallets[walletId];
delete self.focusedTimestamps[walletId];
self.walletIds = _.without(self.walletIds, walletId);
self.storage.removeItem(Wallet.getStorageKey(walletId), function(err) {
if (err) return cb(err);
self.emitAndKeepAlive('walletDeleted', walletId);
if (!self.walletIds.length) {
self.emitAndKeepAlive('noWallets')
}
self.store({
noWallets: true
}, cb);
});
});
};
/**
* readAndBindWallet
*
* @param {string} wid walletId to be readed
* @param {function} cb
*
*/
Identity.prototype.readAndBindWallet = function(walletId, cb) {
var self = this;
self.retrieveWalletFromStorage(walletId, {}, function(error, wallet) {
if (!error) {
self.addWallet(wallet);
self.bindWallet(wallet);
}
return cb(error);
});
};
Identity.prototype.emitAndKeepAlive = function(args) {
var args = Array.prototype.slice.call(arguments);
log.debug('Ident Emitting:', args);
//this.keepAlive(); // TODO
this.emit.apply(this, arguments);
};
/**
* @desc open profile's wallets. Call it AFTER setting
* the proper even listeners. no callback.
*
*/
Identity.prototype.openWallets = function() {
var self = this;
if (_.isEmpty(self.walletIds)) {
self.emitAndKeepAlive('noWallets')
return;
}
// First read the lastFocused wallet
self.walletIds.sort(function(a, b) {
var va = self.focusedTimestamps[a] || 0;
var vb = self.focusedTimestamps[b] || 0;
return va < vb ? 1 : (va === vb ? 0 : -1);
});
// opens the wallets, in the order they were last accessed. Emits open events (newWallet)
async.eachSeries(self.walletIds, function(walletId, a_cb) {
self.readAndBindWallet(walletId, a_cb);
});
};
/**
* @param {string} walletId
* @param {} opts
* opts.importWallet
* @param {Function} cb
*/
Identity.prototype.retrieveWalletFromStorage = function(walletId, opts, cb) {
var self = this;
var importFunction = opts.importWallet || Wallet.fromUntrustedObj;
this.storage.getItem(Wallet.getStorageKey(walletId), function(error, walletData) {
if (error) {
return cb(error);
}
try {
log.info('## OPENING Wallet:', walletId);
if (_.isString(walletData)) {
walletData = JSON.parse(walletData);
}
var readOpts = {
networkOpts: self.networkOpts,
blockchainOpts: self.blockchainOpts,
skipFields: []
};
} catch (e) {
log.debug("ERROR: ", e.message);
if (e && e.message && e.message.indexOf('MISSOPTS') !== -1) {
return cb(new Error('WERROR: Could not read: ' + walletId + ': ' + e.message));
} else {
return cb(e);
}
}
return cb(null, importFunction(walletData, readOpts));
});
};
/**
* @param {Wallet} wallet
* @param {Function} cb
*/
Identity.prototype.storeWallet = function(wallet, cb) {
var self = this;
preconditions.checkArgument(wallet && _.isObject(wallet));
wallet.setVersion(this.version);
var val = wallet.toObj();
var key = wallet.getStorageKey();
log.debug('Storing wallet:' + wallet.getName());
this.storage.setItem(key, val, function(err) {
if (err) {
log.error('Wallet:' + wallet.getName() + ' could not be stored:', err);
log.error('Wallet:' + wallet.getName() + ' Size:', JSON.stringify(wallet.sizes()));
if (err.match('OVERQUOTA')) {
self.emitAndKeepAlive('walletStorageError', wallet.getId(), 'Storage limits on remote server exceeded');
} else {
self.emitAndKeepAlive('walletStorageError', wallet.getId(), err);
}
}
if (cb)
return cb(err);
});
};
/**
* @param {Identity} identity
* @param {Wallet} wallet
* @param {Function} cb
*/
Identity.storeWalletDebounced = _.debounce(function(identity, wallet, cb) {
identity.storeWallet(wallet, cb);
}, 3000);
Identity.prototype.toObj = function() {
return _.pick(this, 'walletIds', 'version', 'fullName', 'password', 'email', 'backupNeeded', 'focusedTimestamps');
};
Identity.prototype.exportEncryptedWithWalletInfo = function(opts) {
var crypto = opts.cryptoUtil || cryptoUtil;
return crypto.encrypt(this.password, this.exportWithWalletInfo(opts));
};
Identity.prototype.setBackupNeeded = function(backupNeeded) {
var self = this;
self.backupNeeded = !!backupNeeded;
self.verifyChecksum(function(err, match) {
if (err) {
log.error(err);
return;
}
if (!match) {
log.error('The profile is out of sync. Please re-login to get the latest changes.');
return;
}
self.store({
noWallets: true
}, function() {});
});
}
Identity.prototype.exportWithWalletInfo = function(opts) {
return _.extend({
wallets: _.map(this.getWallets(), function(wallet) {
return wallet.toObj();
})
},
_.pick(this, 'version', 'fullName', 'password', 'email', 'backupNeeded')
);
};
/**
* @param {Object} opts
* @param {Function} cb
*/
Identity.prototype.store = function(opts, cb) {
var self = this;
opts = opts || {};
var storeFunction = opts.failIfExists ? self.storage.createItem : self.storage.setItem;
storeFunction.call(self.storage, this.getId(), this.toObj(), function(err) {
if (err) return cb(err);
if (opts.noWallets) return cb();
async.each(self.getWallets(), function(wallet, in_cb) {
self.storeWallet(wallet, in_cb);
}, cb);
});
};
/**
* @param {Object} opts
* @param {Function} cb
*/
Identity.prototype.remove = function(opts, cb) {
log.debug('Deleting profile');
var self = this;
opts = opts || {};
async.each(self.getWallets(), function(w, cb) {
w.close();
self.storage.removeItem(Wallet.getStorageKey(w.getId()), function(err) {
if (err) return cb(err);
cb();
});
}, function(err) {
if (err) return cb(err);
self.storage.removeItem(self.getId(), function(err) {
if (err) return cb(err);
self.storage.clear(function(err) {
if (err) return cb(err);
self.emitAndKeepAlive('closed');
return cb();
});
});
});
};
Identity.prototype._cleanUp = function() {
var self = this;
_.each(this.getWallets(), function(w) {
w.close();
delete self.wallets[w.getId()];
});
};
/**
* @desc Closes the wallet and disconnects all services
*/
Identity.prototype.close = function(cb) {
var self = this;
function doClose() {
self._cleanUp();
self.emitAndKeepAlive('closed');
if (cb) return cb();
};
self.verifyChecksum(function(err, match) {
if (!err && match) {
self.store({
noWallets: true,
}, function(err) {
return doClose();
});
} else {
return doClose();
}
});
};
Identity.prototype.importWalletFromObj = function(obj, opts, cb) {
var self = this;
preconditions.checkArgument(cb);
self.verifyChecksum(function(err, match) {
if (err) return cb(err);
if (!match) return cb('The profile is out of sync. Please re-login to get the latest changes.');
var importFunction = opts.importWallet || Wallet.fromUntrustedObj;
var readOpts = {
networkOpts: self.networkOpts,
blockchainOpts: self.blockchainOpts,
skipFields: opts.skipFields,
};
var w = importFunction(obj, readOpts);
if (!w) return cb(new Error('Could not decrypt'));
log.debug('Wallet decrypted:' + w.getName());
self._checkVersion(w.version);
log.debug('Updating Indexes for wallet:' + w.getName());
w.updateIndexes(function(err) {
log.debug('Adding wallet to profile:' + w.getName());
self.storeWallet(w, function(err) {
if (err) return cb(err);
self.addWallet(w);
self.updateFocusedTimestamp(w.getId());
self.bindWallet(w);
self.backupNeeded = true;
self.store({
noWallets: true,
}, function(err) {
return cb(err);
});
});
});
});
};
Identity.prototype.importMultipleWalletsFromObj = function(objs, opts) {
var self = this;
opts = opts || {};
async.eachSeries(objs, function(walletData, cb) {
if (!walletData)
return cb();
self.importWalletFromObj(walletData, opts, cb);
});
};
/**
* @param {Wallet} wallet
* @param {Function} cb
*/
Identity.prototype.closeWallet = function(wallet, cb) {
preconditions.checkState(wallet, 'Wallet not found');
var self = this;
wallet.close(function(err) {
return cb(err);
});
};
Identity.importFromEncryptedFullJson = function(ejson, password, opts, cb) {
var crypto = opts.cryptoUtil || cryptoUtil;
var str = crypto.decrypt(password, ejson);
if (!str) {
// 0.7.3 broken KDF
log.debug('Trying legacy encryption...');
var passphrase = crypto.kdf(password, 'mjuBtGybi/4=', 100);
str = crypto.decrypt(passphrase, ejson);
}
if (!str)
return cb('BADSTR');
return Identity.importFromFullJson(str, password, opts, cb);
};
Identity.importFromFullJson = function(str, password, opts, cb) {
preconditions.checkArgument(str);
var json;
try {
json = JSON.parse(str);
} catch (e) {
return cb('BADSTR: Unable to retrieve json from string', str);
}
var email = json.email;
opts.email = email;
opts.password = password;
if (!email)
return cb('BADSTR');
var iden = new Identity(opts);
opts.failIfExists = true;
json.wallets = json.wallets || {};
iden.store(opts, function(err) {
if (err) return cb(err); //profile already exists
return cb(null, iden, json.wallets);
});
};
/**
* @desc binds a wallet's events and emits 'newWallet'
* @param {string} walletId Wallet id to be binded
* @emits newWallet (walletId)
*/
Identity.prototype.bindWallet = function(w) {
preconditions.checkArgument(w && this.getWalletById(w.getId()));
var self = this;
log.debug('Binding wallet:' + w.getName());
w.on('txProposalsUpdated', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('paymentAck', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('newAddresses', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('settingsUpdated', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('txProposalEvent', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('addressBookUpdated', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('publicKeyRingUpdated', function() {
Identity.storeWalletDebounced(self, w);
});
w.on('ready', function() {
Identity.storeWalletDebounced(self, w);
});
this.emitAndKeepAlive('newWallet', w.getId());
};
/**
* @desc This method prepares options for a new Wallet
*
* @param {Object} opts
* @param {string} opts.id
* @param {PrivateKey=} opts.privateKey
* @param {string=} opts.privateKeyHex
* @param {number} opts.requiredCopayers
* @param {number} opts.totalCopayers
* @param {PublicKeyRing=} opts.publicKeyRing
* @param {string} opts.nickname
* @param {string} opts.password
* @param {boolean} opts.spendUnconfirmed this.walletDefaults.spendUnconfirmed
* @param {number} opts.reconnectDelay time in milliseconds
* @param {number=} opts.version
* @param {callback} opts.version
* @return {Wallet}
*/
Identity.prototype.createWallet = function(opts, cb) {
preconditions.checkArgument(cb);
var self = this;
self.verifyChecksum(function(err, match) {
if (err) return cb(err);
if (!match) return cb('The profile is out of sync. Please re-login to get the latest changes.');
opts = opts || {};
opts.networkName = opts.networkName || 'testnet';
log.debug('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID') + (opts.privateKey ? ' USING PrivateKey: ' + opts.privateKey.getId() : ' NEW PrivateKey'));
var privOpts = {
networkName: opts.networkName,
};
if (opts.privateKeyHex && opts.privateKeyHex.length > 1) {
privOpts.extendedPrivateKeyString = opts.privateKeyHex;
}
opts.privateKey = opts.privateKey || new PrivateKey(privOpts);
var requiredCopayers = opts.requiredCopayers || self.walletDefaults.requiredCopayers;
var totalCopayers = opts.totalCopayers || self.walletDefaults.totalCopayers;
opts.lockTimeoutMin = self.walletDefaults.idleDurationMin;
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
networkName: opts.networkName,
requiredCopayers: requiredCopayers,
totalCopayers: totalCopayers,
});
opts.publicKeyRing.addCopayer(
opts.privateKey.deriveBIP45Branch().extendedPublicKeyString(),
opts.nickname || self.getName()
);
log.debug('\t### PublicKeyRing Initialized');
opts.txProposals = opts.txProposals || new TxProposals({
networkName: opts.networkName,
});
var walletClass = opts.walletClass || Wallet;
log.debug('\t### TxProposals Initialized');
opts.networkOpts = self.networkOpts;
opts.blockchainOpts = self.blockchainOpts;
opts.spendUnconfirmed = opts.spendUnconfirmed || self.walletDefaults.spendUnconfirmed;
opts.reconnectDelay = opts.reconnectDelay || self.walletDefaults.reconnectDelay;
opts.requiredCopayers = requiredCopayers;
opts.totalCopayers = totalCopayers;
opts.version = opts.version || self.version;
var w = new walletClass(opts);
if (self.getWalletById(w.getId())) {
return cb('walletAlreadyExists');
}
self.storeWallet(w, function(err) {
if (err) return cb(err);
self.addWallet(w);
self.updateFocusedTimestamp(w.getId());
self.bindWallet(w);
self.backupNeeded = true;
self.store({
noWallets: true,
}, function(err) {
return cb(err, w);
});
});
});
};
/**
* @desc Checks if a version is compatible with the current version
* @param {string} inVersion - a version, with major, minor, and revision, period-separated (x.y.z)
* @throws {Error} if there's a major version difference
*/
Identity.prototype._checkVersion = function(inVersion) {
if (inVersion) {
var thisV = this.version.split('.');
var thisV0 = parseInt(thisV[0]);
var inV = inVersion.split('.');
var inV0 = parseInt(inV[0]);
}
//We only check for major version differences
if (thisV0 < inV0) {
throw new Error('Major difference in software versions' +
'. Received:' + inVersion +
'. Current version:' + this.version +
'. Aborting.');
}
};
/**
* @desc Pass through to {@link Wallet#secret}
*/
Identity.prototype.decodeSecret = function(secret) {
try {
return Wallet.decodeSecret(secret);
} catch (e) {
return false;
}
};
/**
* getLastFocusedWalletId
*
* @return {string} walletId
*/
Identity.prototype.getLastFocusedWalletId = function() {
if (this.walletIds.length == 0) return undefined;
var max = _.max(this.focusedTimestamps);
if (!max)
return this.walletIds[0];
return _.findKey(this.focusedTimestamps, function(ts) {
return ts == max;
}) || this.walletIds[0];
};
Identity.prototype.updateFocusedTimestamp = function(wid) {
preconditions.checkArgument(wid && this.getWalletById(wid));
this.focusedTimestamps[wid] = Date.now();
};
/**
* @callback walletCreationCallback
* @param {?} err - an error, if any, that happened during the wallet creation
* @param {Wallet=} wallet - the wallet created
*/
/**
* @desc Start the network functionality.
*
* Start up the Network instance and try to join a wallet defined by the
* parameter <tt>secret</tt> using the parameter <tt>nickname</tt>. Encode
* information locally using <tt>passphrase</tt>. <tt>privateHex</tt> is the
* private extended master key. <tt>cb</tt> has two params: error and wallet.
*
* @param {object} opts
* @param {string} opts.secret - the wallet secret
* @param {string} opts.nickname - a nickname for the current user
* @param {string} opts.privateHex - the private extended master key
* @param {walletCreationCallback} cb - a callback
*/
Identity.prototype.joinWallet = function(opts, cb) {
preconditions.checkArgument(opts);
preconditions.checkArgument(opts.secret);
preconditions.checkArgument(cb);
var self = this;
var decodedSecret = this.decodeSecret(opts.secret);
if (!decodedSecret || !decodedSecret.networkName || !decodedSecret.pubKey) {
return cb('badSecret');
}
var privOpts = {
networkName: decodedSecret.networkName,
};
if (opts.privateHex && opts.privateHex.length > 1) {
privOpts.extendedPrivateKeyString = opts.privateHex;
}
//Create our PrivateK
var privateKey = new PrivateKey(privOpts);
log.debug('\t### PrivateKey Initialized');
var joinOpts = {
copayerId: privateKey.getId(),
privkey: privateKey.getIdPriv(),
key: privateKey.getIdKey(),
secretNumber: decodedSecret.secretNumber,
};
var joinNetwork = opts.Async || new Async(this.networkOpts[decodedSecret.networkName]);
// This is a hack to reconize if the connection was rejected or the peer wasn't there.
var connectedOnce = false;
joinNetwork.on('connected', function(sender, data) {
connectedOnce = true;
});
joinNetwork.on('connect_error', function() {
return cb('connectionError');
});
joinNetwork.on('serverError', function() {
return cb('joinError');
});
joinNetwork.start(joinOpts, function() {
joinNetwork.greet(decodedSecret.pubKey, joinOpts.secretNumber);
joinNetwork.on('data', function(sender, data) {
if (data.type === 'walletId' && data.opts) {
if (!data.networkName || data.networkName !== decodedSecret.networkName) {
return cb('badNetwork');
}
data.opts.networkName = data.networkName;
var walletOpts = _.clone(data.opts);
walletOpts.id = data.walletId;
walletOpts.network = joinNetwork;
walletOpts.privateKey = privateKey;
walletOpts.nickname = opts.nickname || self.getName();
if (opts.password)
walletOpts.password = opts.password;
self.createWallet(walletOpts, function(err, w) {
if (w) {
w.sendWalletReady(decodedSecret.pubKey);
} else {
if (!err) {
err = 'walletFull';
}
}
return cb(err, w);
});
}
});
});
};
module.exports = Identity;

View File

@ -1,346 +0,0 @@
'use strict';
var util = require('util');
var async = require('async');
var request = require('request');
var io = require('socket.io-client');
var _ = require('lodash');
var EventEmitter = require('events').EventEmitter;
var preconditions = require('preconditions').singleton();
var bitcore = require('bitcore');
var log = require('../util/log.js');
/*
This class lets interface with the blockchain, making general queries and
subscribing to transactions on addresses and blocks.
Opts:
- url
- reconnection (optional)
- reconnectionDelay (optional)
Events:
- tx: activity on subscribed address.
- block: a new block that includes a subscribed address.
- connect: the connection with the blockchain is ready.
- disconnect: the connection with the blochckain is unavailable.
*/
var Insight = function(opts) {
preconditions.checkArgument(opts)
.shouldBeObject(opts)
.checkArgument(opts.url)
this.status = this.STATUS.DISCONNECTED;
this.subscribed = {};
this.listeningBlocks = false;
this.url = opts.url;
this.opts = {
'reconnection': opts.reconnection || true,
'reconnectionDelay': opts.reconnectionDelay || 1000,
'secure': opts.url.indexOf('https') === 0
};
if (opts.transports) {
this.opts['transports'] = opts.transports;
}
this.socket = this.getSocket();
}
Insight.setCompleteUrl = function(uri) {
if (!uri) return uri;
var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
var parts = [
'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];
function parseuri(str) {
var m = re.exec(str || ''),
uri = {},
i = 14;
while (i--) {
uri[parts[i]] = m[i] || '';
}
return uri;
};
var opts_host;
var opts_secure;
var opts_port;
var opts_protocol;
if (uri) {
uri = parseuri(uri);
opts_host = uri.host;
opts_protocol = uri.protocol;
opts_secure = uri.protocol == 'https' || uri.protocol == 'wss';
opts_port = uri.port;
}
var this_secure = null != opts_secure ? opts_secure :
('https:' == location.protocol);
var opts_hostname;
if (opts_host) {
var pieces = opts_host.split(':');
opts_hostname = pieces.shift();
if (pieces.length) opts_port = pieces.pop();
}
var this_port = opts_port ||
(this_secure ? 443 : 80);
var newUri = opts_protocol + '://' + opts_host + ':' + this_port;
return newUri;
}
util.inherits(Insight, EventEmitter);
Insight.prototype.STATUS = {
CONNECTED: 'connected',
DISCONNECTED: 'disconnected',
DESTROYED: 'destroyed'
}
/** @private */
Insight.prototype.subscribeToBlocks = function() {
var socket = this.getSocket();
if (this.listeningBlocks || !socket.connected) return;
var self = this;
socket.on('block', function(blockHash) {
self.emit('block', blockHash);
});
this.listeningBlocks = true;
}
/** @private */
Insight.prototype._getSocketIO = function(url, opts) {
log.debug('Insight: Connecting to socket:', this.url);
return io(this.url, this.opts);
};
Insight.prototype._setMainHandlers = function(url, opts) {
// Emmit connection events
var self = this;
this.socket.on('connect', function() {
self.status = self.STATUS.CONNECTED;
self.subscribeToBlocks();
self.emit('connect', 0);
});
this.socket.on('connect_error', function() {
if (self.status != self.STATUS.CONNECTED) return;
self.status = self.STATUS.DISCONNECTED;
self.emit('disconnect');
});
this.socket.on('connect_timeout', function() {
if (self.status != self.STATUS.CONNECTED) return;
self.status = self.STATUS.DISCONNECTED;
self.emit('disconnect');
});
this.socket.on('reconnect', function(attempt) {
if (self.status != self.STATUS.DISCONNECTED) return;
self.emit('reconnect', attempt);
self.reSubscribe();
self.status = self.STATUS.CONNECTED;
});
};
/** @private */
Insight.prototype.getSocket = function() {
if (!this.socket) {
this.socket = this._getSocketIO(this.url, this.opts);
this._setMainHandlers();
}
return this.socket;
}
/** @private */
Insight.prototype.request = function(path, cb) {
preconditions.checkArgument(path).shouldBeFunction(cb);
request(this.url + path, cb);
}
/** @private */
Insight.prototype.requestPost = function(path, data, cb) {
preconditions.checkArgument(path).checkArgument(data).shouldBeFunction(cb);
request({
method: "POST",
url: this.url + path,
json: data
}, cb);
}
Insight.prototype.destroy = function() {
var socket = this.getSocket();
this.socket.disconnect();
this.socket.removeAllListeners();
this.socket = null;
this.subscribed = {};
this.status = this.STATUS.DESTROYED;
this.removeAllListeners();
};
Insight.prototype.subscribe = function(addresses) {
addresses = Array.isArray(addresses) ? addresses : [addresses];
var self = this;
function handlerFor(self, address) {
return function(txid) {
// verify the address is still subscribed
if (!self.subscribed[address]) return;
self.emit('tx', {
address: address,
txid: txid
});
}
}
var s = self.getSocket();
addresses.forEach(function(address) {
preconditions.checkArgument(new bitcore.Address(address).isValid());
// skip already subscibed
if (!self.subscribed[address]) {
var handler = handlerFor(self, address);
self.subscribed[address] = handler;
// log.debug('Subscribe to: ', address);
s.emit('subscribe', address);
s.on(address, handler);
}
});
};
Insight.prototype.getSubscriptions = function(addresses) {
return this.subscribed;
}
Insight.prototype.reSubscribe = function() {
log.debug('insight reSubscribe');
var allAddresses = Object.keys(this.subscribed);
this.subscribed = {};
var s = this.socket;
if (s) {
s.removeAllListeners();
this._setMainHandlers();
this.subscribe(allAddresses);
this.subscribeToBlocks();
}
};
Insight.prototype.broadcast = function(rawtx, cb) {
preconditions.checkArgument(rawtx);
preconditions.shouldBeFunction(cb);
this.requestPost('/api/tx/send', {
rawtx: rawtx
}, function(err, res, body) {
if (err || res.statusCode != 200) return cb(err || body);
return cb(null, body ? body.txid : null);
});
};
Insight.prototype.getTransaction = function(txid, cb) {
preconditions.shouldBeFunction(cb);
this.request('/api/tx/' + txid, function(err, res, body) {
if (err || res.statusCode != 200 || !body) return cb(err || res);
cb(null, JSON.parse(body));
});
};
Insight.prototype.getTransactions = function(addresses, from, to, cb) {
preconditions.shouldBeArray(addresses);
preconditions.shouldBeFunction(cb);
var qs = '';
if (_.isNumber(from)) {
qs += '?from=' + from;
if (_.isNumber(to)) {
qs += '&to=' + to;
}
}
this.requestPost('/api/addrs/txs' + qs, {
addrs: addresses.join(',')
}, function(err, res, txs) {
if (err || res.statusCode != 200) return cb(err || res);
cb(null, txs);
});
};
Insight.prototype.getUnspent = function(addresses, cb) {
preconditions.shouldBeArray(addresses);
preconditions.shouldBeFunction(cb);
this.requestPost('/api/addrs/utxo', {
addrs: addresses.join(',')
}, function(err, res, unspentRaw) {
if (err || res.statusCode != 200) return cb(err || res);
// This filter out possible broken unspent, as reported on
// https://github.com/bitpay/copay/issues/1585
// and later gitter conversation.
var unspent = _.filter(unspentRaw, 'scriptPubKey');
cb(null, unspent);
});
};
Insight.prototype.getActivity = function(addresses, cb) {
preconditions.shouldBeArray(addresses);
this.getTransactions(addresses, null, null, function then(err, txs) {
if (err) return cb(err);
var flatArray = function(xss) {
return xss.reduce(function(r, xs) {
return r.concat(xs);
}, []);
};
var getInputs = function(t) {
return t.vin.map(function(vin) {
return vin.addr
});
};
var getOutputs = function(t) {
return flatArray(
t.vout.map(function(vout) {
return vout.scriptPubKey.addresses;
})
);
};
var activityMap = new Array(addresses.length);
var activeAddress = flatArray(txs.map(function(t) {
return getInputs(t).concat(getOutputs(t));
}));
activeAddress.forEach(function(addr) {
var index = addresses.indexOf(addr);
if (index != -1) activityMap[index] = true;
});
cb(null, activityMap);
});
};
module.exports = Insight;

View File

@ -1,57 +0,0 @@
'use strict';
var preconditions = require('preconditions').singleton();
var log = require('../util/log');
function PluginManager(config) {
this.registered = {};
this.scripts = [];
for (var ii in config.plugins) {
var pluginName = ii;
if (!config.plugins[pluginName])
continue;
log.info('Loading plugin: ' + pluginName);
var pluginClass;
if(config.pluginsPath){
pluginClass = require(config.pluginsPath + pluginName);
} else {
pluginClass = require('../js/plugins/' + pluginName);
}
var pluginObj = new pluginClass(config[pluginName]);
pluginObj.init();
this._register(pluginObj, pluginName);
}
};
var KIND_UNIQUE = PluginManager.KIND_UNIQUE = 1;
var KIND_MULTIPLE = PluginManager.KIND_MULTIPLE = 2;
PluginManager.TYPE = {};
PluginManager.TYPE['DB'] = KIND_UNIQUE;
PluginManager.prototype._register = function(obj, name) {
preconditions.checkArgument(obj.type, 'Plugin has not type:' + name);
var type = obj.type;
var kind = PluginManager.TYPE[type];
preconditions.checkArgument(kind, 'Unknown plugin type:' + name);
preconditions.checkState(kind !== PluginManager.KIND_UNIQUE || !this.registered[type], 'Plugin kind already registered:' + name);
if (kind === PluginManager.KIND_UNIQUE) {
this.registered[type] = obj;
} else {
this.registered[type] = this.registered[type] || [];
this.registered[type].push(obj);
}
this.scripts = this.scripts.concat(obj.scripts || []);
};
PluginManager.prototype.get = function(type) {
return this.registered[type];
};
module.exports = PluginManager;

View File

@ -1,264 +0,0 @@
'use strict';
// 62.9% typed (by google's closure-compiler account)
var bitcore = require('bitcore');
var HK = bitcore.HierarchicalKey;
var WalletKey = bitcore.WalletKey;
var networks = bitcore.networks;
var util = bitcore.util;
var _ = require('lodash');
var preconditions = require('preconditions').instance();
var HDPath = require('./HDPath');
/**
* @desc
* Wrapper for bitcore.HierarchicalKey to be used inside of Copay.
*
* @param {Object} opts
* @param {string} opts.networkName if set to 'testnet', use the test3 bitcoin
* network constants (livenet otherwise)
* @param {string} opts.extendedPrivateKeyString if set, use this private key
* string, othewise create a new
* private key
* @constructor
*/
function PrivateKey(opts) {
opts = opts || {};
this.network = opts.networkName === 'testnet' ? networks.testnet : networks.livenet;
var init = opts.extendedPrivateKeyString || this.network.name;
this.bip = new HK(init);
this.privateKeyCache = {};
this.publicHex = this.deriveBIP45Branch().eckey.public.toString('hex');
};
/**
* @desc Retrieve this derivated private key's public key in hexa format
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {string} the public key in a hexadecimal string
*/
PrivateKey.prototype.getId = function() {
if (!this.id) {
this.cacheId();
}
return this.id;
};
/**
* @desc Retrieve this private key's private key in hex format
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {string} the private key in a hexadecimal string
*/
PrivateKey.prototype.getIdPriv = function() {
if (!this.idpriv) {
this.cacheId();
}
return this.idpriv;
};
/**
* @desc Retrieve this private key's private key
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {bitcore.PrivateKey} the private key
*/
PrivateKey.prototype.getIdKey = function() {
if (!this.idkey) {
this.cacheId();
}
return this.idkey;
};
/**
* @desc Caches the result of deriving IdFullBranch
*
* @private
*/
PrivateKey.prototype.cacheId = function() {
var path = HDPath.IdFullBranch;
var idhk = this.bip.derive(path);
this.idkey = idhk.eckey;
this.id = idhk.eckey.public.toString('hex');
this.idpriv = idhk.eckey.private.toString('hex');
};
/**
* @desc Derive the master branch for Copay.
*/
PrivateKey.prototype.deriveBIP45Branch = function() {
if (!this.bip45Branch) {
this.bip45Branch = this.bip.derive(HDPath.BIP45_PUBLIC_PREFIX);
}
return this.bip45Branch;
};
/**
* @desc Returns an object with information needed to rebuild a PrivateKey
* (as most of its properties are derived from the extended private key).
*
* @TODO: Figure out if this is the correct pattern
* This is a static method and is probably used for serialization.
*
* @static
* @param {Object} data
* @param {*} data.networkName - a name for a bitcoin network
* @param {*} data.extendedPrivateKeyString - a bip32 extended private key
* @returns {Object} an object with two properties: networkName and
* extendedPrivateKeyString, taken from the <tt>data</tt>
* parameter.
*/
PrivateKey.trim = function(data) {
var opts = {};
['networkName', 'extendedPrivateKeyString'].forEach(function(k){
opts[k] = data[k];
});
return opts
};
/**
* @desc Generate a private Key from a serialized object
*
* @TODO: This method uses PrivateKey.trim but it's actually not needed...
*
* @param {Object} data
* @param {*} data.networkName - a name for a bitcoin network
* @param {*} data.extendedPrivateKeyString - a bip32 extended private key
* @returns {PrivateKey}
*/
PrivateKey.fromObj = function(obj) {
return new PrivateKey(PrivateKey.trim(obj));
};
/**
* @desc Serialize a private key, keeping only the data necessary to rebuild it
*
* @returns {Object}
*/
PrivateKey.prototype.toObj = function() {
return {
extendedPrivateKeyString: this.getExtendedPrivateKeyString(),
networkName: this.network.name
};
};
/**
* @desc Retrieve a BIP32 extended public key as generated by bitcore
*
* @returns {string}
*/
PrivateKey.prototype.getExtendedPublicKeyString = function() {
return this.bip.extendedPublicKeyString();
};
/**
* @desc Retrieve a BIP32 extended private key as generated by bitcore
*
* @returns {string}
*/
PrivateKey.prototype.getExtendedPrivateKeyString = function() {
return this.bip.extendedPrivateKeyString();
};
/**
* @desc
* Retrieve a HierarchicalKey derived from the given path as generated by
* bitcore
* @param {string} path - a string for derivation (something like "m/234'/1/2")
* @returns {bitcore.HierarchicalKey}
*/
PrivateKey.prototype._getHK = function(path) {
if (_.isUndefined(path)) {
return this.bip;
}
var ret = this.bip.derive(path);
return ret;
};
/**
* @desc
* Retrieve an array of WalletKey derived from given paths. {@see PrivateKey#getForPath}
*
* @param {string[]} paths - the paths to derive
* @returns {bitcore.WalletKey[]} - the derived keys
*/
PrivateKey.prototype.getForPaths = function(paths) {
return paths.map(this.getForPath.bind(this));
};
/**
* @desc
* Retrieve a WalletKey derived from a path.
*
* @param {string} paths - the path to derive
* @returns {bitcore.WalletKey} - the derived key
*/
PrivateKey.prototype.getForPath = function(path) {
var pk = this.privateKeyCache[path];
if (!pk) {
var derivedHK = this._getHK(path);
pk = this.privateKeyCache[path] = derivedHK.eckey.private.toString('hex');
}
var wk = new WalletKey({
network: this.network
});
wk.fromObj({
priv: pk
});
return wk;
};
/**
* @desc
* Retrieve a Branch for Copay using the given path
*
* @TODO: Investigate when is this called and if this is really needed
*
* @param {number} index - the index of the key to generate
* @param {boolean} isChange - whether this is a change adderess or a receive
* @param {number} cosigner - the cosigner index
* @return {bitcore.HierarchicalKey}
*/
PrivateKey.prototype.get = function(index, isChange, cosigner) {
// TODO: Add parameter validation?
var path = HDPath.FullBranch(index, isChange, cosigner);
return this.getForPath(path);
};
/**
* @desc
* Retrieve multiple branches for Copay up to the received indexes
*
* @TODO: Investigate when is this called and if this is really needed
*
* @param {number} receiveIndex - the number of receive addresses to generate
* @param {number} changeIndex - the number of change addresses to generate
* @param {number} cosigner - the cosigner index
* @return {bitcore.HierarchicalKey}
*/
PrivateKey.prototype.getAll = function(receiveIndex, changeIndex, cosigner) {
preconditions.checkArgument(!_.isUndefined(receiveIndex) && !_.isUndefined(changeIndex));
var ret = [];
for (var i = 0; i < receiveIndex; i++) {
ret.push(this.get(i, false, cosigner));
}
for (var i = 0; i < changeIndex; i++) {
ret.push(this.get(i, true, cosigner));
}
return ret;
};
module.exports = PrivateKey;

View File

@ -1,803 +0,0 @@
'use strict';
var preconditions = require('preconditions').instance();
var _ = require('lodash');
var log = require('../util/log');
var bitcore = require('bitcore');
var HK = bitcore.HierarchicalKey;
var Address = bitcore.Address;
var Script = bitcore.Script;
var PrivateKey = require('./PrivateKey');
var HDPath = require('./HDPath');
var HDParams = require('./HDParams');
/**
* @desc Represents a public key ring, the set of all public keys and the used indexes
*
* @constructor
* @param {Object} opts
* @param {string} opts.walletId
* @param {string} opts.network 'livenet' to signal the bitcoin main network, all others are testnet
* @param {number=} opts.requiredCopayers - defaults to 3
* @param {number=} opts.totalCopayers - defaults to 5
* @param {Object[]} [opts.indexes] - an array to be deserialized using {@link HDParams#fromList}
* (defaults to all indexes in zero)
* @param {Object=} opts.nicknameFor - nicknames for other copayers
*/
function PublicKeyRing(opts) {
opts = opts || {};
this.walletId = opts.walletId;
this.network = opts.networkName === 'livenet' ?
bitcore.networks.livenet : bitcore.networks.testnet;
this.requiredCopayers = opts.requiredCopayers || 3;
this.totalCopayers = opts.totalCopayers || 5;
this.copayersHK = [];
this.indexes = opts.indexes ? HDParams.fromList(opts.indexes) : HDParams.init(this.totalCopayers);
this.publicKeysCache = {};
this.nicknameFor = opts.nicknameFor || {};
this.copayerIds = [];
this.resetCache();
};
PublicKeyRing.prototype.resetCache = function() {
this.cache = {};
this.cache.addressToPath = {};
this.cache.pathToAddress = {};
// Non persistent cache
this._isChange = {};
};
/**
* @desc Returns an object with only the keys needed to rebuild a PublicKeyRing
*
* @TODO: Figure out if this is the correct pattern
* This is a static method and is probably used for serialization.
*
* @static
* @param {Object} data
* @param {string} data.walletId - a string to identify a wallet
* @param {string} data.networkName - the name of the bitcoin network
* @param {number} data.requiredCopayers - the number of required copayers
* @param {number} data.totalCopayers - the number of copayers in the ring
* @param {Object[]} data.indexes - an array of objects that can be turned into
* an array of HDParams
* @param {Object} data.nicknameFor - a registry of nicknames for other copayers
* @param {string[]} data.copayersExtPubKeys - the extended public keys of copayers
* @returns {Object} a trimmed down version of PublicKeyRing that can be used
* as a parameter
*/
PublicKeyRing.trim = function(data) {
preconditions.checkArgument(data);
var opts = {};
['walletId', 'networkName', 'requiredCopayers', 'totalCopayers',
'indexes', 'nicknameFor', 'copayersExtPubKeys'
].forEach(function(k) {
opts[k] = data[k];
});
return opts;
};
/**
* @desc Deserializes a PublicKeyRing from a plain object
*
* If the <tt>data</tt> parameter is an instance of PublicKeyRing already,
* it will fail, throwing an assertion error.
*
* @static
* @param {object} data - a serialized version of PublicKeyRing {@see PublicKeyRing#trim}
* @return {PublicKeyRing} - the deserialized object
*/
PublicKeyRing.fromObj = function(opts) {
preconditions.checkArgument(!(opts instanceof PublicKeyRing), 'bad opts format: Did you use .toObj()?');
// Support old indexes schema
if (!Array.isArray(opts.indexes)) {
opts.indexes = HDParams.update(opts.indexes, opts.totalCopayers);
}
var pkr = new PublicKeyRing(opts);
for (var k in opts.copayersExtPubKeys) {
pkr.addCopayer(opts.copayersExtPubKeys[k]);
}
if (opts.cache && opts.cache.addressToPath) {
log.debug('PublicKeyRing: Using address cache');
pkr.cache.addressToPath = opts.cache.addressToPath;
pkr.rebuildCache();
}
return pkr;
};
PublicKeyRing.prototype.rebuildCache = function() {
if (!this.cache.addressToPath)
return;
var self = this;
_.each(this.cache.addressToPath, function(path, address) {
self.cache.pathToAddress[path] = address;
});
};
PublicKeyRing.fromUntrustedObj = function(opts) {
return PublicKeyRing.fromObj(PublicKeyRing.trim(opts));
};
/**
* @desc Serialize this object to a plain object with all the data needed to
* rebuild it
*
* @return {Object} a serialized version of a PublicKeyRing
*/
PublicKeyRing.prototype.toObj = function() {
return {
walletId: this.walletId,
networkName: this.network.name,
requiredCopayers: this.requiredCopayers,
totalCopayers: this.totalCopayers,
indexes: HDParams.serialize(this.indexes),
copayersExtPubKeys: this.copayersHK.map(function(b) {
return b.extendedPublicKeyString();
}),
nicknameFor: this.nicknameFor,
// We only store addressToPath and derive the reset from it
cache: {
addressToPath: this.cache.addressToPath
},
};
};
PublicKeyRing.prototype.toTrimmedObj = function() {
return PublicKeyRing.trim(this.toObj());
}
/**
* @desc
* Retrieve a copayer's public key as a hexadecimal encoded string
*
* @param {number} copayerId - the copayer id
* @returns {string} the extended public key of the i-th copayer
*/
PublicKeyRing.prototype.getCopayerId = function(copayerId) {
preconditions.checkArgument(!_.isUndefined(copayerId))
preconditions.checkArgument(_.isNumber(copayerId));
return this.copayerIds[copayerId];
};
/**
* @desc
* Get the amount of registered copayers in this PubKeyRing
*
* @returns {number} amount of copayers present
*/
PublicKeyRing.prototype.registeredCopayers = function() {
return this.copayersHK.length;
};
/**
* @desc
* Returns true if all the needed copayers have joined the public key ring
*
* @returns {boolean}
*/
PublicKeyRing.prototype.isComplete = function() {
return this.remainingCopayers() == 0;
};
/**
* @desc
* Returns the number of copayers yet to join to make the public key ring complete
*
* @returns {number}
*/
PublicKeyRing.prototype.remainingCopayers = function() {
return this.totalCopayers - this.registeredCopayers();
};
/**
* @desc
* Returns an array of copayer's public keys
*
* @returns {string[]} a list of hexadecimal strings with the public keys for
* the copayers in this ring
*/
PublicKeyRing.prototype.getAllCopayerIds = function() {
return this.copayerIds;
};
/**
* @desc
* Gets the current user's copayerId
*
* @returns {string} the extended public key hexadecimal-encoded
*/
PublicKeyRing.prototype.myCopayerId = function() {
return this.getCopayerId(0);
};
/**
* @desc Throws an error if the public key ring isn't complete
*/
PublicKeyRing.prototype._checkKeys = function() {
if (!this.isComplete()) throw new Error('dont have required keys yet');
};
/**
* @desc
* Updates the internal register of the public hex string for a copayer, based
* on the value of the hierarchical key stored in copayersHK
*
* @private
* @param {number} index - the index of the copayer to update
*/
PublicKeyRing.prototype._updateBip = function(index) {
var hk = this.copayersHK[index].derive(HDPath.IdBranch);
this.copayerIds[index] = hk.eckey.public.toString('hex');
};
/**
* @desc
* Sets a nickname for one of the copayers
*
* @private
* @param {number} index - the index of the copayer to update
* @param {string} nickname - the new nickname for that copayer
*/
PublicKeyRing.prototype._setNicknameForIndex = function(index, nickname) {
this.nicknameFor[this.copayerIds[index]] = nickname;
};
/**
* @desc
* Fetch the name of a copayer
*
* @param {number} index - the index of the copayer
* @return {string} the nickname of the index-th copayer
*/
PublicKeyRing.prototype.nicknameForIndex = function(index) {
return this.nicknameFor[this.copayerIds[index]];
};
/**
* @desc
* Fetch the name of a copayer using its public key
*
* @param {string} copayerId - the public key ring of a copayer, hex encoded
* @return {string} the nickname of the copayer with such pubkey
*/
PublicKeyRing.prototype.nicknameForCopayer = function(copayerId) {
return this.nicknameFor[copayerId] || 'NN';
};
/**
* @desc
* Add a copayer into the public key ring.
*
* @param {string} newHexaExtendedPublicKey - an hex encoded string with the copayer's pubkey
* @param {string} nickname - a nickname for this copayer
* @return {string} the newHexaExtendedPublicKey parameter
*/
PublicKeyRing.prototype.addCopayer = function(newHexaExtendedPublicKey, nickname) {
preconditions.checkArgument(newHexaExtendedPublicKey && _.isString(newHexaExtendedPublicKey));
preconditions.checkArgument(!this.isComplete());
preconditions.checkArgument(!nickname || _.isString(nickname));
preconditions.checkArgument(!_.any(this.copayersHK,
function(copayer) {
return copayer.extendedPublicKeyString === newHexaExtendedPublicKey;
}
));
var newCopayerIndex = this.copayersHK.length;
var hierarchicalKey = new HK(newHexaExtendedPublicKey);
this.copayersHK.push(hierarchicalKey);
this._updateBip(newCopayerIndex);
if (nickname) {
this._setNicknameForIndex(newCopayerIndex, nickname);
}
return newHexaExtendedPublicKey;
};
/**
* @desc
* Get all the public keys for the copayers in this ring, for a given branch of Copay
*
* @param {number} index - the index for the shared address
* @param {boolean} isChange - whether to derive a change address o receive address
* @param {number} copayerIndex - the index of the copayer that requested the derivation
* @return {Buffer[]} an array of derived public keys in hexa format
*/
PublicKeyRing.prototype.getPubKeys = function(index, isChange, copayerIndex) {
this._checkKeys();
log.warn('Slow pubkey derivation...');
var path = HDPath.Branch(index, isChange, copayerIndex);
var pubKeys = _.map(this.copayersHK, function(hdKey) {
return hdKey.derive(path).eckey.public;
});
return pubKeys;
};
/**
* @desc
* Generate a new Script for a copay address generated by index, isChange, and copayerIndex
*
* @TODO this could be cached
*
* @param {number} index - the index for the shared address
* @param {boolean} isChange - whether to derive a change address o receive address
* @param {number} copayerIndex - the index of the copayer that requested the derivation
* @returns {bitcore.Script}
*/
PublicKeyRing.prototype.getRedeemScript = function(index, isChange, copayerIndex) {
var pubKeys = this.getPubKeys(index, isChange, copayerIndex);
var script = Script.createMultisig(this.requiredCopayers, pubKeys);
return script;
};
/**
* @desc
* Get the address for a multisig based on the given params.
*
* Caches the address to the branch in the member addressToPath
*
* @param {number} index - the index for the shared address
* @param {boolean} isChange - whether to derive a change address o receive address
* @param {number} copayerIndex - the index of the copayer that requested the derivation
* @returns {bitcore.Address}
*/
PublicKeyRing.prototype._getAddress = function(index, isChange, id) {
var copayerIndex = this.getCosigner(id);
var path = HDPath.FullBranch(index, isChange, copayerIndex);
if (this.cache.pathToAddress[path])
return this.cache.pathToAddress[path];
log.info('Generating Address:', index, isChange, copayerIndex);
var script = this.getRedeemScript(index, isChange, copayerIndex);
var address = Address.fromScript(script, this.network.name).toString();
this._cacheAddress(address, path, isChange);
return address;
};
PublicKeyRing.prototype._cacheAddress = function(address, path, isChange) {
this.cache.addressToPath[address] = path;
this.cache.pathToAddress[path] = address;
};
/**
* @desc
* Get the parameters used to derive a pubkey or a cosigner index
*
* Overloaded to receive a PubkeyString or a consigner index
*
* @param {number|string} id public key in hex format, or the copayer's index
* @return ????
*/
PublicKeyRing.prototype.getHDParams = function(id) {
var copayerIndex = this.getCosigner(id);
var index = this.indexes.filter(function(i) {
return i.copayerIndex == copayerIndex
});
if (index.length != 1) throw new Error('no index for copayerIndex');
return index[0];
};
/**
* @desc
* Get the path used to derive a pubkey or a cosigner index for an address
*
* @param {string} address a multisig p2sh address
* @return {HDPath}
*/
PublicKeyRing.prototype.pathForAddress = function(address) {
this._checkCache();
var path = this.cache.addressToPath[address];
if (!path) throw new Error('Couldn\'t find path for address ' + address);
return path;
};
/**
* @desc
* Generates a new address and updates the last index used
*
* @param {truthy} isChange - generate a change address if true, otherwise
* generates a receive
* @param {number|string} pubkey - the pubkey for the copayer that generates the
* address (or index in the keyring)
* @returns {bitpay.Address}
*/
PublicKeyRing.prototype.generateAddress = function(isChange, pubkey) {
isChange = !!isChange;
var hdParams = this.getHDParams(pubkey);
var index = isChange ? hdParams.getChangeIndex() : hdParams.getReceiveIndex();
var ret = this._getAddress(index, isChange, hdParams.copayerIndex);
hdParams.increment(isChange);
return ret;
};
/**
* @desc Is an address is from this wallet?
*
* @param {string} address
* @return {boolean}
*/
PublicKeyRing.prototype.addressIsOwn = function(address) {
return !!this.cache.addressToPath[address];
};
/**
* @desc Is an address is a change address?
*
* @param {string} address
* @return {boolean}
*/
PublicKeyRing.prototype.addressIsChange = function(address) {
this._checkCache();
var path = this.cache.addressToPath[address];
if (!path)
return null;
var p = HDPath.indexesForPath(path);
//Memoization Only, never stored.
this._isChange[address] = p.isChange;
return !!this._isChange[address];
};
/**
* @desc
* Maps a copayer's public key to his index in the keyring
*
* @param {number|string|undefined} pubKey - if undefined, returns the SHARED_INDEX
* - if a number, just return it
* - if a string, assume is the hex encoded public key
* @returns {number} the index of the copayer with the given pubkey
*/
PublicKeyRing.prototype.getCosigner = function(pubKey) {
if (_.isUndefined(pubKey)) return HDPath.SHARED_INDEX;
if (_.isNumber(pubKey)) return pubKey;
var sorted = this.copayersHK.map(function(h, i) {
return h.eckey.public.toString('hex');
}).sort(function(h1, h2) {
return h1.localeCompare(h2);
});
var index = sorted.indexOf(pubKey);
if (index == -1) throw new Error('public key is not on the ring');
return index;
};
PublicKeyRing.prototype.buildAddressCache = function() {
var ret = [];
var self = this;
_.each(this.indexes, function(index) {
for (var i = 0; i < index.receiveIndex; i++) {
self._getAddress(i, false, index.copayerIndex);
}
for (var i = 0; i < index.changeIndex; i++) {
self._getAddress(i, true, index.copayerIndex);
}
});
};
PublicKeyRing.prototype.size = function(opts) {
var self = this;
return _.reduce(this.indexes, function(sum, index) {
return sum + index.receiveIndex + index.changeIndex
}, 0);
};
PublicKeyRing.prototype._checkCache = function(opts) {
if (_.isEmpty(this.cache.addressToPath)) {
this.buildAddressCache();
}
if (_.size(this.cache.addressToPath) !== this.size()) {
this.buildAddressCache();
}
};
/**
* @desc
* Gets information about addresses for a copayer
*
* @param {Object} opts
* @returns {AddressInfo[]}
*/
PublicKeyRing.prototype.getAddresses = function() {
this._checkCache();
return _.keys(this.cache.addressToPath);
};
/**
* getAddressesOrdered
* {@link Wallet#getAddressesOrdered}
*
* @param pubkey
* @return {string[]}
*/
PublicKeyRing.prototype.getAddressesOrdered = function(pubkey) {
this._checkCache();
var info = _.map(this.cache.addressToPath, function(path, addr) {
var p = HDPath.indexesForPath(path);
p.address = addr;
return p;
});
var copayerIndex = this.getCosigner(pubkey);
var l = info.length;
var sortedInfo = _.sortBy(info, function(i) {
var goodness = ((i.copayerIndex !== copayerIndex) ? 2 * l : 0) + (i.isChange ? l : 0) + l - i.addressIndex;
return goodness;
});
return _.pluck(sortedInfo, 'address');
};
/**
* @desc
* Gets information about addresses for a copayer
*
* @param {Object} opts
* @returns {AddressInfo[]}
*/
PublicKeyRing.prototype.getReceiveAddresses = function() {
this._checkCache();
var self = this;
return _.filter(this.getAddresses(), function(addr) {
return !self.addressIsChange(addr);
});
};
/**
* @desc
* Retrieve the public keys for all cosigners for a given path
*
* @param {string} path - the BIP32 path
* @return {Buffer[]} the public keys, in buffer format
*/
PublicKeyRing.prototype._getForPath = function(path) {
var p = HDPath.indexesForPath(path);
return this.getPubKeys(p.addressIndex, p.isChange, p.copayerIndex);
};
/**
* @desc
* Retrieve the public keys for derived addresses and the public keys for copayers
*
* @TODO: Should this exist? A user should just call _getForPath(paths)
*
* @param {string[]} paths - the paths to be derived
* @return {Object} with keys pubKeys and copayerIds
*/
PublicKeyRing.prototype.forPaths = function(paths) {
return {
pubKeys: paths.map(this._getForPath.bind(this)),
copayerIds: this.copayerIds,
}
};
/**
* @desc
* Retrieve the public keys for all cosigners for multiple paths
*
* @param {string[]} paths - the BIP32 paths
* @return {Array[]} the public keys, in buffer format (matrix of Buffer, Buffer[][])
*/
PublicKeyRing.prototype._getForPaths = function(paths) {
preconditions.checkArgument(!_.isUndefined(paths));
preconditions.checkArgument(_.isArray(paths));
preconditions.checkArgument(_.all(paths, _.isString));
return paths.map(this._getForPath.bind(this));
};
/**
* @desc
* Returns a map from a pubkey of an address to the id that generated it
*
* @param {string[]} pubkeys - the pubkeys to query
* @param {string[]} paths - the paths to query
*/
PublicKeyRing.prototype.copayersForPubkeys = function(pubkeys, paths) {
preconditions.checkArgument(pubkeys);
preconditions.checkArgument(paths);
var inKeyMap = {},
ret = {};
for (var i in pubkeys) {
inKeyMap[pubkeys[i]] = 1;
};
var keys = this._getForPaths(paths);
for (var i in keys) {
for (var copayerIndex in keys[i]) {
var kHex = keys[i][copayerIndex].toString('hex');
if (inKeyMap[kHex]) {
ret[kHex] = this.copayerIds[copayerIndex];
delete inKeyMap[kHex];
}
}
}
if (_.size(inKeyMap)) {
for (var i in inKeyMap) {
log.error('Pubkey ' + i + ' not identified');
}
throw new Error('Pubkeys not identified');
}
return ret;
};
/**
* @desc
* Returns a map from address -> public key needed
*
* @param {HDPath[]} paths - paths to be solved
* @returns {Object} a map from addresses to Buffer with the hex pubkeys
*/
PublicKeyRing.prototype.getRedeemScriptMap = function(paths) {
var ret = {};
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
var p = HDPath.indexesForPath(path);
var script = this.getRedeemScript(p.addressIndex, p.isChange, p.copayerIndex);
ret[Address.fromScript(script, this.network.name).toString()] = script.getBuffer().toString('hex');
}
return ret;
};
/**
* @desc
* Check if another PubKeyRing is similar to this one (checks network name,
* requiredCopayers, and totalCopayers). If ignoreId is falsy, also check that
* both walletIds match.
*
* @private
* @param {PubKeyRing} inPKR - the other PubKeyRing
* @param {boolean} ignoreId - whether to ignore checking for equal walletId
* @throws {Error} if the wallets mismatch
* @return true
*/
PublicKeyRing.prototype._checkInPKR = function(inPKR, ignoreId) {
preconditions.checkArgument(_.isObject(inPKR));
if (!ignoreId && this.walletId !== inPKR.walletId)
throw new Error('inPKR walletId mismatch');
if (this.network.name !== inPKR.network.name)
throw new Error('Network mismatch. Should be ' + this.network.name +
' and found ' + inPKR.network.name);
if (this.requiredCopayers && inPKR.requiredCopayers &&
(this.requiredCopayers !== inPKR.requiredCopayers))
throw new Error('inPKR requiredCopayers mismatch ' + this.requiredCopayers +
'!=' + inPKR.requiredCopayers);
if (this.totalCopayers && inPKR.totalCopayers &&
this.totalCopayers !== inPKR.totalCopayers)
throw new Error('inPKR totalCopayers mismatch' + this.totalCopayers +
'!=' + inPKR.requiredCopayers);
return true;
};
/**
* @desc
* Merges the public keys of the wallet passed in as a parameter with ours.
*
* @param {PublicKeyRing} inPKR
* @return {boolean} true if there where changes in our internal state
*/
PublicKeyRing.prototype._mergePubkeys = function(inPKR) {
var self = this;
var hasChanged = false;
if (self.isComplete())
return;
inPKR.copayersHK.forEach(function(b) {
var epk = b.extendedPublicKeyString();
var haveIt = _.any(self.copayersHK, function(hk) {
return hk.extendedPublicKeyString() === epk;
});
if (!haveIt) {
if (self.isComplete()) {
throw new Error('trying to add more pubkeys, when PKR isComplete at merge');
}
var l2 = self.copayersHK.length;
self.copayersHK.push(new HK(epk));
self._updateBip(l2);
if (inPKR.nicknameFor[self.getCopayerId(l2)])
self._setNicknameForIndex(l2, inPKR.nicknameFor[self.getCopayerId(l2)]);
hasChanged = true;
}
});
return hasChanged;
};
/**
* @desc
* Merges the indexes for addresses generated with another copy of a list of
* HDParams
*
* @param {HDParams[]} indexes - indexes as received from another sources
* @return {boolean} true if the internal state has changed
*/
PublicKeyRing.prototype.mergeIndexes = function(indexes) {
var self = this;
var hasChanged = false;
indexes.forEach(function(theirs) {
var mine = self.getHDParams(theirs.copayerIndex);
hasChanged |= mine.merge(theirs);
});
return !!hasChanged
}
/**
* @desc
* Merges this public key ring with another one, optionally ignoring the
* wallet id
*
* @param {PublicKeyRing} inPkr
* @param {boolean} ignoreId
* @return {boolean} true if the internal state has changed
*/
PublicKeyRing.prototype.merge = function(inPKR, ignoreId) {
this._checkInPKR(inPKR, ignoreId);
var hasChanged = false;
hasChanged |= this.mergeIndexes(inPKR.indexes);
hasChanged |= this._mergePubkeys(inPKR);
return !!hasChanged;
};
module.exports = PublicKeyRing;

View File

@ -1,624 +0,0 @@
'use strict';
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
var bitcore = require('bitcore');
var util = bitcore.util;
var Transaction = bitcore.Transaction;
var TransactionBuilder = bitcore.TransactionBuilder;
var Script = bitcore.Script;
var Key = bitcore.Key;
var log = require('../util/log');
var TX_MAX_SIZE_KB = 50;
var VERSION = 1;
var CORE_FIELDS = ['builderObj', 'inputChainPaths', 'version', 'comment', 'paymentProtocolURL', 'paymentAckMemo'];
function TxProposal(opts) {
preconditions.checkArgument(opts);
preconditions.checkArgument(opts.inputChainPaths, 'no inputChainPaths');
preconditions.checkArgument(opts.builder, 'no builder');
preconditions.checkArgument(opts.inputChainPaths, 'no inputChainPaths');
this.inputChainPaths = opts.inputChainPaths;
this.version = opts.version;
this.builder = opts.builder;
this.createdTs = opts.createdTs;
// Copayer Actions ( copayerId: timeStamp )
this.signedBy = opts.signedBy || {};
this.seenBy = opts.seenBy || {};
this.rejectedBy = opts.rejectedBy || {};
this.sentTs = opts.sentTs || null;
this.sentTxid = opts.sentTxid || null;
this.comment = opts.comment || null;
this.readonly = opts.readonly || null;
this.merchant = opts.merchant || null;
this.paymentAckMemo = opts.paymentAckMemo || null;
this.paymentProtocolURL = opts.paymentProtocolURL || null;
this.resetCache();
// New Tx Proposal
if (_.isEmpty(this.seenBy) && opts.creator) {
var now = Date.now();
var me = {};
me[opts.creator] = now;
this.seenBy = me;
this.signedBy = {};
this.creator = opts.creator;
this.createdTs = now;
if (opts.signWith) {
if (!this.sign(opts.signWith, opts.creator))
throw new Error('Could not sign generated tx');
}
}
}
TxProposal.prototype._checkPayPro = function() {
if (!this.merchant) return;
if (this.paymentProtocolURL !== this.merchant.request_url)
throw new Error('PayPro: Mismatch on Payment URLs');
if (!this.merchant.outs || this.merchant.outs.length !== 1)
throw new Error('PayPro: Unsopported number of outputs');
if (this.merchant.expires < (this.getSent() || Date.now() / 1000.))
throw new Error('PayPro: Request expired');
if (!this.merchant.total || !this.merchant.outs[0].amountSatStr || !this.merchant.outs[0].address)
throw new Error('PayPro: Missing amount');
var outs = JSON.parse(this.builder.vanilla.outs);
if (_.size(outs) != 1)
throw new Error('PayPro: Wrong outs in Tx');
var ppOut = this.merchant.outs[0];
var txOut = outs[0];
if (ppOut.address !== txOut.address)
throw new Error('PayPro: Wrong out address in Tx');
if (ppOut.amountSatStr !== txOut.amountSatStr + '')
throw new Error('PayPro: Wrong amount in Tx');
};
TxProposal.prototype.isFullySigned = function() {
return this.builder && this.builder.isFullySigned();
};
TxProposal.prototype.getMySignatures = function() {
preconditions.checkState(this._mySignatures, 'Still no signatures from us');
return _.clone(this._mySignatures);
};
TxProposal.prototype._setMySignatures = function(signaturesBefore) {
var mySigs = [];
_.each(this.getSignatures(), function(signatures, index) {
var diff = _.difference(signatures, signaturesBefore[index]);
preconditions.checkState(diff.length == 1, 'more that one signature added!');
mySigs.push(diff[0].toString('hex'));
})
this._mySignatures = mySigs;
return;
};
TxProposal.prototype.sign = function(keys, signerId) {
var before = this.countSignatures();
var signaturesBefore = this.getSignatures();
this.builder.sign(keys);
var signaturesAdded = this.countSignatures() > before;
if (signaturesAdded) {
this.signedBy[signerId] = Date.now();
this._setMySignatures(signaturesBefore);
}
return signaturesAdded;
};
TxProposal.prototype._check = function() {
if (this.builder.signhash && this.builder.signhash !== Transaction.SIGHASH_ALL) {
throw new Error('Invalid tx proposal');
}
// Should be able to build
var tx = this.builder.build();
var txSize = tx.getSize();
if (txSize / 1024 > TX_MAX_SIZE_KB)
throw new Error('BIG: Invalid TX proposal. Too big: ' + txSize + ' bytes');
if (!tx.ins.length)
throw new Error('Invalid tx proposal: no ins');
_.each(tx.ins, function(value, index) {
var scriptSig = value.s;
if (!scriptSig || !scriptSig.length) {
throw new Error('Invalid tx proposal: no signatures');
}
var hashType = tx.getHashType(index);
if (hashType && hashType !== Transaction.SIGHASH_ALL)
throw new Error('Invalid tx proposal: bad signatures');
});
this._checkPayPro();
};
TxProposal.prototype.addMerchantData = function(merchantData) {
preconditions.checkArgument(merchantData.pr);
preconditions.checkArgument(merchantData.request_url);
var m = _.clone(merchantData);
if (!this.paymentProtocolURL)
this.paymentProtocolURL = m.request_url;
// remove unneeded data
m.raw = m.pr.pki_data = m.pr.signature = undefined;
this.merchant = m;
this._checkPayPro();
};
TxProposal.prototype.getSignatures = function() {
var ins = this.builder.build().ins;
var sigs = _.map(ins, function(value) {
var script = new bitcore.Script(value.s);
var nchunks = script.chunks.length;
return _.map(script.chunks.slice(1, nchunks - 1), function(buffer) {
return buffer.toString('hex');
});
});
return sigs;
};
TxProposal.prototype.rejectCount = function() {
return _.size(this.rejectedBy);
};
TxProposal.prototype.isFinallyRejected = function(maxRejectCount) {
return this.rejectCount() > maxRejectCount;
};
TxProposal.prototype.isPending = function(maxRejectCount) {
preconditions.checkArgument(_.isNumber(maxRejectCount));
if (this.isFinallyRejected(maxRejectCount) || this.sentTxid)
return false;
return true;
};
TxProposal.prototype._setSigned = function(copayerId) {
// Sign powns rejected
if (this.rejectedBy[copayerId]) {
log.info("WARN: a previously rejected transaction was signed by:", copayerId);
delete this.rejectedBy[copayerId];
}
this.signedBy[copayerId] = Date.now();
return this;
};
/**
*
* @desc verify signatures of ONE copayer, using an array of signatures for each input
*
* @param {string[]} signatures, of the same copayer, one for each input
* @return {string[]} array for signing pubkeys for each input
*/
TxProposal.prototype._addSignatureAndVerify = function(signatures) {
var self = this;
var ret = [];
var tx = self.builder.build();
var inputsFullySigned = 0;
var newScriptSigs = [];
this.resetCache();
_.each(tx.ins, function(input, index) {
var scriptSig = new Script(input.s);
var info = TxProposal.infoFromRedeemScript(scriptSig);
var txSigHash = tx.hashForSignature(info.script, parseInt(index), Transaction.SIGHASH_ALL);
var keys = TxProposal.formatKeys(info.keys);
var sig = new Buffer(signatures[index], 'hex');
var hashType = sig[sig.length - 1];
if (hashType !== Transaction.SIGHASH_ALL)
throw new Error('BADSIG: Invalid signature: Bad hash type');
var sigRaw = new Buffer(sig.slice(0, sig.length - 1));
var signingPubKeyHex = self._verifyOneSignature(keys, sigRaw, txSigHash);
if (!signingPubKeyHex)
throw new Error('BADSIG: Invalid signatures: invalid for input:' + index);
// now insert it
var keysHex = _.pluck(keys, 'keyHex');
var prio = _.indexOf(keysHex, signingPubKeyHex);
preconditions.checkState(prio >= 0);
var currentKeys = self.getSignersPubKeys()[index];
if (_.indexOf(currentKeys, signingPubKeyHex) >= 0)
throw new Error('BADSIG: Already have this signature');
var currentPrios = _.map(currentKeys, function(key) {
var prio = _.indexOf(keysHex, key);
preconditions.checkState(prio >= 0);
return prio;
});
var insertAt = 0;
while (!_.isUndefined(currentPrios[insertAt]) && prio > currentPrios[insertAt])
insertAt++;
// Insert it! (1 is OP_0!)
scriptSig.chunks.splice(1 + insertAt, 0, sig);
scriptSig.updateBuffer();
if (info.nreq == currentKeys.length + 1) {
inputsFullySigned++;
}
newScriptSigs.push(scriptSig.buffer);
});
preconditions.checkState(newScriptSigs.length === tx.ins.length);
// If we reach here, all signatures are OK, let's update the TX.
_.each(tx.ins, function(input, index) {
input.s = newScriptSigs[index];
// just to keep TransactionBuilder updated
if (tx.ins.length == inputsFullySigned)
self.builder.inputsSigned++;
});
};
TxProposal.prototype.resetCache = function() {
this.cache = {
pubkeysForScript: {},
};
};
/**
* addSignature
*
* @param {string[]} signatures from *ONE* copayer, one signature for each TX input.
* @return {boolean} true = signatures added
*/
TxProposal.prototype.addSignature = function(copayerId, signatures) {
preconditions.checkArgument(_.isArray(signatures));
if (this.isFullySigned())
return false;
var tx = this.builder.build();
preconditions.checkArgument(signatures.length === tx.ins.length, 'Wrong number of signatures given');
this._addSignatureAndVerify(signatures);
this._setSigned(copayerId);
return true;
};
/**
*
* getSignersPubKey
* @desc get Pubkeys of signers, for each input. this is CPU intensive
*
* @return {string[][]} array of hashes for signing pubkeys for each input
*/
TxProposal.prototype.getSignersPubKeys = function(forceUpdate) {
var self = this;
var signersPubKey = [];
if (!self.cache.signersPubKey || forceUpdate) {
log.debug('PERFORMANCE WARN: Verifying *all* TX signatures:', self.getId());
var tx = self.builder.build();
_.each(tx.ins, function(input, index) {
if (!self.cache.pubkeysForScript[input.s]) {
var scriptSig = new Script(input.s);
var signatureCount = scriptSig.countSignatures();
var info = TxProposal.infoFromRedeemScript(scriptSig);
var txSigHash = tx.hashForSignature(info.script, parseInt(index), Transaction.SIGHASH_ALL);
var inputSignersPubKey = self.verifySignatures(info.keys, scriptSig, txSigHash);
// Does scriptSig has strings that are not signatures?
if (inputSignersPubKey.length !== signatureCount)
throw new Error('Invalid signature');
self.cache.pubkeysForScript[input.s] = inputSignersPubKey;
}
signersPubKey[index] = self.cache.pubkeysForScript[input.s];
});
self.cache.signersPubKey = signersPubKey;
} else {
log.debug('Using signatures verification cache')
}
return self.cache.signersPubKey;
};
TxProposal.prototype.getId = function() {
preconditions.checkState(this.builder);
if (!this.ntxid) {
this.ntxid = this.builder.build().getNormalizedHash().toString('hex');
}
return this.ntxid;
};
TxProposal.prototype.toObj = function() {
var o = JSON.parse(JSON.stringify(this));
delete o['builder'];
delete o['cache'];
o.builderObj = this.builder.toObj();
return o;
};
TxProposal._trim = function(o) {
var ret = {};
CORE_FIELDS.forEach(function(k) {
ret[k] = o[k];
});
return ret;
};
TxProposal.fromObj = function(o, forceOpts) {
preconditions.checkArgument(o.builderObj);
delete o['builder'];
forceOpts = forceOpts || {};
o.builderObj.opts = o.builderObj.opts || {};
// force opts is requested.
_.each(forceOpts, function(value, key) {
o.builderObj.opts[key] = value;
});
// Handle undef fee options
if (_.isUndefined(forceOpts.fee) && _.isUndefined(forceOpts.feeSat)) {
o.builderObj.opts.fee = undefined;
o.builderObj.opts.feeSat = undefined;
}
try {
o.builder = TransactionBuilder.fromObj(o.builderObj);
} catch (e) {
throw new Error(e);
return null;
}
return new TxProposal(o);
};
TxProposal.fromUntrustedObj = function(o, forceOpts) {
var trimmed = TxProposal._trim(o);
var txp = TxProposal.fromObj(trimmed, forceOpts);
if (!txp)
throw new Error('Invalid Transaction');
txp._check();
return txp;
};
TxProposal.prototype.toObjTrim = function() {
return TxProposal._trim(this.toObj());
};
TxProposal.formatKeys = function(keys) {
var ret = [];
for (var i in keys) {
if (!Buffer.isBuffer(keys[i]))
throw new Error('keys must be buffers');
var k = new Key();
k.public = keys[i];
ret.push({
keyObj: k,
keyHex: keys[i].toString('hex'),
});
}
return ret;
};
/**
* @desc Verify a single signature, for a given hash, tested against a given list of public keys.
* @param keys
* @param sigRaw
* @param txSigHash
* @return {string?} on valid signature, return the signing public key hex representation
*/
TxProposal.prototype._verifyOneSignature = function(keys, sigRaw, txSigHash) {
preconditions.checkArgument(Buffer.isBuffer(txSigHash));
preconditions.checkArgument(Buffer.isBuffer(sigRaw));
preconditions.checkArgument(_.isArray(keys));
preconditions.checkArgument(keys[0].keyObj);
var signingKey = _.find(keys, function(key) {
var ret = false;
try {
ret = key.keyObj.verifySignatureSync(txSigHash, sigRaw);
} catch (e) {};
return ret;
});
return signingKey ? signingKey.keyHex : null;
};
/**
* @desc verify transaction signatures
*
* @param inKeys
* @param scriptSig
* @param txSigHash
* @return {string[]} signing pubkeys, in order of apperance
*/
TxProposal.prototype.verifySignatures = function(inKeys, scriptSig, txSigHash) {
preconditions.checkArgument(Buffer.isBuffer(txSigHash));
preconditions.checkArgument(inKeys);
preconditions.checkState(Buffer.isBuffer(inKeys[0]));
var self = this;
if (scriptSig.chunks[0] !== 0)
throw new Error('Invalid scriptSig');
var keys = TxProposal.formatKeys(inKeys);
var ret = [];
for (var i = 1; i <= scriptSig.countSignatures(); i++) {
var chunk = scriptSig.chunks[i];
log.debug('\t Verifying CHUNK:', i);
var sigRaw = new Buffer(chunk.slice(0, chunk.length - 1));
var signingPubKeyHex = self._verifyOneSignature(keys, sigRaw, txSigHash);
if (!signingPubKeyHex)
throw new Error('Found a signature that is invalid');
ret.push(signingPubKeyHex);
}
return ret;
};
TxProposal.infoFromRedeemScript = function(s) {
var redeemScript = new Script(s.chunks[s.chunks.length - 1]);
if (!redeemScript)
throw new Error('Bad scriptSig (no redeemscript)');
var nreq = nreq = redeemScript.chunks[0] - 80; //see OP_2-OP_16
var pubkeys = redeemScript.capture();
if (!pubkeys || !pubkeys.length)
throw new Error('Bad scriptSig (no pubkeys)');
return {
nreq: nreq,
keys: pubkeys,
script: redeemScript,
};
};
TxProposal.prototype.getSeen = function(copayerId) {
return this.seenBy[copayerId];
};
TxProposal.prototype.setSeen = function(copayerId) {
if (!this.seenBy[copayerId])
this.seenBy[copayerId] = Date.now();
};
TxProposal.prototype.setRejected = function(copayerId) {
if (this.signedBy[copayerId])
throw new Error('Can not reject a signed TX');
if (!this.rejectedBy[copayerId])
this.rejectedBy[copayerId] = Date.now();
return this;
};
TxProposal.prototype.setSent = function(sentTxid) {
this.sentTxid = sentTxid;
this.sentTs = Date.now();
return this;
};
TxProposal.prototype.getSent = function() {
return this.sentTs;
}
TxProposal.prototype.setCopayers = function(pubkeyToCopayerMap) {
var newCopayer = {},
oldCopayers = {},
newSignedBy = {},
readOnlyPeers = {},
isNew = 1;
for (var k in this.signedBy) {
oldCopayers[k] = 1;
isNew = 0;
};
if (isNew == 0) {
if (!this.creator || !this.createdTs)
throw new Error('Existing TX has no creator');
if (!this.signedBy[this.creator])
throw new Error('Existing TX is not signed by creator');
if (Object.keys(this.signedBy).length === 0)
throw new Error('Existing TX has no signatures');
}
var iSig = this.getSignersPubKeys();
for (var i in iSig) {
var copayerId = pubkeyToCopayerMap[iSig[i]];
if (!copayerId)
throw new Error('Found unknown signature')
if (oldCopayers[copayerId]) {
//Already have it. Do nothing
} else {
newCopayer[copayerId] = Date.now();
delete oldCopayers[i];
}
}
if (Object.keys(newCopayer).length > 1)
throw new Error('New TX must have only 1 new signature');
// Handler creator / createdTs.
// from senderId, and must be signed by senderId * DISABLED*
//
if (isNew) {
this.creator = Object.keys(newCopayer)[0];
this.seenBy[this.creator] = this.createdTs = Date.now();
}
//Ended. Update this
_.extend(this.signedBy, newCopayer);
// signedBy has preference over rejectedBy
for (var i in this.signedBy) {
delete this.rejectedBy[i];
}
return Object.keys(newCopayer);
};
//This should be on bitcore / Transaction
TxProposal.prototype.countSignatures = function() {
var tx = this.builder.build();
var ret = 0;
for (var i in tx.ins) {
ret += tx.countInputSignatures(i);
}
return ret;
};
module.exports = TxProposal;

View File

@ -1,156 +0,0 @@
'use strict';
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
var bitcore = require('bitcore');
var util = bitcore.util;
var Transaction = bitcore.Transaction;
var Script = bitcore.Script;
var Key = bitcore.Key;
var buffertools = bitcore.buffertools;
var log = require('../util/log');
var TxProposal = require('./TxProposal');;
function TxProposals(opts) {
opts = opts || {};
this.walletId = opts.walletId;
this.network = opts.networkName === 'livenet' ?
bitcore.networks.livenet : bitcore.networks.testnet;
this.txps = {};
}
// fromObj => from a trusted source
TxProposals.fromObj = function(o, forceOpts) {
var ret = new TxProposals({
networkName: o.networkName,
walletId: o.walletId,
});
o.txps.forEach(function(o2) {
try {
var t = TxProposal.fromObj(o2, forceOpts);
} catch (e) {
log.info('Ignoring corrupted TxProposal:', o2, e);
}
if (t && t.builder) {
var id = t.getId();
ret.txps[id] = t;
}
});
return ret;
};
TxProposals.prototype.length = function() {
return Object.keys(this.txps).length;
};
TxProposals.prototype.getNtxidsSince = function(sinceTs) {
preconditions.checkArgument(sinceTs);
var ret = [];
for (var ii in this.txps) {
var txp = this.txps[ii];
if (txp.createdTs >= sinceTs)
ret.push(ii);
}
return ret;
};
TxProposals.prototype.getNtxids = function() {
return Object.keys(this.txps);
};
TxProposals.prototype.deleteOne = function(ntxid) {
preconditions.checkState(this.txps[ntxid], 'Unknown TXP: ' + ntxid);
delete this.txps[ntxid];
};
TxProposals.prototype.deleteAll = function() {
this.txps = {};
};
TxProposals.prototype.deletePending = function(maxRejectCount) {
for (var ntxid in this.txps) {
if (this.txps[ntxid].isPending(maxRejectCount))
delete this.txps[ntxid];
};
};
TxProposals.prototype.toObj = function() {
var ret = [];
for (var id in this.txps) {
var t = this.txps[id];
if (!t.sent)
ret.push(t.toObj());
}
return {
txps: ret,
walletId: this.walletId,
networkName: this.network.name,
};
};
// Add a LOCALLY CREATED (trusted) tx proposal
TxProposals.prototype.add = function(txp) {
var ntxid = txp.getId();
this.txps[ntxid] = txp;
return ntxid;
};
TxProposals.prototype.exist = function(ntxid) {
return this.txps[ntxid] ? true : false;
};
TxProposals.prototype.get = function(ntxid) {
var ret = this.txps[ntxid];
if (!ret)
throw new Error('Unknown TXP: ' + ntxid);
return ret;
};
//returns the unspent txid-vout used in PENDING Txs
TxProposals.prototype.getUsedUnspent = function(maxRejectCount) {
var ret = {};
var self = this;
_.each(this.txps, function(txp) {
if (!txp.isPending(maxRejectCount))
return
_.each(txp.builder.getSelectedUnspent(), function(u) {
ret[u.txid + ',' + u.vout] = 1;
});
});
return ret;
};
/**
* purge
*
* @param deleteAll
* @return {undefined}
*/
TxProposals.prototype.purge = function(deleteAll, maxRejectCount) {
var m = _.size(this.txps);
if (deleteAll) {
this.deleteAll();
} else {
this.deletePending(maxRejectCount);
}
var n = _.size(this.txps);
return m - n;
};
module.exports = TxProposals;

File diff suppressed because it is too large Load Diff

View File

@ -1,116 +0,0 @@
'use strict';
var preconditions = require('preconditions').singleton();
function WalletLock(storage, walletId, timeoutMin) {
preconditions.checkArgument(storage);
preconditions.checkArgument(walletId);
this.storage = storage;
this.timeoutMin = timeoutMin || 5;
this.key = WalletLock._keyFor(walletId);
}
WalletLock.prototype.getSessionId = function(cb) {
preconditions.checkArgument(cb);
var self = this;
self.sessionStorage.getItem('sessionId', function(sessionId) {
if (sessionId)
return cb(sessionId);
sessionId = bitcore.SecureRandom.getRandomBuffer(8).toString('hex');
self.sessionStorage.setItem('sessionId', sessionId, function() {
return cb(sessionId);
});
});
};
WalletLock.prototype.init = function(cb) {
preconditions.checkArgument(cb);
var self = this;
self.storage.getSessionId(function(sid) {
preconditions.checkState(sid);
self.sessionId = sid;
cb();
});
};
WalletLock._keyFor = function(walletId) {
return 'lock' + '::' + walletId;
};
WalletLock.prototype._isLockedByOther = function(cb) {
var self = this;
this.storage.getGlobal(this.key, function(json) {
var wl = json ? JSON.parse(json) : null;
if (!wl || !wl.expireTs)
return cb(false);
var expiredSince = Date.now() - wl.expireTs;
if (expiredSince >= 0)
return cb(false);
var isMyself = wl.sessionId === self.sessionId;
if (isMyself)
return cb(false);
// Seconds remainding
return cb(parseInt(-expiredSince / 1000));
});
};
WalletLock.prototype._setLock = function(cb) {
preconditions.checkArgument(cb);
preconditions.checkState(this.sessionId);
var self = this;
this.storage.setGlobal(this.key, {
sessionId: this.sessionId,
expireTs: Date.now() + this.timeoutMin * 60 * 1000,
}, function() {
cb(null);
});
};
WalletLock.prototype._doKeepAlive = function(cb) {
preconditions.checkArgument(cb);
preconditions.checkState(this.sessionId);
var self = this;
this._isLockedByOther(function(t) {
if (t)
return cb(new Error('LOCKED: Wallet is locked for ' + t + ' srcs'));
self._setLock(cb);
});
};
WalletLock.prototype.keepAlive = function(cb) {
var self = this;
if (!self.sessionId) {
return self.init(self._doKeepAlive.bind(self, cb));
};
return this._doKeepAlive(cb);
};
WalletLock.prototype.release = function(cb) {
this.storage.removeGlobal(this.key, cb);
};
module.exports = WalletLock;

View File

@ -1,59 +0,0 @@
var cryptoUtil = require('../util/crypto');
var InsightStorage = require('./InsightStorage');
var inherits = require('inherits');
var log = require('../util/log');
var SEPARATOR = '%^#@';
function EncryptedInsightStorage(config) {
InsightStorage.apply(this, [config]);
}
inherits(EncryptedInsightStorage, InsightStorage);
EncryptedInsightStorage.prototype._brokenDecrypt = function(body) {
var key = cryptoUtil.kdf(this.password + this.email, 'mjuBtGybi/4=', 100);
log.debug('Trying legacy decrypt')
var decryptedJson = cryptoUtil.decrypt(key, body);
return decryptedJson;
};
EncryptedInsightStorage.prototype.resendVerificationEmail = function(callback) {
InsightStorage.prototype.resendVerificationEmail.apply(this, [callback]);
};
EncryptedInsightStorage.prototype.getItem = function(name, callback) {
var self = this;
InsightStorage.prototype.getItem.apply(this, [name,
function(err, body, headers) {
if (err) {
return callback(err);
}
var decryptedJson = cryptoUtil.decrypt(self.email + SEPARATOR + self.password, body);
if (!decryptedJson) {
log.debug('Could not decrypt value using current decryption schema');
decryptedJson = self._brokenDecrypt(body);
}
if (!decryptedJson) {
log.debug('Could not decrypt value.');
return callback('PNOTFOUND');
}
return callback(null, decryptedJson, headers);
}
]);
};
EncryptedInsightStorage.prototype.setItem = function(name, value, callback) {
var record = cryptoUtil.encrypt(this.email + SEPARATOR + this.password, value);
InsightStorage.prototype.setItem.apply(this, [name, record, callback]);
};
EncryptedInsightStorage.prototype.removeItem = function(name, callback) {
InsightStorage.prototype.removeItem.apply(this, [name, callback]);
};
EncryptedInsightStorage.prototype.clear = function(callback) {
InsightStorage.prototype.clear.apply(this, [callback]);
};
module.exports = EncryptedInsightStorage;

View File

@ -1,77 +0,0 @@
var cryptoUtil = require('../util/crypto');
var log = require('../util/log');
var LocalStorage = require('./LocalStorage');
var inherits = require('inherits');
var preconditions = require('preconditions').singleton();
var SEPARATOR = '@#$';
function EncryptedLocalStorage(config) {
LocalStorage.apply(this, [config]);
}
inherits(EncryptedLocalStorage, LocalStorage);
EncryptedLocalStorage.prototype._brokenDecrypt = function(body) {
var key = cryptoUtil.kdf(this.password + this.email, 'mjuBtGybi/4=', 100);
log.debug('Trying legacy decrypt')
var decryptedJson = cryptoUtil.decrypt(key, body);
return decryptedJson;
};
EncryptedLocalStorage.prototype._brokenDecryptUndef = function(body) {
var badkey = undefined + SEPARATOR + undefined;
return cryptoUtil.decrypt(badkey, body);
};
EncryptedLocalStorage.prototype.getItem = function(name, callback) {
var self = this;
preconditions.checkState(self.email);
LocalStorage.prototype.getItem.apply(this, [name,
function(err, body) {
var decryptedJson = cryptoUtil.decrypt(self.email + SEPARATOR + self.password, body);
if (!decryptedJson) {
log.debug('Could not decrypt value using current decryption schema');
decryptedJson = self._brokenDecrypt(body);
}
if (!decryptedJson) {
decryptedJson = self._brokenDecryptUndef(body);
}
if (!decryptedJson) {
log.debug('Could not decrypt value.');
return callback('PNOTFOUND');
}
return callback(null, decryptedJson);
}
]);
};
EncryptedLocalStorage.prototype.setItem = function(name, value, callback) {
if (!_.isString(value)) {
value = JSON.stringify(value);
}
var record = cryptoUtil.encrypt(this.email + SEPARATOR + this.password, value);
LocalStorage.prototype.setItem.apply(this, [name, record, callback]);
};
EncryptedLocalStorage.prototype.removeItem = function(name, callback) {
LocalStorage.prototype.removeItem.apply(this, [name, callback]);
};
EncryptedLocalStorage.prototype.clear = function(callback) {
LocalStorage.prototype.clear.apply(this, [callback]);
};
module.exports = EncryptedLocalStorage;

View File

@ -1,301 +0,0 @@
'use strict';
var preconditions = require('preconditions').singleton();
var loaded = 0;
var SCOPES = 'https://www.googleapis.com/auth/drive';
var log = require('../util/log');
function GoogleDrive(config) {
preconditions.checkArgument(config && config.clientId, 'No clientId at GoogleDrive config');
this.clientId = config.clientId;
this.home = config.home || 'copay';
this.idCache = {};
this.type = 'DB';
this.scripts = [{
then: this.initLoaded.bind(this),
src: 'https://apis.google.com/js/client.js?onload=InitGoogleDrive'
}];
this.isReady = false;
this.useImmediate = true;
this.ts = 100;
};
window.InitGoogleDrive = function() {
log.debug('googleDrive loadeded'); //TODO
loaded = 1;
};
GoogleDrive.prototype.init = function() {};
/**
* Called when the client library is loaded to start the auth flow.
*/
GoogleDrive.prototype.initLoaded = function() {
if (!loaded) {
window.setTimeout(this.initLoaded.bind(this), 500);
} else {
window.setTimeout(this.checkAuth.bind(this), 1);
}
}
/**
* Check if the current user has authorized the application.
*/
GoogleDrive.prototype.checkAuth = function() {
log.debug('Google Drive: Checking Auth');
gapi.auth.authorize({
'client_id': this.clientId,
'scope': SCOPES,
'immediate': this.useImmediate,
},
this.handleAuthResult.bind(this));
};
GoogleDrive.prototype.setCredentils = function(email, password, opts, callback) {
};
/**
* Called when authorization server replies.
*/
GoogleDrive.prototype.handleAuthResult = function(authResult) {
var self = this;
log.debug('Google Drive: authResult', authResult); //TODO
if (authResult.error) {
if (authResult.error) {
self.useImmediate = false;
return this.checkAuth();
};
throw new Error(authResult.error);
}
gapi.client.load('drive', 'v2', function() {
self.isReady = true;
});
}
GoogleDrive.prototype.checkReady = function() {
if (!this.isReady)
throw new Error('goggle drive is not ready!');
};
GoogleDrive.prototype._httpGet = function(theUrl) {
var accessToken = gapi.auth.getToken().access_token;
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", theUrl, false);
xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xmlHttp.send(null);
return xmlHttp.responseText;
}
GoogleDrive.prototype.createItem = function(name, value, callback) {
this.getItem(name, function(err, retrieved) {
if (err || !retrieved) {
return this.setItem(name, value, callback);
} else {
return callback('EEXISTS');
}
});
};
GoogleDrive.prototype.getItem = function(k, cb) {
//console.log('[googleDrive.js.95:getItem:]', k); //TODO
var self = this;
self.checkReady();
self._idForName(k, function(kId) {
// console.log('[googleDrive.js.89:kId:]', kId); //TODO
if (!kId)
return cb(null);
var args = {
'path': '/drive/v2/files/' + kId,
'method': 'GET',
};
// console.log('[googleDrive.js.95:args:]', args); //TODO
var request = gapi.client.request(args);
request.execute(function(res) {
// console.log('[googleDrive.js.175:res:]', res); //TODO
if (!res || !res.downloadUrl)
return cb(null);
return cb(self._httpGet(res.downloadUrl));
});
});
};
GoogleDrive.prototype.setItem = function(k, v, cb) {
// console.log('[googleDrive.js.111:setItem:]', k, v); //TODO
var self = this;
self.checkReady();
self._idForName(this.home, function(parentId) {
preconditions.checkState(parentId);
// console.log('[googleDrive.js.118:parentId:]', parentId); //TODO
self._idForName(k, function(kId) {
// console.log('[googleDrive.js.105]', parentId, kId); //TODO
var boundary = '-------314159265358979323846';
var delimiter = "\r\n--" + boundary + "\r\n";
var close_delim = "\r\n--" + boundary + "--";
var metadata = {
'title': k,
'mimeType': 'application/octet-stream',
'parents': [{
'id': parentId
}],
};
var base64Data = btoa(v);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: application/octet-stream \r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var args = {
'path': '/upload/drive/v2/files' + (kId ? '/' + kId : ''),
'method': kId ? 'PUT' : 'POST',
'params': {
'uploadType': 'multipart',
},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody
}
// console.log('[googleDrive.js.148:args:]', args); //TODO
var request = gapi.client.request(args);
request.execute(function(ret) {
return cb(ret.kind === 'drive#file' ? null : new Error('error saving file on drive'));
});
});
});
};
GoogleDrive.prototype.removeItem = function(k, cb) {
var self = this;
self.checkReady();
self._idForName(this.home, function(parentId) {
preconditions.checkState(parentId);
self._idForName(k, function(kId) {
var args = {
'path': '/drive/v2/files/' + kId,
'method': 'DELETE',
};
var request = gapi.client.request(args);
request.execute(function() {
if (cb)
cb();
});
});
});
};
GoogleDrive.prototype.clear = function() {
this.checkReady();
throw new Error('clear not implemented');
};
GoogleDrive.prototype._mkdir = function(cb) {
preconditions.checkArgument(cb);
var self = this;
log.debug('Creating drive folder ' + this.home);
var request = gapi.client.request({
'path': '/drive/v2/files',
'method': 'POST',
'body': JSON.stringify({
'title': this.home,
'mimeType': "application/vnd.google-apps.folder",
}),
});
request.execute(function() {
self._idForName(self.home, cb);
});
};
GoogleDrive.prototype._idForName = function(name, cb) {
// console.log('[googleDrive.js.199:_idForName:]', name); //TODO
preconditions.checkArgument(name);
preconditions.checkArgument(cb);
var self = this;
if (!self.isReady) {
log.debug('Waiting for Google Drive');
self.ts = self.ts * 1.5;
return setTimeout(self._idForName.bind(self, name, cb), self.ts);
}
if (self.idCache[name]) {
// console.log('[googleDrive.js.212:] FROM CACHE', name, self.idCache[name]); //TODO
return cb(self.idCache[name]);
}
log.debug('GoogleDrive Querying for: ', name); //TODO
var args;
var idParent = name == this.home ? 'root' : self.idCache[this.home];
if (!idParent) {
return self._mkdir(function() {
self._idForName(name, cb);
});
}
// console.log('[googleDrive.js.177:idParent:]', idParent); //TODO
preconditions.checkState(idParent);
args = {
'path': '/drive/v2/files',
'method': 'GET',
'params': {
'q': "title='" + name + "' and trashed = false and '" + idParent + "' in parents",
}
};
var request = gapi.client.request(args);
request.execute(function(res) {
var i = res.items && res.items[0] ? res.items[0].id : false;
if (i)
self.idCache[name] = i;
// console.log('[googleDrive.js.238] CACHING ' + name + ':' + i); //TODO
return cb(self.idCache[name]);
});
};
GoogleDrive.prototype._checkHomeDir = function(cb) {
var self = this;
this._idForName(this.home, function(homeId) {
if (!homeId)
return self._mkdir(cb);
return cb(homeId);
});
};
module.exports = GoogleDrive;

View File

@ -1,287 +0,0 @@
var request = require('request');
var cryptoUtil = require('../util/crypto');
var bitcore = require('bitcore');
var buffers = require('buffer');
var querystring = require('querystring');
var Identity = require('../models/Identity');
var log = require('../util/log');
var SEPARATOR = '|';
function InsightStorage(config) {
this.type = 'DB';
this.storeUrl = config.url || 'https://insight.bitpay.com:443/api/email',
this.request = config.request || request;
this.iterations = config.iterations || 1000;
this.salt = config.salt || 'jBbYTj8zTrOt6V';
}
InsightStorage.prototype.init = function() {};
InsightStorage.prototype.setCredentials = function(email, password, opts) {
this.email = email;
this.password = password;
this._cachedKey = null;
};
InsightStorage.prototype.createItem = function(name, value, callback) {
var self = this;
this.getItem(name, function(err, retrieved) {
if (err || !retrieved) {
return self.setItem(name, value, callback);
} else {
return callback('EEXISTS');
}
});
};
InsightStorage.prototype.resendVerificationEmail = function (callback) {
var passphrase = this.getPassphrase();
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var resendUrl = this.storeUrl + '/resend_email';
log.debug('Resending verification email: ' + this.email);
this.request.get({
url: resendUrl,
headers: {
'Authorization': authHeader
},
body: null,
}, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 409) {
return callback('BADCREDENTIALS: Invalid username or password');
} else if (response.statusCode !== 200) {
return callback('Unable to process the request');
}
return callback();
});
};
function mayBeOldPassword(password) {
// Test for base64
return /^[a-zA-Z0-9\/=\+]+$/.test(password);
}
InsightStorage.prototype.getItem = function(name, callback) {
var passphrase = this.getPassphrase();
var self = this;
this._makeGetRequest(passphrase, name, function(err, body, headers) {
if (err) log.warn(err);
if (err && err.indexOf('PNOTFOUND') !== -1 && mayBeOldPassword(self.password)) {
return self._brokenGetItem(name, callback);
}
return callback(err, body, headers);
});
};
/* This key need to have DIFFERENT
* settings(salt,iterations) than the kdf for wallet/profile encryption
* in Encrpted*Storage. The user should be able
* to change the settings on config.js to modify salt / iterations
* for encryption, but
* mantain the same key & passphrase. This is why those settings are
* not shared with encryption
*/
InsightStorage.prototype.getKey = function() {
if (!this._cachedKey) {
this._cachedKey = cryptoUtil.kdf(this.password + SEPARATOR + this.email, this.salt, this.iterations);
}
return this._cachedKey;
};
InsightStorage.prototype.getPassphrase = function() {
return bitcore.util.twoSha256(this.getKey()).toString('base64');
};
/**
* XmlHttpRequest's getAllResponseHeaders() method returns a string of response
* headers according to the format described here:
* http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
* This method parses that string into a user-friendly key/value pair object.
*/
InsightStorage.parseResponseHeaders = function (headerStr) {
var headers = {};
if (!headerStr) {
return headers;
}
var headerPairs = headerStr.split('\u000d\u000a');
for (var i = 0, len = headerPairs.length; i < len; i++) {
var headerPair = headerPairs[i];
var index = headerPair.indexOf('\u003a\u0020');
if (index > 0) {
var key = headerPair.substring(0, index);
var val = headerPair.substring(index + 2);
headers[key] = val;
}
}
return headers;
}
InsightStorage.prototype._makeGetRequest = function(passphrase, key, callback) {
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var retrieveUrl = this.storeUrl + '/retrieve';
var getParams = {
url: retrieveUrl + '?' + querystring.encode({
key: key,
rand: Math.random() // prevent cache
}),
headers: {
'Authorization': authHeader
}
};
this.request.get(getParams,
function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 403) {
return callback('PNOTFOUND: Profile not found');
}
if (response.statusCode !== 200) {
return callback('Unable to read item from insight');
}
return callback(null, body, InsightStorage.parseResponseHeaders(response.getAllResponseHeaders()));
}
);
};
InsightStorage.prototype._brokenGetItem = function(name, callback) {
var passphrase = this._makeBrokenSecret();
var self = this;
log.debug('using legacy get');
this._makeGetRequest(passphrase, name, function(err, body) {
if (!err) {
return self._changePassphrase(function(err) {
if (err) {
return callback(err);
}
return callback(null, body);
});
}
return callback(err);
});
};
InsightStorage.prototype._makeBrokenSecret = function() {
var key = cryptoUtil.kdf(this.password + this.email, 'mjuBtGybi/4=', 100);
return cryptoUtil.kdf(key, this.password, 100);
};
InsightStorage.prototype._changePassphrase = function(callback) {
var passphrase = this._makeBrokenSecret();
var newPassphrase = this.getPassphrase();
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var url = this.storeUrl + '/change_passphrase';
this.request.post({
url: url,
headers: {
'Authorization': authHeader
},
body: querystring.encode({
newPassphrase: newPassphrase
})
}, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 409) {
return callback('BADCREDENTIALS: Invalid username or password');
}
if (response.statusCode !== 200) {
return callback('Unable to store data on insight');
}
return callback();
});
};
InsightStorage.prototype.setItem = function(name, value, callback) {
var passphrase = this.getPassphrase();
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var registerUrl = this.storeUrl + '/save';
log.debug('setItem ' + name + ' size:'+ (value.length/1024).toFixed(1) + 'kb' );
this.request.post({
url: registerUrl,
headers: {
'Authorization': authHeader
},
body: querystring.encode({
key: name,
record: value
})
}, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 409) {
return callback('BADCREDENTIALS: Invalid username or password');
} else if (response.statusCode === 406) {
return callback('OVERQUOTA: Quota exceeded');
} else if (response.statusCode === 501) {
return callback('EMAILERROR: Error sending verification email');
} else if (response.statusCode !== 200) {
return callback('Unable to store data on insight');
}
return callback();
});
};
InsightStorage.prototype.removeItem = function(key, callback) {
var passphrase = this.getPassphrase();
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var deleteUrl = this.storeUrl + '/delete/item';
var getParams = {
url: deleteUrl + '?' + querystring.encode({
key: key
}),
headers: {
'Authorization': authHeader
}
};
log.debug('Erasing: ' + key);
this.request.get(getParams, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 409) {
return callback('BADCREDENTIALS: Invalid username or password');
} else if (response.statusCode !== 200) {
return callback('Unable to remove data on insight');
}
return callback();
});
};
InsightStorage.prototype.clear = function(callback) {
var passphrase = this.getPassphrase();
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
var deleteUrl = this.storeUrl + '/delete/profile';
log.debug('Clearing storage for: ' + this.email);
this.request.post({
url: deleteUrl,
headers: {
'Authorization': authHeader
},
body: null,
}, function(err, response, body) {
if (err) {
return callback('Connection error');
}
if (response.statusCode === 409) {
return callback('BADCREDENTIALS: Invalid username or password');
} else if (response.statusCode !== 200) {
return callback('Unable to remove data on insight');
}
return callback();
});
};
module.exports = InsightStorage;

View File

@ -1,106 +0,0 @@
'use strict';
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
var isChromeApp = typeof window !== "undefined" && window.chrome && chrome.runtime && chrome.runtime.id;
function LocalStorage(opts) {
this.type = 'DB';
opts = opts || {};
this.ls = opts.ls ||
((typeof localStorage !== "undefined") ? localStorage : null);
if (isChromeApp && !this.ls) {
this.ls = localStorage = chrome.storage.local;
window.localStorage = chrome.storage.local;
}
preconditions.checkState(this.ls,
'localstorage not available, cannot run plugin');
};
LocalStorage.prototype.init = function() {};
LocalStorage.prototype.setCredentials = function(email, password, opts) {
this.email = email;
this.password = password;
};
LocalStorage.prototype.getItem = function(k, cb) {
if (isChromeApp) {
chrome.storage.local.get(k,
function(data) {
//TODO check for errors
return cb(null, data[k]);
});
} else {
return cb(null, this.ls.getItem(k));
}
};
/**
* Same as setItem, but fails if an item already exists
*/
LocalStorage.prototype.createItem = function(name, value, callback) {
var self = this;
self.getItem(name,
function(err, data) {
if (data) {
return callback('EEXISTS');
} else {
return self.setItem(name, value, callback);
}
});
};
LocalStorage.prototype.setItem = function(k, v, cb) {
if (isChromeApp) {
var obj = {};
obj[k] = v;
chrome.storage.local.set(obj, cb);
} else {
this.ls.setItem(k, v);
return cb();
}
};
LocalStorage.prototype.removeItem = function(k, cb) {
if (isChromeApp) {
chrome.storage.local.remove(k, cb);
} else {
this.ls.removeItem(k);
return cb();
}
};
LocalStorage.prototype.clear = function(cb) {
// NOP
return cb();
};
LocalStorage.prototype.allKeys = function(cb) {
if (isChromeApp) {
chrome.storage.local.get(null, function(items) {
return cb(null, _.keys(items));
});
} else {
var ret = [];
var l = this.ls.length;
for (var i = 0; i < l; i++)
ret.push(this.ls.key(i));
return cb(null, ret);
}
};
module.exports = LocalStorage;

View File

@ -1,28 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('applicationService', function($rootScope, $location, $timeout, go, isCordova) {
var root = {};
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
root.restart = function() {
if (isCordova) {
$rootScope.iden = $rootScope.wallet = undefined;
go.path('/');
$timeout(function(){
$rootScope.$digest();
},1);
} else {
// Go home reloading the application
var hashIndex = window.location.href.indexOf('#!/');
if (isChromeApp) {
chrome.runtime.reload();
} else {
window.location = window.location.href.substr(0, hashIndex);
}
}
};
return root;
});

View File

@ -1,86 +0,0 @@
'use strict';
var BackupService = function($rootScope, notification) {
this.$rootScope = $rootScope;
this.notifications = notification;
};
BackupService.prototype.getCopayer = function(wallet) {
return wallet.totalCopayers > 1 ? wallet.getMyCopayerNickname() : '';
};
BackupService.prototype._download = function(ew, walletName, filename) {
var NewBlob = function(data, datatype) {
var out;
try {
out = new Blob([data], {
type: datatype
});
console.debug("case 1");
} catch (e) {
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if (e.name == 'TypeError' && window.BlobBuilder) {
var bb = new BlobBuilder();
bb.append(data);
out = bb.getBlob(datatype);
console.debug("case 2");
} else if (e.name == "InvalidStateError") {
// InvalidStateError (tested on FF13 WinXP)
out = new Blob([data], {
type: datatype
});
console.debug("case 3");
} else {
// We're screwed, blob constructor unsupported entirely
console.debug("Errore");
}
}
return out;
};
var blob;
blob = new NewBlob(ew, 'text/plain;charset=utf-8');
this.notifications.success('Backup created', 'Encrypted backup file saved');
// otherwise lean on the browser implementation
saveAs(blob, filename);
};
BackupService.prototype.walletEncrypted = function(wallet) {
return wallet.exportEncrypted(this.$rootScope.iden.password);
}
BackupService.prototype.walletDownload = function(wallet) {
var ew = this.walletEncrypted(wallet);
var walletName = wallet.getName();
var copayerName = this.getCopayer(wallet);
var filename = (copayerName ? copayerName + '-' : '') + walletName + '-keybackup.json.aes';
this._download(ew, walletName, filename)
};
BackupService.prototype.profileEncrypted = function(iden) {
iden.setBackupNeeded(false);
return iden.exportEncryptedWithWalletInfo(iden.password);
}
BackupService.prototype.profileDownload = function(iden) {
var ew = this.profileEncrypted(iden);
var name = iden.fullName;
var filename = name + '-profile.json';
this._download(ew, name, filename)
};
angular.module('copayApp.services').service('backupService', BackupService);

View File

@ -1,13 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('Compatibility', function($rootScope) {
var root = {};
root.check = function (scope) {
copay.Compatibility.listWalletsPre8(function(wallets) {
scope.anyWallet = wallets.length > 0 ? true : false;
scope.oldWallets = wallets;
});
};
return root;
});

View File

@ -1,36 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('configService', function($timeout, localstorageService, gettextCatalog, defaults) {
var root = {};
root.set = function(opts, cb) {
// Options that have runtime effects
if (opts.logLevel)
copay.logger.setLevel(opts.logLevel);
// Set current version
opts.version = copay.version;
localstorageService.getItem('config', function(err, oldOpsStr) {
var oldOpts = {};
try {
oldOpts = JSON.parse(oldOpsStr);
} catch (e) {};
var newOpts = {};
_.extend(newOpts, copay.defaultConfig, oldOpts, opts);
// TODO remove this global variable.
config = newOpts;
localstorageService.setItem('config', JSON.stringify(newOpts), cb);
});
};
root.reset = function(cb) {
config = defaults;
localstorageService.removeItem('config', cb);
};
return root;
});

View File

@ -1,363 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('identityService', function($rootScope, $location, $timeout, $filter, pluginManager, notification, pendingTxsService, balanceService, applicationService, go) {
// TODO:
// * remove iden from rootScope
// * remove wallet from rootScope
// * create walletService
var root = {};
root.check = function(scope) {
copay.Identity.checkIfExistsAny({
pluginManager: pluginManager.getInstance(config),
}, function(anyProfile) {
copay.Wallet.checkIfExistsAny({
pluginManager: pluginManager.getInstance(config),
}, function(anyWallet) {
scope.loading = false;
scope.anyProfile = anyProfile ? true : false;
scope.anyWallet = anyWallet ? true : false;
if (!scope.anyProfile) {
$location.path('/createProfile');
}
});
});
};
root.create = function(email, password, cb) {
copay.Identity.create({
email: email,
password: password,
pluginManager: pluginManager.getInstance(config),
network: config.network,
networkName: config.networkName,
walletDefaults: config.wallet,
passphraseConfig: config.passphraseConfig,
failIfExists: true,
}, function(err, iden) {
if (err) return cb(err);
preconditions.checkState(iden);
root.bind(iden);
return cb(null);
});
};
root.createDefaultWallet = function(cb) {
var iden = $rootScope.iden;
var walletOptions = {
nickname: iden.fullName,
networkName: config.networkName,
requiredCopayers: 1,
totalCopayers: 1,
password: iden.password,
name: 'My wallet',
};
iden.createWallet(walletOptions, function(err, wallet) {
return cb(err);
});
};
root.resendVerificationEmail = function(cb) {
var iden = $rootScope.iden;
iden.resendVerificationEmail(cb);
};
root.setServerStatus = function(headers) {
if (!headers)
return;
var customHeaders = {};
_.each(_.keys(headers), function(headerKey) {
var hk = headerKey.toLowerCase();
if (hk.indexOf('x-') === 0) {
customHeaders[hk] = headers[headerKey];
}
});
if (customHeaders['x-email-needs-validation'])
$rootScope.needsEmailConfirmation = true;
else
$rootScope.needsEmailConfirmation = null;
if (customHeaders['x-quota-per-item'])
$rootScope.quotaPerItem = parseInt(customHeaders['x-quota-per-item']);
if (customHeaders['x-quota-items-limit'])
$rootScope.quotaItems = parseInt(customHeaders['x-quota-items-limit']);
};
root.open = function(email, password, cb) {
var opts = {
email: email,
password: password,
pluginManager: pluginManager.getInstance(config),
network: config.network,
networkName: config.networkName,
walletDefaults: config.wallet,
passphraseConfig: config.passphraseConfig,
};
copay.Identity.open(opts, function(err, iden, headers) {
if (err) return cb(err);
root.setServerStatus(headers);
root.bind(iden);
return cb(null, iden);
});
};
root.deleteProfile = function(cb) {
$rootScope.iden.remove(null, cb);
};
root.deleteWallet = function(w, cb) {
$rootScope.iden.deleteWallet(w.getId(), cb);
};
root.isFocused = function(wid) {
return $rootScope.wallet && wid === $rootScope.wallet.getId();
};
root.setupGlobalVariables = function(iden) {
$rootScope.reconnecting = false;
$rootScope.iden = iden;
};
root.noFocusedWallet = function() {
$rootScope.wallet = null;
$timeout(function() {
$rootScope.$digest();
})
};
root.setFocusedWallet = function(w, dontUpdateIt) {
if (!_.isObject(w))
w = $rootScope.iden.getWalletById(w);
preconditions.checkState(w && _.isObject(w));
copay.logger.debug('Set focus:', w.getName());
$rootScope.wallet = w;
if (!dontUpdateIt)
$rootScope.iden.updateFocusedTimestamp(w.getId());
pendingTxsService.update();
$timeout(function() {
$rootScope.$digest();
}, 1);
};
root.notifyTxProposalEvent = function(w, e) {
if (e.cId == w.getMyCopayerId())
return;
var user = w.publicKeyRing.nicknameForCopayer(e.cId);
var name = w.getName();
switch (e.type) {
case copay.Wallet.TX_NEW:
notification.info('[' + name + '] New Transaction',
$filter('translate')('You received a transaction proposal from') + ' ' + user);
break;
case copay.Wallet.TX_SIGNED:
notification.success('[' + name + '] Transaction Signed',
$filter('translate')('A transaction was signed by') + ' ' + user);
break;
case copay.Wallet.TX_BROADCASTED:
notification.success('[' + name + '] Transaction Approved',
$filter('translate')('A transaction was broadcasted by') + ' ' + user);
break;
case copay.Wallet.TX_REJECTED:
notification.warning('[' + name + '] Transaction Rejected',
$filter('translate')('A transaction was rejected by') + ' ' + user);
break;
}
};
root.installWalletHandlers = function(w) {
var wid = w.getId();
w.on('connectionError', function() {
if (root.isFocused(wid)) {
var message = "Could not connect to the Insight server. Check your settings and network configuration";
notification.error('Networking Error', message);
}
});
w.on('corrupt', function(peerId) {
copay.logger.warn('Received corrupt message from ' + peerId);
});
w.on('publicKeyRingUpdated', function() {
$rootScope.$digest();
});
w.on('ready', function() {
var isFocused = root.isFocused(wid);
copay.logger.debug('Wallet:' + w.getName() +
' is ready. Focused:', isFocused);
balanceService.update(w, function() {
$rootScope.$digest();
}, isFocused);
});
w.on('tx', function(address, isChange) {
if (!isChange) {
notification.funds('Funds received on ' + w.getName(), address);
}
balanceService.update(w, function() {
$rootScope.$digest();
}, root.isFocused(wid));
});
w.on('balanceUpdated', function() {
balanceService.update(w, function() {
$rootScope.$digest();
}, root.isFocused(wid));
});
w.on('insightReconnected', function() {
$rootScope.reconnecting = false;
balanceService.update(w, function() {
$rootScope.$digest();
}, root.isFocused(wid));
});
w.on('insightError', function() {
if (root.isFocused(wid)) {
$rootScope.reconnecting = true;
$rootScope.$digest();
}
});
w.on('newAddresses', function() {
// Nothing yet
});
// Disabled for now, does not seens to have much value for the user
// w.on('paymentACK', function(memo) {
// notification.success('Payment Acknowledged', memo);
// });
w.on('txProposalEvent', function(ev) {
if (root.isFocused(wid)) {
pendingTxsService.update();
}
// TODO aqui lo unico que cambia son los locked
// se puede optimizar
balanceService.update(w, function() {
$rootScope.$digest();
}, root.isFocused(wid));
root.notifyTxProposalEvent(w, ev);
$timeout(function() {
$rootScope.$digest();
});
});
w.on('addressBookUpdated', function(dontDigest) {
if (root.isFocused(wid)) {
if (!dontDigest) {
$rootScope.$digest();
}
}
});
w.on('connect', function(peerID) {
$rootScope.$digest();
});
// TODO?
// w.on('close', );
// w.on('locked',);
};
root.bind = function(iden) {
preconditions.checkArgument(_.isObject(iden));
copay.logger.debug('Binding profile...');
var self = this;
root.setupGlobalVariables(iden);
iden.on('newWallet', function(wid) {
var w = iden.getWalletById(wid);
copay.logger.debug('newWallet:',
w.getName(), wid, iden.getLastFocusedWalletId());
root.installWalletHandlers(w);
if (wid == iden.getLastFocusedWalletId()) {
copay.logger.debug('GOT Focused wallet:', w.getName());
root.setFocusedWallet(w, true);
go.walletHome();
}
// At the end (after all handlers are in place)...start the wallet.
w.netStart();
});
iden.on('noWallets', function() {
notification.warning('No Wallets', 'Your profile has no wallets. Create one here');
$rootScope.starting = false;
$location.path('/add');
$timeout(function() {
$rootScope.$digest();
}, 1);
});
iden.on('walletDeleted', function(wid) {
// do nothing. this is handled 'on sync' on controller.
});
iden.on('walletStorageError', function(wid, message) {
notification.error('Error storing wallet', message);
});
iden.on('closed', function() {
delete $rootScope['wallet'];
delete $rootScope['iden'];
applicationService.restart();
});
};
root.signout = function() {
if ($rootScope.iden) {
$rootScope.signingOut = true;
$rootScope.iden.close(function() { // Will trigger 'closed'
$timeout(function() {
$rootScope.signingOut = null;
}, 100);
}); // Will trigger 'closed'
}
};
root.createWallet = function(opts, cb) {
$rootScope.iden.createWallet(opts, cb);
};
root.importWallet = function(encryptedObj, pass, opts, cb) {
copay.Compatibility.importEncryptedWallet($rootScope.iden, encryptedObj, pass, opts, cb);
};
root.joinWallet = function(opts, cb) {
$rootScope.iden.joinWallet(opts, function(err, w) {
return cb(err);
});
};
root.importProfile = function(str, password, cb) {
copay.Identity.importFromEncryptedFullJson(str, password, {
pluginManager: pluginManager.getInstance(config),
network: config.network,
networkName: config.networkName,
walletDefaults: config.wallet,
passphraseConfig: config.passphraseConfig,
}, function(err, iden, walletObjs) {
if (err) return cb(err);
root.bind(iden);
iden.importMultipleWalletsFromObj(walletObjs);
return cb();
});
};
return root;
});

View File

@ -1,9 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('localstorageService', function($rootScope) {
var LS = require('../js/plugins/LocalStorage');
var ls = new LS();
return ls;
});

View File

@ -1,51 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('pendingTxsService', function($rootScope, $filter, rateService) {
var root = {};
root.setAlternativeAmount = function(w, tx, cb) {
var alternativeIsoCode = w.settings.alternativeIsoCode;
rateService.whenAvailable(function() {
_.each(tx.outs, function(out) {
var valueSat = out.valueSat * w.settings.unitToSatoshi;
out.alternativeAmount = $filter('noFractionNumber')(
rateService.toFiat(valueSat, alternativeIsoCode), 2);
out.alternativeIsoCode = alternativeIsoCode;
});
if (cb) return cb(tx);
});
};
root.getDecoratedTxProposals = function(w) {
var txps = w.getPendingTxProposals();
_.each(txps, function(tx) {
root.setAlternativeAmount(w, tx);
if (tx.outs) {
_.each(tx.outs, function(out) {
out.valueSat = out.value;
out.value = $filter('noFractionNumber')(out.value);
});
}
});
return txps;
};
/**
* @desc adds 2 fields to wallet: pendingTxProposalsCountForUs, pendingTxProposals.
*
* @param w wallet
*/
root.update = function(w) {
var w = $rootScope.wallet;
if (!w) return;
//pendingTxCount
var ret = w.getPendingTxProposalsCount();
w.pendingTxProposalsCountForUs = ret.pendingForUs;
w.pendingTxProposals = root.getDecoratedTxProposals(w);
};
return root;
});

View File

@ -1,115 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('pinService', function($rootScope, $timeout, localstorageService) {
var KEY = 'pinDATA';
var SALT = '4gllotIKguqi0EkIslC0';
var ITER = 5000;
var ls = localstorageService;
var root = {};
var _firstpin;
root.check = function(cb) {
ls.getItem(KEY, function(err, value) {
return cb(err, value ? true : false);
});
};
root.get = function(pin, cb) {
ls.getItem(KEY, function(err, value) {
if (!value) return cb(null);
var enc = value;
var data = copay.crypto.decrypt('' + parseInt(pin), enc);
var err = new Error('Could not decrypt');
if (data) {
var obj;
try {
obj = JSON.parse(data);
err = null;
} catch (e) {};
}
return cb(err, obj);
});
};
root.save = function(pin, email, password, cb) {
var credentials = {
email: email,
password: password,
};
var enc = copay.crypto.encrypt('' + parseInt(pin), credentials, SALT, ITER);
ls.setItem(KEY, enc, function(err) {
return cb(err);
});
};
root.clear = function(cb) {
ls.removeItem(KEY, cb);
};
root.clearPin = function(scope) {
scope.digits = [];
scope.defined = [];
};
root.pressPin = function(scope, digit, skipOpenWithPin) {
scope.error = null;
scope.digits.push(digit);
scope.defined.push(true);
if (scope.digits.length == 4) {
var pin = scope.digits.join('');
if (!$rootScope.hasPin) {
if (!_firstpin) {
_firstpin = pin;
scope.askForPin = 2;
$timeout(function() {
scope.clear();
}, 100);
return;
}
else {
if (pin === _firstpin) {
_firstpin = null;
scope.askForPin = null;
scope.createPin(pin);
return;
}
else {
_firstpin = null;
scope.askForPin = 1;
$timeout(function() {
scope.clear();
scope.error = 'Entered PINs were not equal. Try again';
$timeout(function() {
scope.error = null;
}, 2000);
}, 100);
return;
}
}
}
if (!skipOpenWithPin) {
scope.openWithPin(pin);
}
}
};
root.skipPin = function(scope, creatingProfile) {
if (!$rootScope.hasPin) {
if (!creatingProfile) {
scope.openWallets();
}
else {
scope.createDefaultWallet()
}
}
else {
scope.pinLogout();
}
};
return root;
});

View File

@ -1,8 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('rateService', function(request) {
var cfg = _.extend(config.rates, {
request: request
});
return copay.RateService.singleton(cfg);
});

View File

@ -1,6 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('request', function() {
return require('request');
});

View File

@ -1,36 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('txStatus', function($modal) {
var root = {};
root.notify = function(status) {
var msg;
if (status == copay.Wallet.TX_BROADCASTED)
msg = 'Transaction broadcasted';
else if (status == copay.Wallet.TX_PROPOSAL_SENT)
msg = 'Transaction proposal created';
else if (status == copay.Wallet.TX_SIGNED)
msg = 'Transaction proposal signed';
else if (status == copay.Wallet.TX_REJECTED)
msg = 'Transaction was rejected';
if (msg)
root.openModal(msg);
};
root.openModal = function(statusStr) {
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.statusStr = statusStr;
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};
$modal.open({
templateUrl: 'views/modals/tx-status.html',
windowClass: 'tiny',
controller: ModalInstanceCtrl,
});
};
return root;
});

View File

@ -1,122 +0,0 @@
/*
** copay-shell integration
*/
(function() {
/*
** This is a monkey patch for when Copay is running from
** within Copay-Shell (atom-shell). Since the renderer (the frontend)
** receives context from Node.js, we get a `module.exports` contruct
** available to us. Because of this, some libs (specifically Moment.js)
** attempt to assume their CommonJS form and bind to this. This causes
** there to be no references in the window to these libs, so let's trick
** the renderer into thinking that we are _not_ in a CommonJS environment.
*/
if (typeof module !== 'undefined') module = {
exports: false
};
// are we running in copay shell?
if (window.process && process.type === 'renderer') {
window.cshell = initCopayShellBindings();
} else {
return;
}
function controller(name) {
return angular.element(
document.querySelectorAll(
'[ng-controller="' + name + '"], [data-ng-controller="' + name + '"]'
)
).scope();
};
function needsWalletLogin(ipc) {
ipc.send('alert', 'info', 'Please select a wallet.');
};
function initCopayShellBindings() {
var ipc = require('ipc');
var clipb = require('clipboard');
// atom shell forces to implement the clipboard (on osx) on our own - thanks obama.
Mousetrap.stopCallback = function() {
return false
};
Mousetrap.bind('command+c', function(e) {
clipb.writeText(window.getSelection().toString());
});
Mousetrap.bind('command+v', function(e) {
if (document.activeElement) {
document.activeElement.value = clipb.readText();
document.activeElement.dispatchEvent(new Event('change'));
}
});
// handle messages
ipc.on('address:create', function(data) {
location.href = '#/addresses';
var ctrl = controller('AddressesController');
if (!ctrl) return needsWalletLogin(ipc);
ctrl.newAddr();
});
ipc.on('transactions:send', function(data) {
location.href = '#/send';
var ctrl = controller('SendController');
if (!ctrl) return needsWalletLogin(ipc);
});
ipc.on('transactions:all', function(data) {
location.href = '#/transactions';
var ctrl = controller('TransactionsController');
if (!ctrl) return needsWalletLogin(ipc);
ctrl.show();
});
ipc.on('transactions:pending', function(data) {
location.href = '#/transactions';
var ctrl = controller('TransactionsController');
if (!ctrl) return needsWalletLogin(ipc);
ctrl.show(true);
});
ipc.on('backup:download', function(data) {
location.href = '#/backup';
var ctrl = controller('BackupController');
if (!ctrl) return needsWalletLogin(ipc);
ctrl.download();
});
ipc.on('backup:email', function(data) {
location.href = '#/backup';
var ctrl = controller('BackupController');
if (!ctrl) return needsWalletLogin(ipc);
ctrl.openModal();
});
ipc.on('backup:import:data', function(data) {
location.href = '#/import';
var ctrl = controller('ImportController');
if (!ctrl) return;
ctrl.backupText = data;
ctrl.openPasteArea();
ctrl.$apply();
});
ipc.on('backup:import', function(data) {
location.href = '#/import';
});
// let the shell know when an error occurs
window.onerror = function(err) {
ipc.send('error', err);
};
return ipc;
};
})();

View File

@ -1,79 +0,0 @@
var preconditions = require('preconditions').singleton();
module.exports = {
request: function(options, callback) {
preconditions.checkArgument(_.isObject(options));
options.method = options.method || 'GET';
options.headers = options.headers || {};
var ret = {
success: function(cb) {
this._success = cb;
return this;
},
error: function(cb) {
this._error = cb;
return this;
},
_success: function() {;
},
_error: function(_, err) {
console.trace(err);
throw err;
}
};
var method = (options.method || 'GET').toUpperCase();
var url = options.url;
var req = options;
req.headers = req.headers || {};
req.body = req.body || req.data || '';
var xhr = options.xhr || new XMLHttpRequest();
xhr.open(method, url, true);
Object.keys(req.headers).forEach(function(key) {
var val = req.headers[key];
if (key === 'Content-Length') return;
if (key === 'Content-Transfer-Encoding') return;
xhr.setRequestHeader(key, val);
});
if (req.responseType) {
xhr.responseType = req.responseType;
}
xhr.onload = function(event) {
var response = xhr.response;
var buf = new Uint8Array(response);
var headers = {};
(xhr.getAllResponseHeaders() || '').replace(
/(?:\r?\n|^)([^:\r\n]+): *([^\r\n]+)/g,
function($0, $1, $2) {
headers[$1.toLowerCase()] = $2;
}
);
return ret._success(buf, xhr.status, headers, options);
};
xhr.onerror = function(event) {
var status;
if (xhr.status === 0 || !xhr.statusText) {
status = 'HTTP Request Error: This endpoint likely does not support cross-origin requests.';
} else {
status = xhr.statusText;
}
return ret._error(null, status, null, options);
};
if (req.body) {
xhr.send(req.body);
} else {
xhr.send(null);
}
return ret;
},
};

View File

@ -1,83 +0,0 @@
/**
* Small module for some helpers that wrap sjcl with some good practices.
*/
var sjcl = require('sjcl');
var _ = require('lodash');
var log = require('../util/log.js');
var config = require('../../config');
var defaultSalt = (config && config.passphraseConfig && config.passphraseConfig.storageSalt) || 'mjuBtGybi/4=';
var defaultIterations = (config && config.passphraseConfig && config.passphraseConfig.iterations) || 1000;
module.exports = {
/**
* @param {string} password
* @param {string} salt - base64 encoded, defaults to 'mjuBtGybi/4='
* @param {number} iterations - defaults to 100
* @param {number} length - bits, defaults to 512 bits
* @returns {string} base64 encoded pbkdf2 derivation using sha1 for hmac
*/
kdf: function(password, salt, iterations, length) {
return sjcl.codec.base64.fromBits(
this.kdfbinary(password, salt, iterations, length)
);
},
/**
* @param {string} key
* @param {string} data
* @return {string} base64 encoded hmac
*/
hmac: function(key, data) {
return sjcl.codec.base64.fromBits(
new sjcl.misc.hmac(key, sjcl.hash.sha256).encrypt(data)
);
},
/**
* @param {string} password
* @param {string} salt - base64 encoded, defaults to 'mjuBtGybi/4='
* @param {number} iterations - defaults to 100
* @param {number} length - bits, defaults to 512 bits
* @returns {string} base64 encoded pbkdf2 derivation using sha1 for hmac
*/
kdfbinary: function(password, salt, iterations, length) {
iterations = iterations || defaultIterations;
length = length || 512;
salt = sjcl.codec.base64.toBits(salt || defaultSalt);
var hash = sjcl.hash.sha256.hash(sjcl.hash.sha256.hash(password));
var prff = function(key) {
return new sjcl.misc.hmac(hash, sjcl.hash.sha1);
};
return sjcl.misc.pbkdf2(hash, salt, iterations, length, prff);
},
/**
* Encrypts symmetrically using a passphrase
*/
encrypt: function(key, message, salt, iter) {
if (!_.isString(message)) {
message = JSON.stringify(message);
}
sjcl.json.defaults.salt = salt || defaultSalt;
sjcl.json.defaults.iter = iter || defaultIterations;
return sjcl.encrypt(key, message);
},
/**
* Decrypts symmetrically using a passphrase
*/
decrypt: function(key, sjclEncryptedJson) {
var output = {};
try {
return sjcl.decrypt(key, sjclEncryptedJson);
} catch (e) {
log.debug('Decryption failed due to error: ' + e.message);
return null;
}
}
};

View File

@ -1,95 +0,0 @@
/**
* Small module for exporting data to CSV.
*/
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
var moment = require('moment');
var logger = require('../util/log.js');
var config = require('../../config');
var COL_DELIMITER = ',';
var ROW_DELIMITER = '\r\n';
function getValue(obj, property) {
if (_.isFunction(property)) {
try {
return property(obj);
} catch (err) {
if (_.isString(err)) return err;
return undefined;
}
}
if (!_.isObject(obj)) return undefined;
return obj.hasOwnProperty(property) ? obj[property] : undefined;
};
function formatValue(value, type, format) {
if (_.isUndefined(value) || _.isNull(value)) return '';
var r;
switch (type) {
default:
case 'string':
r = value.toString();
r.replace('"', '\\"');
break;
case 'date':
r = moment(value).format(format);
break;
case 'number':
r = value.toString();
break;
}
// escape when commas in values
if (r.indexOf(',') !== -1) {
r = '"' + r + '"';
}
return r;
};
function getHeader(descriptor) {
return _.map(descriptor.columns, function (col) {
return col.label || (_.isString(col.property) ? col.property : '') || '';
});
};
function processDataRow(data, descriptor) {
return _.map(descriptor.columns, function (col) {
var value = getValue(data, col.property);
var formatted = formatValue(value, col.type, col.format);
return formatted;
});
};
/**
* @desc Convert json object to csv based on a descriptor
*
* @param {array} data - the array of json objects to convert to csv
* @param {object} descriptor - an object that parameterizes the conversion
* @param {function} cb - called with the resulting csv
*/
module.exports.toCsv = function(data, descriptor, cb) {
preconditions.shouldBeArray(data);
preconditions.shouldBeObject(descriptor);
preconditions.shouldBeArray(descriptor.columns);
preconditions.shouldBeFunction(cb);
var colDelimiter = descriptor.colDelimiter || COL_DELIMITER;
var rowDelimiter = descriptor.rowDelimiter || ROW_DELIMITER;
var rows = _.map(data, function (dataRow) {
return processDataRow(dataRow, descriptor);
});
var header = getHeader(descriptor);
rows.unshift(header);
var csv = _.reduce(rows, function (memo, row) {
return memo + row.join(colDelimiter) + rowDelimiter;
}, '');
return cb(null, csv);
};

View File

@ -1,150 +0,0 @@
var config = config || require('../../config');
var _ = require('lodash');
var ls;
try {
var LS = require('../js/plugins/LocalStorage');
ls = new LS();
} catch (e) {};
/**
* @desc
* A simple logger that wraps the <tt>console.log</tt> methods when available.
*
* Usage:
* <pre>
* log = new Logger('copay');
* log.setLevel('info');
* log.debug('Message!'); // won't show
* log.setLevel('debug');
* log.debug('Message!', 1); // will show '[debug] copay: Message!, 1'
* </pre>
*
* @param {string} name - a name for the logger. This will show up on every log call
* @constructor
*/
var Logger = function(name) {
this.name = name || 'log';
this.level = 2;
};
Logger.prototype.getLevels = function() {
return levels;
};
var levels = {
'debug': 0,
'info': 1,
'log': 2,
'warn': 3,
'error': 4,
'fatal': 5
};
_.each(levels, function(level, levelName) {
Logger.prototype[levelName] = function() {
if (level >= levels[this.level]) {
if (Error.stackTraceLimit && this.level == 'debug') {
var old = Error.stackTraceLimit;
Error.stackTraceLimit = 2;
var stack;
// this hack is to be compatible with IE11
try {
anerror();
} catch (e) {
stack = e.stack;
}
var lines = stack.split('\n');
var caller = lines[2];
caller = ':' + caller.substr(6);
Error.stackTraceLimit = old;
}
var str = '[' + levelName + (caller || '') + '] ' + arguments[0],
extraArgs,
extraArgs = [].slice.call(arguments, 1);
if (console[levelName]) {
extraArgs.unshift(str);
console[levelName].apply(console, extraArgs);
} else {
if (extraArgs.length) {
str += JSON.stringify(extraArgs);
}
console.log(str);
}
}
};
});
/**
* @desc
* Sets the level of a logger. A level can be any bewteen: 'debug', 'info', 'log',
* 'warn', 'error', and 'fatal'. That order matters: if a logger's level is set to
* 'warn', calling <tt>level.debug</tt> won't have any effect.
*
* @param {number} level - the name of the logging level
*/
Logger.prototype.setLevel = function(level) {
this.level = level;
};
/**
* @class Logger
* @method debug
* @desc Log messages at the debug level.
* @param {*} args - the arguments to be logged.
*/
/**
* @class Logger
* @method info
* @desc Log messages at the info level.
* @param {*} args - the arguments to be logged.
*/
/**
* @class Logger
* @method log
* @desc Log messages at an intermediary level called 'log'.
* @param {*} args - the arguments to be logged.
*/
/**
* @class Logger
* @method warn
* @desc Log messages at the warn level.
* @param {*} args - the arguments to be logged.
*/
/**
* @class Logger
* @method error
* @desc Log messages at the error level.
* @param {*} args - the arguments to be logged.
*/
/**
* @class Logger
* @method fatal
* @desc Log messages at the fatal level.
* @param {*} args - the arguments to be logged.
*/
var logger = new Logger('copay');
var error = new Error();
var logLevel = config.logLevel || 'info';
if (ls && ls.getItem) {
ls.getItem("config", function(err, value) {
if (err) return;
var localConfig = JSON.parse(value);
if (localConfig && localConfig.logLevel)
logLevel = localConfig.logLevel;
logger.setLevel(logLevel);
});
} else {
logger.setLevel(logLevel);
}
module.exports = logger;

View File

@ -1,118 +0,0 @@
// Karma configuration
// Generated on Fri Mar 21 2014 17:52:41 GMT-0300 (ART)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha', 'chai'],
// list of files / patterns to load in the browser
files: [
//Configs
'config.js',
'lib/angular/angular.min.js',
'lib/angular-mocks/angular-mocks.js',
'lib/moment/moment.js',
'lib/ng-idle/angular-idle.min.js',
'lib/angular-moment/angular-moment.js',
'lib/qrcode-generator/js/qrcode.js',
'lib/angular-qrcode/qrcode.js',
'lib/angular-route/angular-route.min.js',
'lib/angular-foundation/mm-foundation.min.js',
'lib/angular-foundation/mm-foundation-tpls.min.js',
'lib/angular-load/angular-load.min.js',
'lib/angular-gravatar/build/md5.min.js',
'lib/angular-gravatar/build/angular-gravatar.min.js',
'lib/angular-touch/angular-touch.min.js',
'lib/angular-gettext/dist/angular-gettext.min.js',
'lib/inherits/inherits.js',
'lib/lodash/dist/lodash.js',
'lib/file-saver/FileSaver.js',
'lib/socket.io-client/socket.io.js',
'lib/sjcl.js',
'lib/qrcode-decoder-js/lib/qrcode-decoder.min.js',
'lib/bitcore.js',
'js/copayBundle.js',
//App-specific Code
'js/app.js',
'js/routes.js',
'js/services/*.js',
'js/directives.js',
'js/filters.js',
'js/controllers/*.js',
'js/translations.js',
'js/init.js',
'test/mocks/FakeBlockchainSocket.js',
'test/mocha.conf.js',
//test files
'setup/karma.js',
'test/unit/**/*.js',
'test/*.js',
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'js/controllers/*.js': ['coverage']
},
coverageReporter: {
type: 'html',
dir: 'coverage/'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome', 'Firefox'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// if browser doesn't capture output in given timeout (ms), kill it
captureTimeout: 60000
});
};

View File

@ -1,34 +0,0 @@
#! /usr/bin/node
'use strict';
var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) {
sys.puts(stdout)
}
function isNumber(n) {
return !isNaN(parseInt(n)) && isFinite(n);
}
var args = process.argv.slice(2);
var n_str = args[0];
if (!isNumber(n_str)) {
console.log('Program requires one numeric argument for the amount of copayers');
process.exit(1);
}
var N = parseInt(n_str);
var DEFAULT_PORT = process.env.DEFAULT_PORT || 3000;
for (var i = 0; i < N; i++) {
var port = (i + DEFAULT_PORT);
console.log('Simulating copayer #' + (i + 1) + ' at http://localhost:' + port);
var command = 'PORT=' + port + ' npm start &'
exec(command, puts);
}

File diff suppressed because one or more lines are too long

View File

@ -1,58 +0,0 @@
"use strict";function q(a){throw a;}var r=void 0,s=!1;var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});
sjcl.cipher.aes=function(a){this.m[0][0][0]||this.H();var b,c,d,e,f=this.m[0][4],g=this.m[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid("invalid aes key size"));this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
255]]};
sjcl.cipher.aes.prototype={encrypt:function(a){return v(this,a,0)},decrypt:function(a){return v(this,a,1)},m:[[[],[],[],[],[]],[[],[],[],[],[]]],H:function(){var a=this.m[0],b=this.m[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[l=h[f]]];p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
function v(a,b,c){4!==b.length&&q(new sjcl.exception.invalid("invalid aes block size"));var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,u=[0,0,0,0];h=a.m[c];a=h[0];var t=h[1],x=h[2],y=h[3],z=h[4];for(m=0;m<n;m++)h=a[e>>>24]^t[f>>16&255]^x[g>>8&255]^y[b&255]^d[p],k=a[f>>>24]^t[g>>16&255]^x[b>>8&255]^y[e&255]^d[p+1],l=a[g>>>24]^t[b>>16&255]^x[e>>8&255]^y[f&255]^d[p+2],b=a[b>>>24]^t[e>>16&255]^x[f>>8&255]^y[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=0;4>
m;m++)u[c?3&-m:m]=z[e>>>24]<<24^z[f>>16&255]<<16^z[g>>8&255]<<8^z[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return u}
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.Q(a.slice(b/32),32-(b&31)).slice(1);return c===r?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.Q(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return s;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
c},Q:function(a,b,c,d){var e;e=0;for(d===r&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},n:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
sjcl.codec.base32={r:"0123456789abcdefghjkmnpqrstvwxyz",BITS:32,BASE:5,REMAINING:27,fromBits:function(a){var b=sjcl.codec.base32.BASE,c=sjcl.codec.base32.REMAINING,d="",e,f=0,g=sjcl.codec.base32.r,h=0,k=sjcl.bitArray.bitLength(a);for(e=0;d.length*b<=k;)d+=g.charAt((h^a[e]>>>f)>>>c),f<b?(h=a[e]<<b-f,f+=c,e++):(h<<=b,f-=b);return d},toBits:function(a){var b=sjcl.codec.base32.BITS,c=sjcl.codec.base32.BASE,d=sjcl.codec.base32.REMAINING,e=[],f,g=0,h=sjcl.codec.base32.r,k=0,l;for(f=0;f<a.length;f++)l=h.indexOf(a.charAt(f)),
0>l&&q(new sjcl.exception.invalid("this isn't base32!")),g>d?(g-=d,e.push(k^l>>>g),k=l<<b-g):(g+=c,k^=l<<b-g);g&56&&e.push(sjcl.bitArray.partial(g&56,k,1));return e}};
sjcl.codec.base64={r:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.r,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.r,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++)h=f.indexOf(a.charAt(d)),
0>h&&q(new sjcl.exception.invalid("this isn't base64!")),26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.H();a?(this.e=a.e.slice(0),this.d=a.d.slice(0),this.c=a.c):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.e=this.u.slice(0);this.d=[];this.c=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.d=sjcl.bitArray.concat(this.d,a);b=this.c;a=this.c=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.q(c.splice(0,16));return this},finalize:function(){var a,b=this.d,c=this.e,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.c/
4294967296));for(b.push(this.c|0);b.length;)this.q(b.splice(0,16));this.reset();return c},u:[],b:[],H:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.u[b]=a(Math.pow(c,0.5)));this.b[b]=a(Math.pow(c,1/3));b++}},q:function(a){var b,c,d=a.slice(0),e=this.e,f=this.b,g=e[0],h=e[1],k=e[2],l=e[3],n=e[4],m=e[5],p=e[6],u=e[7];for(a=0;64>a;a++)16>a?b=d[a]:(b=d[a+1&15],c=d[a+14&15],b=d[a&15]=(b>>>7^b>>>18^b>>>3^
b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0),b=b+u+(n>>>6^n>>>11^n>>>25^n<<26^n<<21^n<<7)+(p^n&(m^p))+f[a],u=p,p=m,m=n,n=l+b|0,l=k,k=h,h=g,g=b+(h&k^l&(h^k))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0;e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+k|0;e[3]=e[3]+l|0;e[4]=e[4]+n|0;e[5]=e[5]+m|0;e[6]=e[6]+p|0;e[7]=e[7]+u|0}};sjcl.hash.sha1=function(a){a?(this.e=a.e.slice(0),this.d=a.d.slice(0),this.c=a.c):this.reset()};sjcl.hash.sha1.hash=function(a){return(new sjcl.hash.sha1).update(a).finalize()};
sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.e=this.u.slice(0);this.d=[];this.c=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.d=sjcl.bitArray.concat(this.d,a);b=this.c;a=this.c=b+sjcl.bitArray.bitLength(a);for(b=this.blockSize+b&-this.blockSize;b<=a;b+=this.blockSize)this.q(c.splice(0,16));return this},finalize:function(){var a,b=this.d,c=this.e,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);
b.push(Math.floor(this.c/0x100000000));for(b.push(this.c|0);b.length;)this.q(b.splice(0,16));this.reset();return c},u:[1732584193,4023233417,2562383102,271733878,3285377520],b:[1518500249,1859775393,2400959708,3395469782],q:function(a){var b,c,d,e,f,g,h=a.slice(0),k=this.e;c=k[0];d=k[1];e=k[2];f=k[3];g=k[4];for(a=0;79>=a;a++)16<=a&&(h[a]=(h[a-3]^h[a-8]^h[a-14]^h[a-16])<<1|(h[a-3]^h[a-8]^h[a-14]^h[a-16])>>>31),b=19>=a?d&e|~d&f:39>=a?d^e^f:59>=a?d&e|d&f|e&f:79>=a?d^e^f:r,b=(c<<5|c>>>27)+b+g+h[a]+this.b[Math.floor(a/
20)]|0,g=f,f=e,e=d<<30|d>>>2,d=c,c=b;k[0]=k[0]+c|0;k[1]=k[1]+d|0;k[2]=k[2]+e|0;k[3]=k[3]+f|0;k[4]=k[4]+g|0}};
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];7>k&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.N(a,b,c,d,e,f);g=sjcl.mode.ccm.s(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,
h-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.s(a,k,c,l,e,b);a=sjcl.mode.ccm.N(a,k.data,c,d,e,b);f.equal(k.tag,a)||q(new sjcl.exception.corrupt("ccm: tag doesn't match"));return k.data},N:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.n;e/=8;(e%2||4>e||16<e)&&q(new sjcl.exception.invalid("ccm: invalid tag length"));(0xffffffff<d.length||0xffffffff<b.length)&&q(new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"));
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(k(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(k(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,8*e)},s:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.n;var k=b.length,l=h.bitLength(b);c=h.concat([h.partial(8,
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));var g,h=sjcl.mode.ocb2.K,k=sjcl.bitArray,l=k.n,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));d.length&&
(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));e=e||64;var g=sjcl.mode.ocb2.K,h=sjcl.bitArray,k=h.n,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,u=sjcl.bitArray.bitLength(b)-e,t=[];d=d||[];for(c=0;c+4<u/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),t=t.concat(m),n=g(n);p=u-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,0,0]));
l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));h.equal(h.clamp(l,e),h.bitSlice(b,u))||q(new sjcl.exception.corrupt("ocb: tag doesn't match"));return t.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.K,e=sjcl.bitArray,f=e.n,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,
d(h))),g))},K:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.s(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.s(s,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt("gcm: tag doesn't match"));return a.data},$:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.n;e=[0,0,0,0];f=b.slice(0);
for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.$(b,a);return b},s:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,u,t=sjcl.bitArray;m=c.length;p=t.bitLength(c);u=t.bitLength(d);h=t.bitLength(e);g=b.encrypt([0,
0,0,0]);96===h?(e=e.slice(0),e=t.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=t.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(u/0x100000000),u&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);d[0]^=k[0];
d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:t.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.O=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.p=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.p[0].update(c[0]);this.p[1].update(c[1]);this.J=new b(this.p[0])};
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){this.R&&q(new sjcl.exception.invalid("encrypt on already updated hmac called!"));this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.J=new this.O(this.p[0]);this.R=s};sjcl.misc.hmac.prototype.update=function(a){this.R=!0;this.J.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.J.finalize(),a=(new this.O(this.p[1])).update(a).finalize();this.reset();return a};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;(0>d||0>c)&&q(sjcl.exception.invalid("invalid params to pbkdf2"));"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
sjcl.prng=function(a){this.f=[new sjcl.hash.sha256];this.k=[0];this.I=0;this.w={};this.G=0;this.M={};this.P=this.g=this.l=this.X=0;this.b=[0,0,0,0,0,0,0,0];this.i=[0,0,0,0];this.D=r;this.F=a;this.t=s;this.C={progress:{},seeded:{}};this.o=this.W=0;this.A=1;this.B=2;this.T=0x10000;this.L=[0,48,64,96,128,192,0x100,384,512,768,1024];this.U=3E4;this.S=80};
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;d===this.o&&q(new sjcl.exception.notReady("generator isn't seeded"));if(d&this.B){d=!(d&this.A);e=[];var f=0,g;this.P=e[0]=(new Date).valueOf()+this.U;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.f.length&&!(e=e.concat(this.f[g].finalize()),f+=this.k[g],this.k[g]=0,!d&&this.I&1<<g);g++);this.I>=1<<this.f.length&&(this.f.push(new sjcl.hash.sha256),this.k.push(0));this.g-=f;f>this.l&&(this.l=f);this.I++;
this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.D=new sjcl.cipher.aes(this.b);for(d=0;4>d&&!(this.i[d]=this.i[d]+1|0,this.i[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.T&&w(this),e=A(this),c.push(e[0],e[1],e[2],e[3]);w(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b&&q("Setting paranoia=0 will ruin your security; use it only for testing");this.F=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),
g=this.w[c],h=this.isReady(),k=0;d=this.M[c];d===r&&(d=this.M[c]=this.X++);g===r&&(g=this.w[c]=0);this.w[c]=(this.w[c]+1)%this.f.length;switch(typeof a){case "number":b===r&&(b=1);this.f[g].update([d,this.G++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{"[object Array]"!==c&&(k=1);for(c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&(k=1)}if(!k){if(b===r)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,
e>>>=1;this.f[g].update([d,this.G++,2,b,f,a.length].concat(a))}break;case "string":b===r&&(b=a.length);this.f[g].update([d,this.G++,3,b,f,a.length]);this.f[g].update(a);break;default:k=1}k&&q(new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"));this.k[g]+=b;this.g+=b;h===this.o&&(this.isReady()!==this.o&&B("seeded",Math.max(this.l,this.g)),B("progress",this.getProgress()))},isReady:function(a){a=this.L[a!==r?a:this.F];return this.l&&this.l>=a?this.k[0]>this.S&&
(new Date).valueOf()>this.P?this.B|this.A:this.A:this.g>=a?this.B|this.o:this.o},getProgress:function(a){a=this.L[a?a:this.F];return this.l>=a?1:this.g>a?1:this.g/a},startCollectors:function(){this.t||(this.a={loadTimeCollector:C(this,this.ba),mouseCollector:C(this,this.ca),keyboardCollector:C(this,this.aa),accelerometerCollector:C(this,this.V),touchCollector:C(this,this.ea)},window.addEventListener?(window.addEventListener("load",this.a.loadTimeCollector,s),window.addEventListener("mousemove",this.a.mouseCollector,
s),window.addEventListener("keypress",this.a.keyboardCollector,s),window.addEventListener("devicemotion",this.a.accelerometerCollector,s),window.addEventListener("touchmove",this.a.touchCollector,s)):document.attachEvent?(document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector)):q(new sjcl.exception.bug("can't attach event")),this.t=!0)},stopCollectors:function(){this.t&&(window.removeEventListener?
(window.removeEventListener("load",this.a.loadTimeCollector,s),window.removeEventListener("mousemove",this.a.mouseCollector,s),window.removeEventListener("keypress",this.a.keyboardCollector,s),window.removeEventListener("devicemotion",this.a.accelerometerCollector,s),window.removeEventListener("touchmove",this.a.touchCollector,s)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",this.a.mouseCollector),document.detachEvent("keypress",
this.a.keyboardCollector)),this.t=s)},addEventListener:function(a,b){this.C[a][this.W++]=b},removeEventListener:function(a,b){var c,d,e=this.C[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},aa:function(){D(1)},ca:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&sjcl.random.addEntropy([b,c],2,"mouse");D(0)},ea:function(a){a=a.touches[0]||a.changedTouches[0];sjcl.random.addEntropy([a.pageX||
a.clientX,a.pageY||a.clientY],1,"touch");D(0)},ba:function(){D(2)},V:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&sjcl.random.addEntropy(b,1,"accelerometer")}a&&sjcl.random.addEntropy(a,2,"accelerometer");D(0)}};function B(a,b){var c,d=sjcl.random.C[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}
function D(a){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?sjcl.random.addEntropy(window.performance.now(),a,"loadtime"):sjcl.random.addEntropy((new Date).valueOf(),a,"loadtime")}function w(a){a.b=A(a).concat(A(a));a.D=new sjcl.cipher.aes(a.b)}function A(a){for(var b=0;4>b&&!(a.i[b]=a.i[b]+1|0,a.i[b]);b++);return a.D.encrypt(a.i)}function C(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
a:try{var E,F,G,H;if(H="undefined"!==typeof module){var I;if(I=module.exports){var J;try{J=require("crypto")}catch(K){J=null}I=(F=J)&&F.randomBytes}H=I}if(H)E=F.randomBytes(128),E=new Uint32Array((new Uint8Array(E)).buffer),sjcl.random.addEntropy(E,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){G=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(G);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(G);
else break a;sjcl.random.addEntropy(G,1024,"crypto['getRandomValues']")}}catch(L){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(L))}
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},Z:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.h({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.h(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||4<
f.iv.length)&&q(new sjcl.exception.invalid("json encrypt: invalid parameters"));"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.h(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,
b,c,d){var e=sjcl.json,f=e.Z.apply(e,arguments);return e.encode(f)},Y:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.h(e.h(e.h({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)&&q(new sjcl.exception.invalid("json decrypt: invalid parameters"));
"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f=sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.h(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.Y(a,e.decode(b),c,d)},encode:function(a){var b,
c="{",d="";for(b in a)if(a.hasOwnProperty(b))switch(b.match(/^[a-z0-9]+$/i)||q(new sjcl.exception.invalid("json encode: invalid property name")),c+=d+'"'+b+'":',d=",",typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:q(new sjcl.exception.bug("json encode: unsupported type"))}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");a.match(/^\{.*\}$/)||q(new sjcl.exception.invalid("json decode: this isn't json!"));
a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++)(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i))||q(new sjcl.exception.invalid("json decode: this isn't json!")),d[3]?b[d[2]]=parseInt(d[3],10):d[4]?b[d[2]]=d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):d[5]&&(b[d[2]]="true"===d[5]);return b},h:function(a,b,c){a===r&&(a={});if(b===r)return a;for(var d in b)b.hasOwnProperty(d)&&(c&&(a[d]!==
r&&a[d]!==b[d])&&q(new sjcl.exception.invalid("required parameter overridden")),a[d]=b[d]);return a},ga:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},fa:function(a,b){var c={},d;for(d=0;d<b.length;d++)a[b[d]]!==r&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.da={};
sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.da,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===r?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};

View File

@ -7,7 +7,8 @@
"wallet",
"copay",
"multisignature",
"bitcoin"
"bitcoin",
"bitcore"
],
"main": "app.js",
"id": "jid1-x7bV5evAaI1P9Q",
@ -21,73 +22,34 @@
"url": "https://github.com/bitpay/copay/issues"
},
"dependencies": {
"browser-request": "git://github.com/matiu/browser-request.git#67200dd4ec133457fb7dc69f005540f92b543f0a",
"cordova": "^4.1.2",
"inherits": "^2.0.1",
"lodash": "^2.4.1",
"moment": "2.6.0",
"optimist": "^0.6.1",
"preconditions": "^1.0.7",
"querystring": "^0.2.0",
"request": "^2.40.0"
},
"scripts": {
"start": "node server.js",
"coverage": "./node_modules/.bin/istanbul cover -x lib/sjcl.js ./node_modules/.bin/_mocha -- --reporter spec test",
"test": "sh test/run.sh",
"dist": "node shell/scripts/dist.js",
"shell": "node shell/scripts/launch.js",
"setup-shell": "node shell/scripts/download-atom-shell.js",
"postinstall": "./node_modules/.bin/grunt"
},
"devDependencies": {
"angular-gravatar": "*",
"async": "^0.9.0",
"bitcore": "git://github.com/bitpay/bitcore.git#e20df2144926dbc20bd468d671e73f8e52bb70c1",
"blanket": "^1.1.6",
"browser-pack": "^2.0.1",
"browserify": "^3.32.1",
"buffertools": "^2.0.1",
"chai": "^1.9.1",
"cli-color": "^0.3.2",
"commander": "^2.1.0",
"coveralls": "^2.10.0",
"express": "^4.10.0",
"github-releases": "^0.2.0",
"express": "^4.11.2",
"fs": "0.0.2",
"grunt": "^0.4.5",
"grunt-angular-gettext": "^0.2.15",
"grunt-browserify": "^2.0.8",
"grunt-cli": "^0.1.13",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-copy": "^0.7.0",
"grunt-contrib-cssmin": "^0.10.0",
"grunt-contrib-uglify": "^0.5.1",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-cssmin": "^0.12.2",
"grunt-contrib-uglify": "^0.8.0",
"grunt-contrib-watch": "^0.5.3",
"grunt-exec": "*",
"grunt-jsdoc": "^0.5.7",
"grunt-exec": "^0.4.6",
"grunt-markdown": "^0.5.0",
"grunt-mocha-test": "^0.8.2",
"grunt-release": "^0.7.0",
"istanbul": "^0.2.10",
"karma": "^0.12.9",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^0.1.3",
"shelljs": "^0.3.0"
},
"scripts": {
"start": "node app.js",
"test": "./node_modules/.bin/grunt test-coveralls"
},
"devDependencies": {
"angular": "^1.3.14",
"angular-mocks": "^1.3.14",
"grunt-karma": "^0.10.1",
"grunt-karma-coveralls": "^2.5.3",
"karma": "^0.12.31",
"karma-cli": "0.0.4",
"karma-coverage": "^0.2.7",
"karma-firefox-launcher": "^0.1",
"karma-mocha": "^0.1.9",
"karma-phantomjs-launcher": "^0.1.4",
"karma-sinon": "^1.0.3",
"load-grunt-tasks": "^0.6.0",
"mocha": "^1.18.2",
"mocha-lcov-reporter": "^0.0.1",
"mock-fs": "^2.3.1",
"node-cryptojs-aes": "^0.4.0",
"request": "^2.40.0",
"shelljs": "^0.3.0",
"sinon": "^1.10.3",
"sjcl": "*",
"socket.io-client": "^1.0.6",
"travis-cov": "^0.2.5",
"uglifyify": "^1.2.3"
"karma-jasmine": "^0.3.5",
"karma-phantomjs-launcher": "^0.1.4"
}
}

View File

@ -1,32 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Copay</title>
<style>
body { background-color: #2C3E50; }
a {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
background-color: #008cba;
color: #fff;
display: block;
font-family: "Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;
margin: 20px auto;
opacity: .8;
outline: none;
padding: 10px;
text-decoration: none;
text-align: center;
width: 200px;
}
a:hover { opacity: 1; }
</style>
</head>
<body>
<a href="index.html" target="_blank">Open wallet</a>
<a href="index.html#!/settings" target="_blank">Settings</a>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More