├── .bowerrc ├── .gitignore ├── .jshintrc ├── .npmignore ├── Gruntfile.js ├── README.md ├── bitcore-node-zcash ├── index.js └── service.js ├── bower.json ├── package.json ├── po ├── de_DE.po ├── es.po └── ja.po └── public ├── css └── main.min.css ├── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf └── glyphicons-halflings-regular.woff ├── img ├── .gitignore ├── angularjs.png ├── icons │ ├── copy.png │ └── favicon.ico ├── leveldb.png ├── loading.gif ├── logo.svg └── nodejs.png ├── index.html ├── js ├── angularjs-all.min.js ├── main.min.js └── vendors.min.js ├── lib └── zeroclipboard │ └── ZeroClipboard.swf ├── robots.txt ├── sound └── transaction.mp3 ├── src ├── css │ └── common.css └── js │ ├── app.js │ ├── config.js │ ├── controllers │ ├── address.js │ ├── blocks.js │ ├── charts.js │ ├── connection.js │ ├── currency.js │ ├── footer.js │ ├── header.js │ ├── index.js │ ├── messages.js │ ├── scanner.js │ ├── search.js │ ├── status.js │ └── transactions.js │ ├── directives.js │ ├── filters.js │ ├── init.js │ ├── ios-imagefile-megapixel │ └── megapix-image.js │ ├── jsqrcode │ ├── alignpat.js │ ├── bitmat.js │ ├── bmparser.js │ ├── datablock.js │ ├── databr.js │ ├── datamask.js │ ├── decoder.js │ ├── detector.js │ ├── errorlevel.js │ ├── findpat.js │ ├── formatinf.js │ ├── gf256.js │ ├── gf256poly.js │ ├── grid.js │ ├── qrcode.js │ ├── rsdecoder.js │ ├── test.html │ └── version.js │ ├── services │ ├── address.js │ ├── blocks.js │ ├── charts.js │ ├── currency.js │ ├── global.js │ ├── socket.js │ ├── status.js │ └── transactions.js │ └── translations.js └── views ├── 404.html ├── address.html ├── block.html ├── block_list.html ├── charts.html ├── dummy-translations.html ├── includes ├── connection.html ├── currency.html ├── header.html ├── infoStatus.html └── search.html ├── index.html ├── messages_verify.html ├── redirect.html ├── status.html ├── transaction.html ├── transaction ├── list.html └── tx.html └── transaction_sendraw.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "public/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # from https://github.com/github/gitignore/blob/master/Node.gitignore 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | *.swp 11 | tags 12 | pids 13 | logs 14 | results 15 | build 16 | 17 | node_modules 18 | 19 | # extras 20 | *.swp 21 | *.swo 22 | *~ 23 | .project 24 | peerdb.json 25 | 26 | npm-debug.log 27 | .nodemonignore 28 | 29 | .DS_Store 30 | public/lib/* 31 | !public/lib/zeroclipboard/ZeroClipboard.swf 32 | db/txs/* 33 | db/txs 34 | db/testnet/txs/* 35 | db/testnet/txs 36 | db/blocks/* 37 | db/blocks 38 | db/testnet/blocks/* 39 | db/testnet/blocks 40 | 41 | public/js/angularjs-all.js 42 | public/js/main.js 43 | public/js/vendors.js 44 | 45 | public/css/main.css 46 | 47 | README.html 48 | po/* 49 | !po/*.po 50 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, // Enable globals available when code is running inside of the NodeJS runtime environment. 3 | "browser": true, // Standard browser globals e.g. `window`, `document`. 4 | "esnext": true, // Allow ES.next specific features such as `const` and `let`. 5 | "bitwise": false, // Prohibit bitwise operators (&, |, ^, etc.). 6 | "camelcase": false, // Permit only camelcase for `var` and `object indexes`. 7 | "curly": false, // Require {} for every new block or scope. 8 | "eqeqeq": true, // Require triple equals i.e. `===`. 9 | "immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 10 | "latedef": true, // Prohibit variable use before definition. 11 | "newcap": true, // Require capitalization of all constructor functions e.g. `new F()`. 12 | "noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`. 13 | "quotmark": "single", // Define quotes to string values. 14 | "regexp": true, // Prohibit `.` and `[^...]` in regular expressions. 15 | "undef": true, // Require all non-global variables be declared before they are used. 16 | "unused": true, // Warn unused variables. 17 | "strict": true, // Require `use strict` pragma in every file. 18 | "trailing": true, // Prohibit trailing whitespaces. 19 | "smarttabs": false, // Suppresses warnings about mixed tabs and spaces 20 | "globals": { // Globals variables. 21 | "angular": true 22 | }, 23 | "predef": [ // Extra globals. 24 | "define", 25 | "require", 26 | "exports", 27 | "module", 28 | "describe", 29 | "before", 30 | "beforeEach", 31 | "after", 32 | "afterEach", 33 | "it", 34 | "inject", 35 | "$", 36 | "io", 37 | "app", 38 | "moment" 39 | ], 40 | "indent": false, // Specify indentation spacing 41 | "devel": true, // Allow development statements e.g. `console.log();`. 42 | "noempty": true // Prohibit use of empty blocks. 43 | } 44 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | tags 11 | pids 12 | logs 13 | results 14 | build 15 | 16 | node_modules 17 | 18 | # extras 19 | *.swp 20 | *.swo 21 | *~ 22 | .project 23 | peerdb.json 24 | 25 | npm-debug.log 26 | .nodemonignore 27 | 28 | .DS_Store 29 | db/txs/* 30 | db/txs 31 | db/testnet/txs/* 32 | db/testnet/txs 33 | db/blocks/* 34 | db/blocks 35 | db/testnet/blocks/* 36 | db/testnet/blocks 37 | 38 | README.html 39 | k* 40 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | //Load NPM tasks 6 | grunt.loadNpmTasks('grunt-contrib-uglify'); 7 | grunt.loadNpmTasks('grunt-contrib-concat'); 8 | grunt.loadNpmTasks('grunt-contrib-watch'); 9 | grunt.loadNpmTasks('grunt-css'); 10 | grunt.loadNpmTasks('grunt-markdown'); 11 | grunt.loadNpmTasks('grunt-macreload'); 12 | grunt.loadNpmTasks('grunt-angular-gettext'); 13 | 14 | // Project Configuration 15 | grunt.initConfig({ 16 | pkg: grunt.file.readJSON('package.json'), 17 | concat: { 18 | options: { 19 | process: function(src, filepath) { 20 | if (filepath.substr(filepath.length - 2) === 'js') { 21 | return '// Source: ' + filepath + '\n' + 22 | src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); 23 | } else { 24 | return src; 25 | } 26 | } 27 | }, 28 | vendors: { 29 | src: ['public/src/js/ios-imagefile-megapixel/megapix-image.js', 'public/lib/qrcode-generator/js/qrcode.js', 'public/src/js/jsqrcode/grid.js', 'public/src/js/jsqrcode/version.js', 'public/src/js/jsqrcode/detector.js', 'public/src/js/jsqrcode/formatinf.js', 'public/src/js/jsqrcode/errorlevel.js', 'public/src/js/jsqrcode/bitmat.js', 'public/src/js/jsqrcode/datablock.js', 'public/src/js/jsqrcode/bmparser.js', 'public/src/js/jsqrcode/datamask.js', 'public/src/js/jsqrcode/rsdecoder.js', 'public/src/js/jsqrcode/gf256poly.js', 'public/src/js/jsqrcode/gf256.js', 'public/src/js/jsqrcode/decoder.js', 'public/src/js/jsqrcode/qrcode.js', 'public/src/js/jsqrcode/findpat.js', 'public/src/js/jsqrcode/alignpat.js', 'public/src/js/jsqrcode/databr.js', 'public/lib/moment/min/moment.min.js', 'public/lib/moment/lang/es.js', 'public/lib/zeroclipboard/ZeroClipboard.min.js', 30 | 'public/lib/c3/c3.min.js', 31 | 'public/lib/d3/d3.min.js' 32 | ], 33 | dest: 'public/js/vendors.js' 34 | }, 35 | angular: { 36 | src: ['public/lib/angular/angular.min.js', 'public/lib/angular-resource/angular-resource.min.js', 'public/lib/angular-route/angular-route.min.js', 'public/lib/angular-qrcode/qrcode.js', 'public/lib/angular-animate/angular-animate.min.js', 'public/lib/angular-bootstrap/ui-bootstrap.js', 'public/lib/angular-bootstrap/ui-bootstrap-tpls.js', 'public/lib/angular-ui-utils/ui-utils.min.js', 'public/lib/ngprogress/build/ngProgress.min.js', 'public/lib/angular-gettext/dist/angular-gettext.min.js', 'public/lib/angular-moment/angular-moment.min.js'], 37 | dest: 'public/js/angularjs-all.js' 38 | }, 39 | main: { 40 | src: ['public/src/js/app.js', 'public/src/js/controllers/*.js', 'public/src/js/services/*.js', 'public/src/js/directives.js', 'public/src/js/filters.js', 'public/src/js/config.js', 'public/src/js/init.js', 'public/src/js/translations.js'], 41 | dest: 'public/js/main.js' 42 | }, 43 | css: { 44 | src: [ 45 | 'public/lib/bootstrap/dist/css/bootstrap.min.css', 46 | 'public/lib/c3/c3.min.css', 47 | 'public/src/css/**/*.css' 48 | ], 49 | dest: 'public/css/main.css' 50 | } 51 | }, 52 | uglify: { 53 | options: { 54 | banner: '/*! <%= pkg.name %> <%= pkg.version %> */\n', 55 | mangle: false 56 | }, 57 | vendors: { 58 | src: 'public/js/vendors.js', 59 | dest: 'public/js/vendors.min.js' 60 | }, 61 | angular: { 62 | src: 'public/js/angularjs-all.js', 63 | dest: 'public/js/angularjs-all.min.js' 64 | }, 65 | main: { 66 | src: 'public/js/main.js', 67 | dest: 'public/js/main.min.js' 68 | } 69 | }, 70 | cssmin: { 71 | css: { 72 | src: 'public/css/main.css', 73 | dest: 'public/css/main.min.css' 74 | } 75 | }, 76 | markdown: { 77 | all: { 78 | files: [ 79 | { 80 | expand: true, 81 | src: 'README.md', 82 | dest: '.', 83 | ext: '.html' 84 | } 85 | ] 86 | } 87 | }, 88 | macreload: { 89 | chrome: { 90 | browser: 'chrome', 91 | editor: 'macvim' 92 | } 93 | }, 94 | watch: { 95 | main: { 96 | files: ['public/src/js/**/*.js'], 97 | tasks: ['concat:main', 'uglify:main'], 98 | }, 99 | css: { 100 | files: ['public/src/css/**/*.css'], 101 | tasks: ['concat:css', 'cssmin'], 102 | }, 103 | }, 104 | nggettext_extract: { 105 | pot: { 106 | files: { 107 | 'po/template.pot': ['public/views/*.html', 'public/views/**/*.html'] 108 | } 109 | }, 110 | }, 111 | nggettext_compile: { 112 | all: { 113 | options: { 114 | module: 'insight' 115 | }, 116 | files: { 117 | 'public/src/js/translations.js': ['po/*.po'] 118 | } 119 | }, 120 | } 121 | }); 122 | 123 | //Making grunt default to force in order not to break the project. 124 | grunt.option('force', true); 125 | 126 | //Default task(s). 127 | grunt.registerTask('default', ['watch']); 128 | 129 | //Update .pot file 130 | grunt.registerTask('translate', ['nggettext_extract']); 131 | 132 | //Compile task (concat + minify) 133 | grunt.registerTask('compile', ['nggettext_compile', 'concat', 'uglify', 'cssmin']); 134 | 135 | 136 | }; 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Insight UI 2 | 3 | A Bitcoin blockchain explorer web application service for [Bitcore Node](https://github.com/bitpay/bitcore-node) using the [Insight API](https://github.com/zcash-hackworks/insight-api-zcash). 4 | 5 | ## Quick Start 6 | 7 | Please see the guide at [https://bitcore.io/guides/full-node](https://bitcore.io/guides/full-node) for information about getting a block explorer running. This is only the front-end component of the block explorer, and is packaged together with all of the necessary components in [Bitcore](https://github.com/bitpay/bitcore). 8 | 9 | ## Getting Started 10 | 11 | To manually install all of the necessary components, you can run these commands: 12 | 13 | ```bash 14 | npm install -g bitcore-node 15 | bitcore-node create mynode 16 | cd mynode 17 | bitcore-node install insight-api 18 | bitcore-node install insight-ui 19 | bitcore-node start 20 | ``` 21 | 22 | Open a web browser to `http://localhost:3001/insight/` 23 | 24 | ## Development 25 | 26 | To run Insight UI locally in development mode: 27 | 28 | Install bower dependencies: 29 | 30 | ``` 31 | $ bower install 32 | ``` 33 | 34 | To compile and minify the web application's assets: 35 | 36 | ``` 37 | $ grunt compile 38 | ``` 39 | 40 | There is a convenient Gruntfile.js for automation during editing the code 41 | 42 | ``` 43 | $ grunt 44 | ``` 45 | 46 | ## Multilanguage support 47 | 48 | Insight UI uses [angular-gettext](http://angular-gettext.rocketeer.be) for multilanguage support. 49 | 50 | To enable a text to be translated, add the ***translate*** directive to html tags. See more details [here](http://angular-gettext.rocketeer.be/dev-guide/annotate/). Then, run: 51 | 52 | ``` 53 | grunt compile 54 | ``` 55 | 56 | This action will create a template.pot file in ***po/*** folder. You can open it with some PO editor ([Poedit](http://poedit.net)). Read this [guide](http://angular-gettext.rocketeer.be/dev-guide/translate/) to learn how to edit/update/import PO files from a generated POT file. PO file will be generated inside po/ folder. 57 | 58 | If you make new changes, simply run **grunt compile** again to generate a new .pot template and the angular javascript ***js/translations.js***. Then (if use Poedit), open .po file and choose ***update from POT File*** from **Catalog** menu. 59 | 60 | Finally changes your default language from ***public/src/js/config*** 61 | 62 | ``` 63 | gettextCatalog.currentLanguage = 'es'; 64 | ``` 65 | 66 | This line will take a look at any *.po files inside ***po/*** folder, e.g. 67 | **po/es.po**, **po/nl.po**. After any change do not forget to run ***grunt 68 | compile***. 69 | 70 | 71 | ## Note 72 | 73 | For more details about the [Insight API](https://github.com/zcash-hackworks/insight-api-zcash) configuration and end-points, go to [Insight API GitHub repository](https://github.com/zcash-hackworks/insight-api-zcash). 74 | 75 | ## Contribute 76 | 77 | Contributions and suggestions are welcomed at the [Insight UI GitHub repository](https://github.com/zcash-hackworks/insight-ui-zcash). 78 | 79 | 80 | ## License 81 | (The MIT License) 82 | 83 | Permission is hereby granted, free of charge, to any person obtaining 84 | a copy of this software and associated documentation files (the 85 | 'Software'), to deal in the Software without restriction, including 86 | without limitation the rights to use, copy, modify, merge, publish, 87 | distribute, sublicense, and/or sell copies of the Software, and to 88 | permit persons to whom the Software is furnished to do so, subject to 89 | the following conditions: 90 | 91 | The above copyright notice and this permission notice shall be 92 | included in all copies or substantial portions of the Software. 93 | 94 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 95 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 96 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 97 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 98 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 99 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 100 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 101 | -------------------------------------------------------------------------------- /bitcore-node-zcash/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BaseService = require('./service'); 4 | var inherits = require('util').inherits; 5 | var fs = require('fs'); 6 | 7 | var InsightUI = function(options) { 8 | BaseService.call(this, options); 9 | if (typeof options.apiPrefix !== 'undefined') { 10 | this.apiPrefix = options.apiPrefix; 11 | } else { 12 | this.apiPrefix = 'insight-api-zcash'; 13 | } 14 | if (typeof options.routePrefix !== 'undefined') { 15 | this.routePrefix = options.routePrefix; 16 | } else { 17 | this.routePrefix = 'insight'; 18 | } 19 | }; 20 | 21 | InsightUI.dependencies = ['insight-api-zcash']; 22 | 23 | inherits(InsightUI, BaseService); 24 | 25 | InsightUI.prototype.start = function(callback) { 26 | this.indexFile = this.filterIndexHTML(fs.readFileSync(__dirname + '/../public/index.html', {encoding: 'utf8'})); 27 | setImmediate(callback); 28 | }; 29 | 30 | InsightUI.prototype.getRoutePrefix = function() { 31 | return this.routePrefix; 32 | }; 33 | 34 | InsightUI.prototype.setupRoutes = function(app, express) { 35 | var self = this; 36 | 37 | app.use('/', function(req, res, next){ 38 | if (req.headers.accept && req.headers.accept.indexOf('text/html') !== -1 && 39 | req.headers["X-Requested-With"] !== 'XMLHttpRequest' 40 | ) { 41 | res.setHeader('Content-Type', 'text/html'); 42 | res.send(self.indexFile); 43 | } else { 44 | express.static(__dirname + '/../public')(req, res, next); 45 | } 46 | }); 47 | }; 48 | 49 | InsightUI.prototype.filterIndexHTML = function(data) { 50 | var transformed = data 51 | .replace(/apiPrefix = '\/api'/, "apiPrefix = '/" + this.apiPrefix + "'"); 52 | 53 | if (this.routePrefix) { 54 | transformed = transformed.replace(/insight is an open-source Zcash blockchain explorer with complete REST " 27 | "and websocket APIs that can be used for writing web wallets and other apps " 28 | "that need more advanced blockchain queries than provided by zcashd RPC. " 29 | "Check out the source code." 31 | msgstr "" 32 | "insight es un explorador de bloques de Zcash open-source con un completo " 34 | "conjunto de REST y APIs de websockets que pueden ser usadas para escribir " 35 | "monederos de Zcashs y otras aplicaciones que requieran consultar un " 36 | "explorador de bloques. Obtén el código en el repositorio abierto de Github." 38 | 39 | #: public/views/index.html 40 | msgid "" 41 | "insight is still in development, so be sure to report any " 42 | "bugs and provide feedback for improvement at our github issue tracker." 44 | msgstr "" 45 | "insight esta en desarrollo aún, por ello agradecemos que " 46 | "nos reporten errores o sugerencias para mejorar el software. Github issue " 48 | "tracker." 49 | 50 | #: public/views/index.html 51 | msgid "About" 52 | msgstr "Acerca de" 53 | 54 | #: public/views/address.html 55 | msgid "Address" 56 | msgstr "Dirección" 57 | 58 | #: public/views/index.html 59 | msgid "Age" 60 | msgstr "Edad" 61 | 62 | #: public/views/status.html 63 | msgid "Application Status" 64 | msgstr "Estado de la Aplicación" 65 | 66 | #: public/views/status.html 67 | msgid "Best Block" 68 | msgstr "Mejor Bloque" 69 | 70 | #: public/views/status.html 71 | msgid "Zcash node information" 72 | msgstr "Información del nodo Zcash" 73 | 74 | #: public/views/block.html 75 | msgid "Block" 76 | msgstr "Bloque" 77 | 78 | #: public/views/block.html 79 | msgid "Block Reward" 80 | msgstr "Bloque Recompensa" 81 | 82 | #: public/views/block_list.html public/views/dummy-translations.html 83 | #: public/views/status.html 84 | msgid "Blocks" 85 | msgstr "Bloques" 86 | 87 | #: public/views/status.html 88 | msgid "Bytes Serialized" 89 | msgstr "Bytes Serializados" 90 | 91 | #: public/views/includes/connection.html 92 | msgid "" 93 | "Can't connect to zcashd to get live updates from the p2p network. (Tried " 94 | "connecting to zcashd at {{host}}:{{port}} and failed.)" 95 | msgstr "" 96 | "No se pudo conectar a zcashd para obtener actualizaciones en vivo de la " 97 | "red p2p. (Se intentó conectar a zcashd de {{host}}:{{port}} y falló.)" 98 | 99 | #: public/views/includes/connection.html 100 | msgid "Can't connect to insight server. Attempting to reconnect..." 101 | msgstr "No se pudo conectar al servidor insight. Intentando re-conectar..." 102 | 103 | #: public/views/includes/connection.html 104 | msgid "Can't connect to internet. Please, check your connection." 105 | msgstr "No se pudo conectar a Internet. Por favor, verifique su conexión." 106 | 107 | #: public/views/status.html 108 | msgid "Complete" 109 | msgstr "Completado" 110 | 111 | #: public/views/transaction.html public/views/transaction/tx.html 112 | msgid "Confirmations" 113 | msgstr "Confirmaciones" 114 | 115 | #: public/views/includes/header.html 116 | msgid "Conn" 117 | msgstr "Con" 118 | 119 | #: public/views/status.html 120 | msgid "Connections to other nodes" 121 | msgstr "Conexiones a otros nodos" 122 | 123 | #: public/views/status.html 124 | msgid "Current Blockchain Tip (insight)" 125 | msgstr "Actual Blockchain Tip (insight)" 126 | 127 | #: public/views/status.html 128 | msgid "Current Sync Status" 129 | msgstr "Actual Estado de Sincronización" 130 | 131 | #: public/views/transaction.html 132 | msgid "Details" 133 | msgstr "Detalles" 134 | 135 | #: public/views/block.html 136 | msgid "Difficulty" 137 | msgstr "Dificultad" 138 | 139 | #: public/views/transaction/tx.html 140 | msgid "Double spent attempt detected. From tx:" 141 | msgstr "Intento de doble gasto detectado. De la transacción:" 142 | 143 | #: public/views/includes/connection.html 144 | msgid "Error!" 145 | msgstr "¡Error!" 146 | 147 | #: public/views/transaction/tx.html 148 | msgid "Fee" 149 | msgstr "Tasa" 150 | 151 | #: public/views/address.html 152 | msgid "Final Balance" 153 | msgstr "Balance Final" 154 | 155 | #: public/views/status.html 156 | msgid "Finish Date" 157 | msgstr "Fecha Final" 158 | 159 | #: public/views/404.html 160 | msgid "Go to home" 161 | msgstr "Volver al Inicio" 162 | 163 | #: public/views/status.html 164 | msgid "Hash Serialized" 165 | msgstr "Hash Serializado" 166 | 167 | #: public/views/block.html public/views/block_list.html 168 | #: public/views/index.html public/views/status.html 169 | #: public/views/includes/header.html 170 | msgid "Height" 171 | msgstr "Altura" 172 | 173 | #: public/views/transaction.html public/views/transaction/tx.html 174 | msgid "Included in Block" 175 | msgstr "Incluido en el Bloque" 176 | 177 | #: public/views/transaction/tx.html 178 | msgid "Incoherence in levelDB detected:" 179 | msgstr "Detectada una incoherencia en levelDB:" 180 | 181 | #: public/views/status.html 182 | msgid "Info Errors" 183 | msgstr "Errores de Información" 184 | 185 | #: public/views/status.html 186 | msgid "Initial Block Chain Height" 187 | msgstr "Altura de la Cadena en Bloque Inicial" 188 | 189 | #: public/views/transaction.html 190 | msgid "Input" 191 | msgstr "Entrada" 192 | 193 | #: public/views/status.html 194 | msgid "Last Block" 195 | msgstr "Último Bloque" 196 | 197 | #: public/views/status.html 198 | msgid "Last Block Hash (Zcashd)" 199 | msgstr "Último Bloque Hash (Zcashd)" 200 | 201 | #: public/views/index.html 202 | msgid "Latest Blocks" 203 | msgstr "Últimos Bloques" 204 | 205 | #: public/views/index.html 206 | msgid "Latest Transactions" 207 | msgstr "Últimas Transacciones" 208 | 209 | #: public/views/address.html 210 | msgid "Loading Address Information" 211 | msgstr "Cargando Información de la Dirección" 212 | 213 | #: public/views/block.html 214 | msgid "Loading Block Information" 215 | msgstr "Cargando Información del Bloque" 216 | 217 | #: public/views/block_list.html 218 | msgid "Loading Selected Date..." 219 | msgstr "Cargando Fecha Seleccionada..." 220 | 221 | #: public/views/transaction.html 222 | msgid "Loading Transaction Details" 223 | msgstr "Cargando Detalles de la Transacción" 224 | 225 | #: public/views/transaction/list.html 226 | msgid "Loading Transactions..." 227 | msgstr "Cargando Transacciones..." 228 | 229 | #: public/views/includes/infoStatus.html 230 | msgid "Loading..." 231 | msgstr "Cargando..." 232 | 233 | #: public/views/transaction.html 234 | msgid "Mined Time" 235 | msgstr "Hora de Minado" 236 | 237 | #: public/views/block.html public/views/block_list.html 238 | #: public/views/index.html 239 | msgid "Mined by" 240 | msgstr "Minado por" 241 | 242 | #: public/views/status.html 243 | msgid "Mining Difficulty" 244 | msgstr "Dificultad de Minado" 245 | 246 | #: public/views/block.html 247 | msgid "Next Block" 248 | msgstr "Próximo Bloque" 249 | 250 | #: public/views/transaction/tx.html 251 | msgid "No Inputs (Newly Generated Coins)" 252 | msgstr "Sin Entradas (Monedas Recién Generadas)" 253 | 254 | #: public/views/block_list.html 255 | msgid "No blocks yet." 256 | msgstr "No hay bloques aún." 257 | 258 | #: public/views/includes/header.html public/views/includes/search.html 259 | msgid "No matching records found!" 260 | msgstr "¡No se encontraron registros coincidentes!" 261 | 262 | #: public/views/address.html 263 | msgid "No. Transactions" 264 | msgstr "Nro. de Transacciones" 265 | 266 | #: public/views/block.html 267 | msgid "Number Of Transactions" 268 | msgstr "Número de Transacciones" 269 | 270 | #: public/views/transaction.html 271 | msgid "Output" 272 | msgstr "Salida" 273 | 274 | #: public/views/index.html 275 | msgid "Powered by" 276 | msgstr "Funciona con" 277 | 278 | #: public/views/block.html 279 | msgid "Previous Block" 280 | msgstr "Bloque Anterior" 281 | 282 | #: public/views/status.html 283 | msgid "Protocol version" 284 | msgstr "Versión del protocolo" 285 | 286 | #: public/views/status.html 287 | msgid "Proxy setting" 288 | msgstr "Opción de proxy" 289 | 290 | #: public/views/transaction.html 291 | msgid "Received Time" 292 | msgstr "Hora de Recibido" 293 | 294 | #: public/views/redirect.html 295 | msgid "Redirecting..." 296 | msgstr "Redireccionando..." 297 | 298 | #: public/views/includes/header.html 299 | msgid "Search for block, transaction or address" 300 | msgstr "Buscar bloques, transacciones o direcciones" 301 | 302 | #: public/views/index.html 303 | msgid "See all blocks" 304 | msgstr "Ver todos los bloques" 305 | 306 | #: public/views/status.html 307 | msgid "Show Transaction Output data" 308 | msgstr "Mostrar dato de Salida de la Transacción" 309 | 310 | #: public/views/transaction/tx.html 311 | msgid "Show all" 312 | msgstr "Mostrar todos" 313 | 314 | #: public/views/transaction/tx.html 315 | msgid "Show input" 316 | msgstr "Mostrar entrada" 317 | 318 | #: public/views/transaction/tx.html 319 | msgid "Show less" 320 | msgstr "Ver menos" 321 | 322 | #: public/views/transaction/tx.html 323 | msgid "Show more" 324 | msgstr "Ver más" 325 | 326 | #: public/views/block_list.html public/views/index.html 327 | #: public/views/transaction.html 328 | msgid "Size" 329 | msgstr "Tamaño" 330 | 331 | #: public/views/block.html 332 | msgid "Size (bytes)" 333 | msgstr "Tamaño (bytes)" 334 | 335 | #: public/views/status.html 336 | msgid "Skipped Blocks (previously synced)" 337 | msgstr "Bloques Saltados (previamente sincronizado)" 338 | 339 | #: public/views/status.html 340 | msgid "Start Date" 341 | msgstr "Fecha de Inicio" 342 | 343 | #: public/views/dummy-translations.html 344 | msgid "Status" 345 | msgstr "Estado" 346 | 347 | #: public/views/block.html public/views/transaction.html 348 | msgid "Summary" 349 | msgstr "Resumen" 350 | 351 | #: public/views/address.html 352 | msgid "Summary confirmed" 353 | msgstr "Resumen confirmados" 354 | 355 | #: public/views/status.html 356 | msgid "Sync Progress" 357 | msgstr "Proceso de Sincronización" 358 | 359 | #: public/views/status.html 360 | msgid "Sync Status" 361 | msgstr "Estado de Sincronización" 362 | 363 | #: public/views/status.html 364 | msgid "Sync Type" 365 | msgstr "Tipo de Sincronización" 366 | 367 | #: public/views/status.html 368 | msgid "Synced Blocks" 369 | msgstr "Bloques Sincornizados" 370 | 371 | #: public/views/status.html 372 | msgid "Testnet" 373 | msgstr "Red de prueba" 374 | 375 | #: public/views/transaction/list.html 376 | msgid "There are no transactions involving this address." 377 | msgstr "No hay transacciones para esta dirección" 378 | 379 | #: public/views/status.html 380 | msgid "Time Offset" 381 | msgstr "Desplazamiento de hora" 382 | 383 | #: public/views/block.html 384 | msgid "Timestamp" 385 | msgstr "Fecha y hora" 386 | 387 | #: public/views/block_list.html 388 | msgid "Today" 389 | msgstr "Hoy" 390 | 391 | #: public/views/status.html 392 | msgid "Total Amount" 393 | msgstr "Cantidad Total" 394 | 395 | #: public/views/address.html 396 | msgid "Total Received" 397 | msgstr "Total Recibido" 398 | 399 | #: public/views/address.html 400 | msgid "Total Sent" 401 | msgstr "Total Enviado" 402 | 403 | #: public/views/transaction.html 404 | msgid "Transaction" 405 | msgstr "Transacción" 406 | 407 | #: public/views/status.html 408 | msgid "Transaction Output Set Information" 409 | msgstr "Información del Conjunto de Salida de la Transacción" 410 | 411 | #: public/views/status.html 412 | msgid "Transaction Outputs" 413 | msgstr "Salidas de la Transacción" 414 | 415 | #: public/views/address.html public/views/block.html 416 | #: public/views/block_list.html public/views/index.html 417 | #: public/views/status.html 418 | msgid "Transactions" 419 | msgstr "Transacciones" 420 | 421 | #: public/views/transaction/tx.html 422 | msgid "Type" 423 | msgstr "Tipo" 424 | 425 | #: public/views/address.html 426 | msgid "Unconfirmed" 427 | msgstr "Sin confirmar" 428 | 429 | #: public/views/transaction.html public/views/transaction/tx.html 430 | msgid "Unconfirmed Transaction!" 431 | msgstr "¡Transacción sin confirmar!" 432 | 433 | #: public/views/address.html 434 | msgid "Unconfirmed Txs Balance" 435 | msgstr "Balance sin confirmar" 436 | 437 | #: public/views/index.html 438 | msgid "Value Out" 439 | msgstr "Valor de Salida" 440 | 441 | #: public/views/block.html public/views/status.html 442 | msgid "Version" 443 | msgstr "Versión" 444 | 445 | #: public/views/block_list.html public/views/index.html 446 | msgid "Waiting for blocks..." 447 | msgstr "Esperando bloques..." 448 | 449 | #: public/views/index.html 450 | msgid "Waiting for transactions..." 451 | msgstr "Esperando transacciones..." 452 | 453 | #: public/views/block_list.html 454 | msgid "by date." 455 | msgstr "por fecha." 456 | 457 | #: public/views/transaction/tx.html 458 | msgid "first seen at" 459 | msgstr "Visto a" 460 | 461 | #: public/views/transaction/tx.html 462 | msgid "mined" 463 | msgstr "minado" 464 | 465 | #: public/views/block_list.html 466 | msgid "mined on:" 467 | msgstr "minado el:" 468 | 469 | #~ msgid "Waiting for blocks" 470 | #~ msgstr "Esperando bloques" 471 | -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/img/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/.gitignore -------------------------------------------------------------------------------- /public/img/angularjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/angularjs.png -------------------------------------------------------------------------------- /public/img/icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/icons/copy.png -------------------------------------------------------------------------------- /public/img/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/icons/favicon.ico -------------------------------------------------------------------------------- /public/img/leveldb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/leveldb.png -------------------------------------------------------------------------------- /public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/loading.gif -------------------------------------------------------------------------------- /public/img/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/img/nodejs.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Testnet Insight 10 | Insight 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 43 |
44 |
45 | 46 |
47 |
48 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /public/lib/zeroclipboard/ZeroClipboard.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/lib/zeroclipboard/ZeroClipboard.swf -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /address 3 | Disallow: /api 4 | Disallow: /transaction 5 | -------------------------------------------------------------------------------- /public/sound/transaction.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/str4d/insight-ui-zcash/5a5fdc2aad05194d3b34ab9fce8470b873c7d636/public/sound/transaction.mp3 -------------------------------------------------------------------------------- /public/src/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var testnet = false; 4 | var netSymbol = testnet ? 'TAZ' : 'ZEC'; 5 | 6 | var defaultLanguage = localStorage.getItem('insight-language') || 'en'; 7 | var defaultCurrency = localStorage.getItem('insight-currency') || netSymbol; 8 | 9 | angular.module('insight',[ 10 | 'ngAnimate', 11 | 'ngResource', 12 | 'ngRoute', 13 | 'ngProgress', 14 | 'ui.bootstrap', 15 | 'ui.route', 16 | 'monospaced.qrcode', 17 | 'gettext', 18 | 'angularMoment', 19 | 'insight.system', 20 | 'insight.socket', 21 | 'insight.blocks', 22 | 'insight.transactions', 23 | 'insight.address', 24 | 'insight.search', 25 | 'insight.charts', 26 | 'insight.status', 27 | 'insight.connection', 28 | 'insight.currency', 29 | 'insight.messages' 30 | ]); 31 | 32 | angular.module('insight.system', []); 33 | angular.module('insight.socket', []); 34 | angular.module('insight.blocks', []); 35 | angular.module('insight.transactions', []); 36 | angular.module('insight.address', []); 37 | angular.module('insight.search', []); 38 | angular.module('insight.charts', []); 39 | angular.module('insight.status', []); 40 | angular.module('insight.connection', []); 41 | angular.module('insight.currency', []); 42 | angular.module('insight.messages', []); 43 | -------------------------------------------------------------------------------- /public/src/js/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //Setting up route 4 | angular.module('insight').config(function($routeProvider) { 5 | $routeProvider. 6 | when('/block/:blockHash', { 7 | templateUrl: 'views/block.html', 8 | title: 'Zcash Block ' 9 | }). 10 | when('/block-index/:blockHeight', { 11 | controller: 'BlocksController', 12 | templateUrl: 'views/redirect.html' 13 | }). 14 | when('/tx/send', { 15 | templateUrl: 'views/transaction_sendraw.html', 16 | title: 'Broadcast Raw Transaction' 17 | }). 18 | when('/tx/:txId/:v_type?/:v_index?', { 19 | templateUrl: 'views/transaction.html', 20 | title: 'Zcash Transaction ' 21 | }). 22 | when('/', { 23 | templateUrl: 'views/index.html', 24 | title: 'Home' 25 | }). 26 | when('/blocks', { 27 | templateUrl: 'views/block_list.html', 28 | title: 'Zcash Blocks solved Today' 29 | }). 30 | when('/blocks-date/:blockDate/:startTimestamp?', { 31 | templateUrl: 'views/block_list.html', 32 | title: 'Zcash Blocks solved ' 33 | }). 34 | when('/address/:addrStr', { 35 | templateUrl: 'views/address.html', 36 | title: 'Zcash Address ' 37 | }). 38 | when('/charts/:chartType?', { 39 | templateUrl: 'views/charts.html', 40 | title: 'Charts' 41 | }). 42 | when('/status', { 43 | templateUrl: 'views/status.html', 44 | title: 'Status' 45 | }). 46 | when('/messages/verify', { 47 | templateUrl: 'views/messages_verify.html', 48 | title: 'Verify Message' 49 | }) 50 | .otherwise({ 51 | templateUrl: 'views/404.html', 52 | title: 'Error' 53 | }); 54 | }); 55 | 56 | //Setting HTML5 Location Mode 57 | angular.module('insight') 58 | .config(function($locationProvider) { 59 | $locationProvider.html5Mode(true); 60 | $locationProvider.hashPrefix('!'); 61 | }) 62 | .run(function($rootScope, $route, $location, $routeParams, $anchorScroll, ngProgress, gettextCatalog, amMoment) { 63 | gettextCatalog.currentLanguage = defaultLanguage; 64 | amMoment.changeLocale(defaultLanguage); 65 | $rootScope.$on('$routeChangeStart', function() { 66 | ngProgress.start(); 67 | }); 68 | 69 | $rootScope.$on('$routeChangeSuccess', function() { 70 | ngProgress.complete(); 71 | 72 | //Change page title, based on Route information 73 | $rootScope.titleDetail = ''; 74 | $rootScope.title = $route.current.title; 75 | $rootScope.isCollapsed = true; 76 | $rootScope.currentAddr = null; 77 | 78 | $location.hash($routeParams.scrollTo); 79 | $anchorScroll(); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /public/src/js/controllers/address.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.address').controller('AddressController', 4 | function($scope, $rootScope, $routeParams, $location, Global, Address, getSocket) { 5 | $scope.global = Global; 6 | 7 | var socket = getSocket($scope); 8 | var addrStr = $routeParams.addrStr; 9 | 10 | var _startSocket = function() { 11 | socket.on('bitcoind/addresstxid', function(data) { 12 | if (data.address === addrStr) { 13 | $rootScope.$broadcast('tx', data.txid); 14 | var base = document.querySelector('base'); 15 | var beep = new Audio(base.href + '/sound/transaction.mp3'); 16 | beep.play(); 17 | } 18 | }); 19 | socket.emit('subscribe', 'bitcoind/addresstxid', [addrStr]); 20 | }; 21 | 22 | var _stopSocket = function () { 23 | socket.emit('unsubscribe', 'bitcoind/addresstxid', [addrStr]); 24 | }; 25 | 26 | socket.on('connect', function() { 27 | _startSocket(); 28 | }); 29 | 30 | $scope.$on('$destroy', function(){ 31 | _stopSocket(); 32 | }); 33 | 34 | $scope.params = $routeParams; 35 | 36 | $scope.findOne = function() { 37 | $rootScope.currentAddr = $routeParams.addrStr; 38 | _startSocket(); 39 | 40 | Address.get({ 41 | addrStr: $routeParams.addrStr 42 | }, 43 | function(address) { 44 | $rootScope.titleDetail = address.addrStr.substring(0, 7) + '...'; 45 | $rootScope.flashMessage = null; 46 | $scope.address = address; 47 | }, 48 | function(e) { 49 | if (e.status === 400) { 50 | $rootScope.flashMessage = 'Invalid Address: ' + $routeParams.addrStr; 51 | } else if (e.status === 503) { 52 | $rootScope.flashMessage = 'Backend Error. ' + e.data; 53 | } else { 54 | $rootScope.flashMessage = 'Address Not Found'; 55 | } 56 | $location.path('/'); 57 | }); 58 | }; 59 | 60 | }); 61 | -------------------------------------------------------------------------------- /public/src/js/controllers/blocks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.blocks').controller('BlocksController', 4 | function($scope, $rootScope, $routeParams, $location, Global, Block, Blocks, BlockByHeight) { 5 | $scope.global = Global; 6 | $scope.loading = false; 7 | 8 | if ($routeParams.blockHeight) { 9 | BlockByHeight.get({ 10 | blockHeight: $routeParams.blockHeight 11 | }, function(hash) { 12 | $location.path('/block/' + hash.blockHash); 13 | }, function() { 14 | $rootScope.flashMessage = 'Bad Request'; 15 | $location.path('/'); 16 | }); 17 | } 18 | 19 | //Datepicker 20 | var _formatTimestamp = function (date) { 21 | var yyyy = date.getUTCFullYear().toString(); 22 | var mm = (date.getUTCMonth() + 1).toString(); // getMonth() is zero-based 23 | var dd = date.getUTCDate().toString(); 24 | 25 | return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]); //padding 26 | }; 27 | 28 | $scope.$watch('dt', function(newValue, oldValue) { 29 | if (newValue !== oldValue) { 30 | $location.path('/blocks-date/' + _formatTimestamp(newValue)); 31 | } 32 | }); 33 | 34 | $scope.openCalendar = function($event) { 35 | $event.preventDefault(); 36 | $event.stopPropagation(); 37 | 38 | $scope.opened = true; 39 | }; 40 | 41 | $scope.humanSince = function(time) { 42 | var m = moment.unix(time).startOf('day'); 43 | var b = moment().startOf('day'); 44 | return moment.min(m).from(b); 45 | }; 46 | 47 | 48 | $scope.list = function() { 49 | $scope.loading = true; 50 | 51 | if ($routeParams.blockDate) { 52 | $scope.detail = 'On ' + $routeParams.blockDate; 53 | } 54 | 55 | if ($routeParams.startTimestamp) { 56 | var d=new Date($routeParams.startTimestamp*1000); 57 | var m=d.getMinutes(); 58 | if (m<10) m = '0' + m; 59 | $scope.before = ' before ' + d.getHours() + ':' + m; 60 | } 61 | 62 | $rootScope.titleDetail = $scope.detail; 63 | 64 | Blocks.get({ 65 | blockDate: $routeParams.blockDate, 66 | startTimestamp: $routeParams.startTimestamp 67 | }, function(res) { 68 | $scope.loading = false; 69 | $scope.blocks = res.blocks; 70 | $scope.pagination = res.pagination; 71 | }); 72 | }; 73 | 74 | $scope.findOne = function() { 75 | $scope.loading = true; 76 | 77 | Block.get({ 78 | blockHash: $routeParams.blockHash 79 | }, function(block) { 80 | $rootScope.titleDetail = block.height; 81 | $rootScope.flashMessage = null; 82 | $scope.loading = false; 83 | $scope.block = block; 84 | }, function(e) { 85 | if (e.status === 400) { 86 | $rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId; 87 | } 88 | else if (e.status === 503) { 89 | $rootScope.flashMessage = 'Backend Error. ' + e.data; 90 | } 91 | else { 92 | $rootScope.flashMessage = 'Block Not Found'; 93 | } 94 | $location.path('/'); 95 | }); 96 | }; 97 | 98 | $scope.params = $routeParams; 99 | 100 | }); 101 | -------------------------------------------------------------------------------- /public/src/js/controllers/charts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.charts').controller('ChartsController', 4 | function($scope, $rootScope, $routeParams, $location, Chart, Charts) { 5 | $scope.loading = false; 6 | 7 | $scope.list = function() { 8 | Charts.get({ 9 | }, function(res) { 10 | $scope.charts = res.charts; 11 | }); 12 | 13 | if ($routeParams.chartType) { 14 | $scope.chart(); 15 | } 16 | }; 17 | 18 | $scope.chart = function() { 19 | $scope.loading = true; 20 | 21 | Chart.get({ 22 | chartType: $routeParams.chartType 23 | }, function(chart) { 24 | $scope.loading = false; 25 | $scope.chartType = $routeParams.chartType; 26 | $scope.chartName = chart.name; 27 | $scope.chart = c3.generate(chart); 28 | }, function(e) { 29 | if (e.status === 400) { 30 | $rootScope.flashMessage = 'Invalid chart: ' + $routeParams.chartType; 31 | } 32 | else if (e.status === 503) { 33 | $rootScope.flashMessage = 'Backend Error. ' + e.data; 34 | } 35 | else { 36 | $rootScope.flashMessage = 'Chart Not Found'; 37 | } 38 | $location.path('/'); 39 | }); 40 | }; 41 | 42 | $scope.params = $routeParams; 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /public/src/js/controllers/connection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.connection').controller('ConnectionController', 4 | function($scope, $window, Status, getSocket, PeerSync) { 5 | 6 | // Set initial values 7 | $scope.apiOnline = true; 8 | $scope.serverOnline = true; 9 | $scope.clienteOnline = true; 10 | 11 | var socket = getSocket($scope); 12 | 13 | // Check for the node server connection 14 | socket.on('connect', function() { 15 | $scope.serverOnline = true; 16 | socket.on('disconnect', function() { 17 | $scope.serverOnline = false; 18 | }); 19 | }); 20 | 21 | // Check for the api connection 22 | $scope.getConnStatus = function() { 23 | PeerSync.get({}, 24 | function(peer) { 25 | $scope.apiOnline = peer.connected; 26 | $scope.host = peer.host; 27 | $scope.port = peer.port; 28 | }, 29 | function() { 30 | $scope.apiOnline = false; 31 | }); 32 | }; 33 | 34 | socket.emit('subscribe', 'sync'); 35 | socket.on('status', function(sync) { 36 | $scope.sync = sync; 37 | $scope.apiOnline = (sync.status !== 'aborted' && sync.status !== 'error'); 38 | }); 39 | 40 | // Check for the client conneciton 41 | $window.addEventListener('offline', function() { 42 | $scope.$apply(function() { 43 | $scope.clienteOnline = false; 44 | }); 45 | }, true); 46 | 47 | $window.addEventListener('online', function() { 48 | $scope.$apply(function() { 49 | $scope.clienteOnline = true; 50 | }); 51 | }, true); 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /public/src/js/controllers/currency.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.currency').controller('CurrencyController', 4 | function($scope, $rootScope, Currency) { 5 | $rootScope.currency.symbol = defaultCurrency; 6 | 7 | var _roundFloat = function(x, n) { 8 | if(!parseInt(n, 10) || !parseFloat(x)) n = 0; 9 | 10 | return Math.round(x * Math.pow(10, n)) / Math.pow(10, n); 11 | }; 12 | 13 | $rootScope.currency.getConvertion = function(value) { 14 | value = value * 1; // Convert to number 15 | 16 | if (!isNaN(value) && typeof value !== 'undefined' && value !== null) { 17 | if (value === 0.00000000) return '0 ' + this.symbol; // fix value to show 18 | 19 | var response; 20 | 21 | if (this.symbol === 'USD') { 22 | response = _roundFloat((value * this.factor), 2); 23 | } else if (this.symbol === 'm'+netSymbol) { 24 | this.factor = 1000; 25 | response = _roundFloat((value * this.factor), 5); 26 | } else if (this.symbol === 'bits') { 27 | this.factor = 1000000; 28 | response = _roundFloat((value * this.factor), 2); 29 | } else { 30 | this.factor = 1; 31 | response = value; 32 | } 33 | // prevent sci notation 34 | if (response < 1e-7) response=response.toFixed(8); 35 | 36 | return response + ' ' + this.symbol; 37 | } 38 | 39 | return 'value error'; 40 | }; 41 | 42 | $scope.setCurrency = function(currency) { 43 | $rootScope.currency.symbol = currency; 44 | localStorage.setItem('insight-currency', currency); 45 | 46 | if (currency === 'USD') { 47 | Currency.get({}, function(res) { 48 | $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; 49 | }); 50 | } else if (currency === 'm'+netSymbol) { 51 | $rootScope.currency.factor = 1000; 52 | } else if (currency === 'bits') { 53 | $rootScope.currency.factor = 1000000; 54 | } else { 55 | $rootScope.currency.factor = 1; 56 | } 57 | }; 58 | 59 | // Get initial value 60 | Currency.get({}, function(res) { 61 | $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; 62 | }); 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /public/src/js/controllers/footer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.system').controller('FooterController', 4 | function($scope, $route, $templateCache, gettextCatalog, amMoment, Version) { 5 | 6 | $scope.defaultLanguage = defaultLanguage; 7 | 8 | var _getVersion = function() { 9 | Version.get({}, 10 | function(res) { 11 | $scope.version = res.version; 12 | }); 13 | }; 14 | 15 | $scope.version = _getVersion(); 16 | 17 | $scope.availableLanguages = [{ 18 | name: 'Deutsch', 19 | isoCode: 'de_DE', 20 | }, { 21 | name: 'English', 22 | isoCode: 'en', 23 | }, { 24 | name: 'Spanish', 25 | isoCode: 'es', 26 | }, { 27 | name: 'Japanese', 28 | isoCode: 'ja', 29 | }]; 30 | 31 | $scope.setLanguage = function(isoCode) { 32 | gettextCatalog.currentLanguage = $scope.defaultLanguage = defaultLanguage = isoCode; 33 | amMoment.changeLocale(isoCode); 34 | localStorage.setItem('insight-language', isoCode); 35 | var currentPageTemplate = $route.current.templateUrl; 36 | $templateCache.remove(currentPageTemplate); 37 | $route.reload(); 38 | }; 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /public/src/js/controllers/header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.system').controller('HeaderController', 4 | function($scope, $rootScope, $modal, getSocket, Global, Block) { 5 | $scope.global = Global; 6 | 7 | $rootScope.currency = { 8 | factor: 1, 9 | bitstamp: 0, 10 | testnet: testnet, 11 | netSymbol: netSymbol, 12 | symbol: netSymbol 13 | }; 14 | 15 | $scope.menu = [{ 16 | 'title': 'Blocks', 17 | 'link': 'blocks' 18 | }, { 19 | 'title': 'Charts', 20 | 'link': 'charts' 21 | }, { 22 | 'title': 'Status', 23 | 'link': 'status' 24 | }]; 25 | 26 | $scope.openScannerModal = function() { 27 | var modalInstance = $modal.open({ 28 | templateUrl: 'scannerModal.html', 29 | controller: 'ScannerController' 30 | }); 31 | }; 32 | 33 | var _getBlock = function(hash) { 34 | Block.get({ 35 | blockHash: hash 36 | }, function(res) { 37 | $scope.totalBlocks = res.height; 38 | }); 39 | }; 40 | 41 | var socket = getSocket($scope); 42 | socket.on('connect', function() { 43 | socket.emit('subscribe', 'inv'); 44 | 45 | socket.on('block', function(block) { 46 | var blockHash = block.toString(); 47 | _getBlock(blockHash); 48 | }); 49 | }); 50 | 51 | $rootScope.isCollapsed = true; 52 | }); 53 | -------------------------------------------------------------------------------- /public/src/js/controllers/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TRANSACTION_DISPLAYED = 10; 4 | var BLOCKS_DISPLAYED = 5; 5 | 6 | angular.module('insight.system').controller('IndexController', 7 | function($scope, Global, getSocket, Blocks) { 8 | $scope.global = Global; 9 | 10 | var _getBlocks = function() { 11 | Blocks.get({ 12 | limit: BLOCKS_DISPLAYED 13 | }, function(res) { 14 | $scope.blocks = res.blocks; 15 | $scope.blocksLength = res.length; 16 | }); 17 | }; 18 | 19 | var socket = getSocket($scope); 20 | 21 | var _startSocket = function() { 22 | socket.emit('subscribe', 'inv'); 23 | socket.on('tx', function(tx) { 24 | $scope.txs.unshift(tx); 25 | if (parseInt($scope.txs.length, 10) >= parseInt(TRANSACTION_DISPLAYED, 10)) { 26 | $scope.txs = $scope.txs.splice(0, TRANSACTION_DISPLAYED); 27 | } 28 | }); 29 | 30 | socket.on('block', function() { 31 | _getBlocks(); 32 | }); 33 | }; 34 | 35 | socket.on('connect', function() { 36 | _startSocket(); 37 | }); 38 | 39 | 40 | 41 | $scope.humanSince = function(time) { 42 | var m = moment.unix(time); 43 | return moment.min(m).fromNow(); 44 | }; 45 | 46 | $scope.index = function() { 47 | _getBlocks(); 48 | _startSocket(); 49 | }; 50 | 51 | $scope.txs = []; 52 | $scope.blocks = []; 53 | }); 54 | -------------------------------------------------------------------------------- /public/src/js/controllers/messages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.messages').controller('VerifyMessageController', 4 | function($scope, $http) { 5 | $scope.message = { 6 | address: '', 7 | signature: '', 8 | message: '' 9 | }; 10 | $scope.verification = { 11 | status: 'unverified', // ready|loading|verified|error 12 | result: null, 13 | error: null, 14 | address: '' 15 | }; 16 | 17 | $scope.verifiable = function() { 18 | return ($scope.message.address 19 | && $scope.message.signature 20 | && $scope.message.message); 21 | }; 22 | $scope.verify = function() { 23 | $scope.verification.status = 'loading'; 24 | $scope.verification.address = $scope.message.address; 25 | $http.post(window.apiPrefix + '/messages/verify', $scope.message) 26 | .success(function(data, status, headers, config) { 27 | if(typeof(data.result) != 'boolean') { 28 | // API returned 200 but result was not true or false 29 | $scope.verification.status = 'error'; 30 | $scope.verification.error = null; 31 | return; 32 | } 33 | 34 | $scope.verification.status = 'verified'; 35 | $scope.verification.result = data.result; 36 | }) 37 | .error(function(data, status, headers, config) { 38 | $scope.verification.status = 'error'; 39 | $scope.verification.error = data; 40 | }); 41 | }; 42 | 43 | // Hide the verify status message on form change 44 | var unverify = function() { 45 | $scope.verification.status = 'unverified'; 46 | }; 47 | $scope.$watch('message.address', unverify); 48 | $scope.$watch('message.signature', unverify); 49 | $scope.$watch('message.message', unverify); 50 | }); 51 | -------------------------------------------------------------------------------- /public/src/js/controllers/scanner.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.system').controller('ScannerController', 4 | function($scope, $rootScope, $modalInstance, Global) { 5 | $scope.global = Global; 6 | 7 | // Detect mobile devices 8 | var isMobile = { 9 | Android: function() { 10 | return navigator.userAgent.match(/Android/i); 11 | }, 12 | BlackBerry: function() { 13 | return navigator.userAgent.match(/BlackBerry/i); 14 | }, 15 | iOS: function() { 16 | return navigator.userAgent.match(/iPhone|iPad|iPod/i); 17 | }, 18 | Opera: function() { 19 | return navigator.userAgent.match(/Opera Mini/i); 20 | }, 21 | Windows: function() { 22 | return navigator.userAgent.match(/IEMobile/i); 23 | }, 24 | any: function() { 25 | return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); 26 | } 27 | }; 28 | 29 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; 30 | window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; 31 | 32 | $scope.isMobile = isMobile.any(); 33 | $scope.scannerLoading = false; 34 | 35 | var $searchInput = angular.element(document.getElementById('search')), 36 | cameraInput, 37 | video, 38 | canvas, 39 | $video, 40 | context, 41 | localMediaStream; 42 | 43 | var _scan = function(evt) { 44 | if ($scope.isMobile) { 45 | $scope.scannerLoading = true; 46 | var files = evt.target.files; 47 | 48 | if (files.length === 1 && files[0].type.indexOf('image/') === 0) { 49 | var file = files[0]; 50 | 51 | var reader = new FileReader(); 52 | reader.onload = (function(theFile) { 53 | return function(e) { 54 | var mpImg = new MegaPixImage(file); 55 | mpImg.render(canvas, { maxWidth: 200, maxHeight: 200, orientation: 6 }); 56 | 57 | setTimeout(function() { 58 | qrcode.width = canvas.width; 59 | qrcode.height = canvas.height; 60 | qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height); 61 | 62 | try { 63 | //alert(JSON.stringify(qrcode.process(context))); 64 | qrcode.decode(); 65 | } catch (e) { 66 | alert(e); 67 | } 68 | }, 1500); 69 | }; 70 | })(file); 71 | 72 | // Read in the file as a data URL 73 | reader.readAsDataURL(file); 74 | } 75 | } else { 76 | if (localMediaStream) { 77 | context.drawImage(video, 0, 0, 300, 225); 78 | 79 | try { 80 | qrcode.decode(); 81 | } catch(e) { 82 | //qrcodeError(e); 83 | } 84 | } 85 | 86 | setTimeout(_scan, 500); 87 | } 88 | }; 89 | 90 | var _successCallback = function(stream) { 91 | video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; 92 | localMediaStream = stream; 93 | video.play(); 94 | setTimeout(_scan, 1000); 95 | }; 96 | 97 | var _scanStop = function() { 98 | $scope.scannerLoading = false; 99 | $modalInstance.close(); 100 | if (!$scope.isMobile) { 101 | if (localMediaStream.stop) localMediaStream.stop(); 102 | localMediaStream = null; 103 | video.src = ''; 104 | } 105 | }; 106 | 107 | var _videoError = function(err) { 108 | console.log('Video Error: ' + JSON.stringify(err)); 109 | _scanStop(); 110 | }; 111 | 112 | qrcode.callback = function(data) { 113 | _scanStop(); 114 | 115 | var str = (data.indexOf('zcash:') === 0) ? data.substring(8) : data; 116 | console.log('QR code detected: ' + str); 117 | $searchInput 118 | .val(str) 119 | .triggerHandler('change') 120 | .triggerHandler('submit'); 121 | }; 122 | 123 | $scope.cancel = function() { 124 | _scanStop(); 125 | }; 126 | 127 | $modalInstance.opened.then(function() { 128 | $rootScope.isCollapsed = true; 129 | 130 | // Start the scanner 131 | setTimeout(function() { 132 | canvas = document.getElementById('qr-canvas'); 133 | context = canvas.getContext('2d'); 134 | 135 | if ($scope.isMobile) { 136 | cameraInput = document.getElementById('qrcode-camera'); 137 | cameraInput.addEventListener('change', _scan, false); 138 | } else { 139 | video = document.getElementById('qrcode-scanner-video'); 140 | $video = angular.element(video); 141 | canvas.width = 300; 142 | canvas.height = 225; 143 | context.clearRect(0, 0, 300, 225); 144 | 145 | navigator.getUserMedia({video: true}, _successCallback, _videoError); 146 | } 147 | }, 500); 148 | }); 149 | }); 150 | -------------------------------------------------------------------------------- /public/src/js/controllers/search.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.search').controller('SearchController', 4 | function($scope, $routeParams, $location, $timeout, Global, Block, Transaction, Address, BlockByHeight) { 5 | $scope.global = Global; 6 | $scope.loading = false; 7 | 8 | var _badQuery = function() { 9 | $scope.badQuery = true; 10 | 11 | $timeout(function() { 12 | $scope.badQuery = false; 13 | }, 2000); 14 | }; 15 | 16 | var _resetSearch = function() { 17 | $scope.q = ''; 18 | $scope.loading = false; 19 | }; 20 | 21 | $scope.search = function() { 22 | var q = $scope.q; 23 | $scope.badQuery = false; 24 | $scope.loading = true; 25 | 26 | Block.get({ 27 | blockHash: q 28 | }, function() { 29 | _resetSearch(); 30 | $location.path('block/' + q); 31 | }, function() { //block not found, search on TX 32 | Transaction.get({ 33 | txId: q 34 | }, function() { 35 | _resetSearch(); 36 | $location.path('tx/' + q); 37 | }, function() { //tx not found, search on Address 38 | Address.get({ 39 | addrStr: q 40 | }, function() { 41 | _resetSearch(); 42 | $location.path('address/' + q); 43 | }, function() { // block by height not found 44 | if (isFinite(q)) { // ensure that q is a finite number. A logical height value. 45 | BlockByHeight.get({ 46 | blockHeight: q 47 | }, function(hash) { 48 | _resetSearch(); 49 | $location.path('/block/' + hash.blockHash); 50 | }, function() { //not found, fail :( 51 | $scope.loading = false; 52 | _badQuery(); 53 | }); 54 | } 55 | else { 56 | $scope.loading = false; 57 | _badQuery(); 58 | } 59 | }); 60 | }); 61 | }); 62 | }; 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /public/src/js/controllers/status.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.status').controller('StatusController', 4 | function($scope, $routeParams, $location, Global, Status, Sync, getSocket) { 5 | $scope.global = Global; 6 | 7 | $scope.getStatus = function(q) { 8 | Status.get({ 9 | q: 'get' + q 10 | }, 11 | function(d) { 12 | $scope.loaded = 1; 13 | angular.extend($scope, d); 14 | }, 15 | function(e) { 16 | $scope.error = 'API ERROR: ' + e.data; 17 | }); 18 | }; 19 | 20 | $scope.humanSince = function(time) { 21 | var m = moment.unix(time / 1000); 22 | return moment.min(m).fromNow(); 23 | }; 24 | 25 | var _onSyncUpdate = function(sync) { 26 | $scope.sync = sync; 27 | }; 28 | 29 | var _startSocket = function () { 30 | socket.emit('subscribe', 'sync'); 31 | socket.on('status', function(sync) { 32 | _onSyncUpdate(sync); 33 | }); 34 | }; 35 | 36 | var socket = getSocket($scope); 37 | socket.on('connect', function() { 38 | _startSocket(); 39 | }); 40 | 41 | 42 | $scope.getSync = function() { 43 | _startSocket(); 44 | Sync.get({}, 45 | function(sync) { 46 | _onSyncUpdate(sync); 47 | }, 48 | function(e) { 49 | var err = 'Could not get sync information' + e.toString(); 50 | $scope.sync = { 51 | error: err 52 | }; 53 | }); 54 | }; 55 | }); 56 | -------------------------------------------------------------------------------- /public/src/js/controllers/transactions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.transactions').controller('transactionsController', 4 | function($scope, $rootScope, $routeParams, $location, Global, Transaction, TransactionsByBlock, TransactionsByAddress) { 5 | $scope.global = Global; 6 | $scope.loading = false; 7 | $scope.loadedBy = null; 8 | 9 | var pageNum = 0; 10 | var pagesTotal = 1; 11 | var COIN = 100000000; 12 | 13 | var _aggregateItems = function(items) { 14 | if (!items) return []; 15 | 16 | var l = items.length; 17 | 18 | var ret = []; 19 | var tmp = {}; 20 | var u = 0; 21 | 22 | for(var i=0; i < l; i++) { 23 | 24 | var notAddr = false; 25 | // non standard input 26 | if (items[i].scriptSig && !items[i].addr) { 27 | items[i].addr = 'Unparsed address [' + u++ + ']'; 28 | items[i].notAddr = true; 29 | notAddr = true; 30 | } 31 | 32 | // non standard output 33 | if (items[i].scriptPubKey && !items[i].scriptPubKey.addresses) { 34 | items[i].scriptPubKey.addresses = ['Unparsed address [' + u++ + ']']; 35 | items[i].notAddr = true; 36 | notAddr = true; 37 | } 38 | 39 | // multiple addr at output 40 | if (items[i].scriptPubKey && items[i].scriptPubKey.addresses.length > 1) { 41 | items[i].addr = items[i].scriptPubKey.addresses.join(','); 42 | ret.push(items[i]); 43 | continue; 44 | } 45 | 46 | var addr = items[i].addr || (items[i].scriptPubKey && items[i].scriptPubKey.addresses[0]); 47 | 48 | if (!tmp[addr]) { 49 | tmp[addr] = {}; 50 | tmp[addr].valueSat = 0; 51 | tmp[addr].count = 0; 52 | tmp[addr].addr = addr; 53 | tmp[addr].items = []; 54 | } 55 | tmp[addr].isSpent = items[i].spentTxId; 56 | 57 | tmp[addr].doubleSpentTxID = tmp[addr].doubleSpentTxID || items[i].doubleSpentTxID; 58 | tmp[addr].doubleSpentIndex = tmp[addr].doubleSpentIndex || items[i].doubleSpentIndex; 59 | tmp[addr].dbError = tmp[addr].dbError || items[i].dbError; 60 | tmp[addr].valueSat += Math.round(items[i].value * COIN); 61 | tmp[addr].items.push(items[i]); 62 | tmp[addr].notAddr = notAddr; 63 | 64 | if (items[i].unconfirmedInput) 65 | tmp[addr].unconfirmedInput = true; 66 | 67 | tmp[addr].count++; 68 | } 69 | 70 | angular.forEach(tmp, function(v) { 71 | v.value = v.value || parseInt(v.valueSat) / COIN; 72 | ret.push(v); 73 | }); 74 | return ret; 75 | }; 76 | 77 | var _processTX = function(tx) { 78 | tx.vinSimple = _aggregateItems(tx.vin); 79 | tx.voutSimple = _aggregateItems(tx.vout); 80 | }; 81 | 82 | var _paginate = function(data) { 83 | $scope.loading = false; 84 | 85 | pagesTotal = data.pagesTotal; 86 | pageNum += 1; 87 | 88 | data.txs.forEach(function(tx) { 89 | _processTX(tx); 90 | $scope.txs.push(tx); 91 | }); 92 | }; 93 | 94 | var _byBlock = function() { 95 | TransactionsByBlock.get({ 96 | block: $routeParams.blockHash, 97 | pageNum: pageNum 98 | }, function(data) { 99 | _paginate(data); 100 | }); 101 | }; 102 | 103 | var _byAddress = function () { 104 | TransactionsByAddress.get({ 105 | address: $routeParams.addrStr, 106 | pageNum: pageNum 107 | }, function(data) { 108 | _paginate(data); 109 | }); 110 | }; 111 | 112 | var _findTx = function(txid) { 113 | Transaction.get({ 114 | txId: txid 115 | }, function(tx) { 116 | $rootScope.titleDetail = tx.txid.substring(0,7) + '...'; 117 | $rootScope.flashMessage = null; 118 | $scope.tx = tx; 119 | _processTX(tx); 120 | $scope.txs.unshift(tx); 121 | }, function(e) { 122 | if (e.status === 400) { 123 | $rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId; 124 | } 125 | else if (e.status === 503) { 126 | $rootScope.flashMessage = 'Backend Error. ' + e.data; 127 | } 128 | else { 129 | $rootScope.flashMessage = 'Transaction Not Found'; 130 | } 131 | 132 | $location.path('/'); 133 | }); 134 | }; 135 | 136 | $scope.findThis = function() { 137 | _findTx($routeParams.txId); 138 | }; 139 | 140 | //Initial load 141 | $scope.load = function(from) { 142 | $scope.loadedBy = from; 143 | $scope.loadMore(); 144 | }; 145 | 146 | //Load more transactions for pagination 147 | $scope.loadMore = function() { 148 | if (pageNum < pagesTotal && !$scope.loading) { 149 | $scope.loading = true; 150 | 151 | if ($scope.loadedBy === 'address') { 152 | _byAddress(); 153 | } 154 | else { 155 | _byBlock(); 156 | } 157 | } 158 | }; 159 | 160 | // Highlighted txout 161 | if ($routeParams.v_type == '>' || $routeParams.v_type == '<') { 162 | $scope.from_vin = $routeParams.v_type == '<' ? true : false; 163 | $scope.from_vout = $routeParams.v_type == '>' ? true : false; 164 | $scope.v_index = parseInt($routeParams.v_index); 165 | $scope.itemsExpanded = true; 166 | } 167 | 168 | //Init without txs 169 | $scope.txs = []; 170 | 171 | $scope.$on('tx', function(event, txid) { 172 | _findTx(txid); 173 | }); 174 | 175 | }); 176 | 177 | angular.module('insight.transactions').controller('SendRawTransactionController', 178 | function($scope, $http) { 179 | $scope.transaction = ''; 180 | $scope.status = 'ready'; // ready|loading|sent|error 181 | $scope.txid = ''; 182 | $scope.error = null; 183 | 184 | $scope.formValid = function() { 185 | return !!$scope.transaction; 186 | }; 187 | $scope.send = function() { 188 | var postData = { 189 | rawtx: $scope.transaction 190 | }; 191 | $scope.status = 'loading'; 192 | $http.post(window.apiPrefix + '/tx/send', postData) 193 | .success(function(data, status, headers, config) { 194 | if(typeof(data.txid) != 'string') { 195 | // API returned 200 but the format is not known 196 | $scope.status = 'error'; 197 | $scope.error = 'The transaction was sent but no transaction id was got back'; 198 | return; 199 | } 200 | 201 | $scope.status = 'sent'; 202 | $scope.txid = data.txid; 203 | }) 204 | .error(function(data, status, headers, config) { 205 | $scope.status = 'error'; 206 | if(data) { 207 | $scope.error = data; 208 | } else { 209 | $scope.error = "No error message given (connection error?)" 210 | } 211 | }); 212 | }; 213 | }); 214 | -------------------------------------------------------------------------------- /public/src/js/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ZeroClipboard = window.ZeroClipboard; 4 | 5 | angular.module('insight') 6 | .directive('scroll', function ($window) { 7 | return function(scope, element, attrs) { 8 | angular.element($window).bind('scroll', function() { 9 | if (this.pageYOffset >= 200) { 10 | scope.secondaryNavbar = true; 11 | } else { 12 | scope.secondaryNavbar = false; 13 | } 14 | scope.$apply(); 15 | }); 16 | }; 17 | }) 18 | .directive('whenScrolled', function($window) { 19 | return { 20 | restric: 'A', 21 | link: function(scope, elm, attr) { 22 | var pageHeight, clientHeight, scrollPos; 23 | $window = angular.element($window); 24 | 25 | var handler = function() { 26 | pageHeight = window.document.documentElement.scrollHeight; 27 | clientHeight = window.document.documentElement.clientHeight; 28 | scrollPos = window.pageYOffset; 29 | 30 | if (pageHeight - (scrollPos + clientHeight) === 0) { 31 | scope.$apply(attr.whenScrolled); 32 | } 33 | }; 34 | 35 | $window.on('scroll', handler); 36 | 37 | scope.$on('$destroy', function() { 38 | return $window.off('scroll', handler); 39 | }); 40 | } 41 | }; 42 | }) 43 | .directive('clipCopy', function() { 44 | ZeroClipboard.config({ 45 | moviePath: '/lib/zeroclipboard/ZeroClipboard.swf', 46 | trustedDomains: ['*'], 47 | allowScriptAccess: 'always', 48 | forceHandCursor: true 49 | }); 50 | 51 | return { 52 | restric: 'A', 53 | scope: { clipCopy: '=clipCopy' }, 54 | template: '
Copied!
', 55 | link: function(scope, elm) { 56 | var clip = new ZeroClipboard(elm); 57 | 58 | clip.on('load', function(client) { 59 | var onMousedown = function(client) { 60 | client.setText(scope.clipCopy); 61 | }; 62 | 63 | client.on('mousedown', onMousedown); 64 | 65 | scope.$on('$destroy', function() { 66 | client.off('mousedown', onMousedown); 67 | }); 68 | }); 69 | 70 | clip.on('noFlash wrongflash', function() { 71 | return elm.remove(); 72 | }); 73 | } 74 | }; 75 | }) 76 | .directive('focus', function ($timeout) { 77 | return { 78 | scope: { 79 | trigger: '@focus' 80 | }, 81 | link: function (scope, element) { 82 | scope.$watch('trigger', function (value) { 83 | if (value === "true") { 84 | $timeout(function () { 85 | element[0].focus(); 86 | }); 87 | } 88 | }); 89 | } 90 | }; 91 | }); 92 | -------------------------------------------------------------------------------- /public/src/js/filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight') 4 | .filter('startFrom', function() { 5 | return function(input, start) { 6 | start = +start; //parse to int 7 | return input.slice(start); 8 | } 9 | }) 10 | .filter('split', function() { 11 | return function(input, delimiter) { 12 | var delimiter = delimiter || ','; 13 | return input.split(delimiter); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /public/src/js/init.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.element(document).ready(function() { 4 | // Init the app 5 | // angular.bootstrap(document, ['insight']); 6 | }); 7 | -------------------------------------------------------------------------------- /public/src/js/ios-imagefile-megapixel/megapix-image.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Mega pixel image rendering library for iOS6 Safari 3 | * 4 | * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel), 5 | * which causes unexpected subsampling when drawing it in canvas. 6 | * By using this library, you can safely render the image with proper stretching. 7 | * 8 | * Copyright (c) 2012 Shinichi Tomita 9 | * Released under the MIT license 10 | */ 11 | (function() { 12 | 13 | /** 14 | * Detect subsampling in loaded image. 15 | * In iOS, larger images than 2M pixels may be subsampled in rendering. 16 | */ 17 | function detectSubsampling(img) { 18 | var iw = img.naturalWidth, ih = img.naturalHeight; 19 | if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image 20 | var canvas = document.createElement('canvas'); 21 | canvas.width = canvas.height = 1; 22 | var ctx = canvas.getContext('2d'); 23 | ctx.drawImage(img, -iw + 1, 0); 24 | // subsampled image becomes half smaller in rendering size. 25 | // check alpha channel value to confirm image is covering edge pixel or not. 26 | // if alpha value is 0 image is not covering, hence subsampled. 27 | return ctx.getImageData(0, 0, 1, 1).data[3] === 0; 28 | } else { 29 | return false; 30 | } 31 | } 32 | 33 | /** 34 | * Detecting vertical squash in loaded image. 35 | * Fixes a bug which squash image vertically while drawing into canvas for some images. 36 | */ 37 | function detectVerticalSquash(img, iw, ih) { 38 | var canvas = document.createElement('canvas'); 39 | canvas.width = 1; 40 | canvas.height = ih; 41 | var ctx = canvas.getContext('2d'); 42 | ctx.drawImage(img, 0, 0); 43 | var data = ctx.getImageData(0, 0, 1, ih).data; 44 | // search image edge pixel position in case it is squashed vertically. 45 | var sy = 0; 46 | var ey = ih; 47 | var py = ih; 48 | while (py > sy) { 49 | var alpha = data[(py - 1) * 4 + 3]; 50 | if (alpha === 0) { 51 | ey = py; 52 | } else { 53 | sy = py; 54 | } 55 | py = (ey + sy) >> 1; 56 | } 57 | var ratio = (py / ih); 58 | return (ratio===0)?1:ratio; 59 | } 60 | 61 | /** 62 | * Rendering image element (with resizing) and get its data URL 63 | */ 64 | function renderImageToDataURL(img, options, doSquash) { 65 | var canvas = document.createElement('canvas'); 66 | renderImageToCanvas(img, canvas, options, doSquash); 67 | return canvas.toDataURL("image/jpeg", options.quality || 0.8); 68 | } 69 | 70 | /** 71 | * Rendering image element (with resizing) into the canvas element 72 | */ 73 | function renderImageToCanvas(img, canvas, options, doSquash) { 74 | var iw = img.naturalWidth, ih = img.naturalHeight; 75 | var width = options.width, height = options.height; 76 | var ctx = canvas.getContext('2d'); 77 | ctx.save(); 78 | transformCoordinate(canvas, width, height, options.orientation); 79 | var subsampled = detectSubsampling(img); 80 | if (subsampled) { 81 | iw /= 2; 82 | ih /= 2; 83 | } 84 | var d = 1024; // size of tiling canvas 85 | var tmpCanvas = document.createElement('canvas'); 86 | tmpCanvas.width = tmpCanvas.height = d; 87 | var tmpCtx = tmpCanvas.getContext('2d'); 88 | var vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1; 89 | var dw = Math.ceil(d * width / iw); 90 | var dh = Math.ceil(d * height / ih / vertSquashRatio); 91 | var sy = 0; 92 | var dy = 0; 93 | while (sy < ih) { 94 | var sx = 0; 95 | var dx = 0; 96 | while (sx < iw) { 97 | tmpCtx.clearRect(0, 0, d, d); 98 | tmpCtx.drawImage(img, -sx, -sy); 99 | ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh); 100 | sx += d; 101 | dx += dw; 102 | } 103 | sy += d; 104 | dy += dh; 105 | } 106 | ctx.restore(); 107 | tmpCanvas = tmpCtx = null; 108 | } 109 | 110 | /** 111 | * Transform canvas coordination according to specified frame size and orientation 112 | * Orientation value is from EXIF tag 113 | */ 114 | function transformCoordinate(canvas, width, height, orientation) { 115 | switch (orientation) { 116 | case 5: 117 | case 6: 118 | case 7: 119 | case 8: 120 | canvas.width = height; 121 | canvas.height = width; 122 | break; 123 | default: 124 | canvas.width = width; 125 | canvas.height = height; 126 | } 127 | var ctx = canvas.getContext('2d'); 128 | switch (orientation) { 129 | case 2: 130 | // horizontal flip 131 | ctx.translate(width, 0); 132 | ctx.scale(-1, 1); 133 | break; 134 | case 3: 135 | // 180 rotate left 136 | ctx.translate(width, height); 137 | ctx.rotate(Math.PI); 138 | break; 139 | case 4: 140 | // vertical flip 141 | ctx.translate(0, height); 142 | ctx.scale(1, -1); 143 | break; 144 | case 5: 145 | // vertical flip + 90 rotate right 146 | ctx.rotate(0.5 * Math.PI); 147 | ctx.scale(1, -1); 148 | break; 149 | case 6: 150 | // 90 rotate right 151 | ctx.rotate(0.5 * Math.PI); 152 | ctx.translate(0, -height); 153 | break; 154 | case 7: 155 | // horizontal flip + 90 rotate right 156 | ctx.rotate(0.5 * Math.PI); 157 | ctx.translate(width, -height); 158 | ctx.scale(-1, 1); 159 | break; 160 | case 8: 161 | // 90 rotate left 162 | ctx.rotate(-0.5 * Math.PI); 163 | ctx.translate(-width, 0); 164 | break; 165 | default: 166 | break; 167 | } 168 | } 169 | 170 | 171 | /** 172 | * MegaPixImage class 173 | */ 174 | function MegaPixImage(srcImage) { 175 | if (window.Blob && srcImage instanceof Blob) { 176 | var img = new Image(); 177 | var URL = window.URL && window.URL.createObjectURL ? window.URL : 178 | window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : 179 | null; 180 | if (!URL) { throw Error("No createObjectURL function found to create blob url"); } 181 | img.src = URL.createObjectURL(srcImage); 182 | this.blob = srcImage; 183 | srcImage = img; 184 | } 185 | if (!srcImage.naturalWidth && !srcImage.naturalHeight) { 186 | var _this = this; 187 | srcImage.onload = function() { 188 | var listeners = _this.imageLoadListeners; 189 | if (listeners) { 190 | _this.imageLoadListeners = null; 191 | for (var i=0, len=listeners.length; i maxWidth) { 224 | width = maxWidth; 225 | height = (imgHeight * width / imgWidth) << 0; 226 | } 227 | if (maxHeight && height > maxHeight) { 228 | height = maxHeight; 229 | width = (imgWidth * height / imgHeight) << 0; 230 | } 231 | var opt = { width : width, height : height }; 232 | for (var k in options) opt[k] = options[k]; 233 | 234 | var tagName = target.tagName.toLowerCase(); 235 | if (tagName === 'img') { 236 | target.src = renderImageToDataURL(this.srcImage, opt, doSquash); 237 | } else if (tagName === 'canvas') { 238 | renderImageToCanvas(this.srcImage, target, opt, doSquash); 239 | } 240 | if (typeof this.onrender === 'function') { 241 | this.onrender(target); 242 | } 243 | }; 244 | 245 | /** 246 | * Export class to global 247 | */ 248 | if (typeof define === 'function' && define.amd) { 249 | define([], function() { return MegaPixImage; }); // for AMD loader 250 | } else { 251 | this.MegaPixImage = MegaPixImage; 252 | } 253 | 254 | })(); 255 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/alignpat.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function AlignmentPattern(posX, posY, estimatedModuleSize) 27 | { 28 | this.x=posX; 29 | this.y=posY; 30 | this.count = 1; 31 | this.estimatedModuleSize = estimatedModuleSize; 32 | 33 | this.__defineGetter__("EstimatedModuleSize", function() 34 | { 35 | return this.estimatedModuleSize; 36 | }); 37 | this.__defineGetter__("Count", function() 38 | { 39 | return this.count; 40 | }); 41 | this.__defineGetter__("X", function() 42 | { 43 | return Math.floor(this.x); 44 | }); 45 | this.__defineGetter__("Y", function() 46 | { 47 | return Math.floor(this.y); 48 | }); 49 | this.incrementCount = function() 50 | { 51 | this.count++; 52 | } 53 | this.aboutEquals=function( moduleSize, i, j) 54 | { 55 | if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) 56 | { 57 | var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); 58 | return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; 59 | } 60 | return false; 61 | } 62 | 63 | } 64 | 65 | function AlignmentPatternFinder( image, startX, startY, width, height, moduleSize, resultPointCallback) 66 | { 67 | this.image = image; 68 | this.possibleCenters = new Array(); 69 | this.startX = startX; 70 | this.startY = startY; 71 | this.width = width; 72 | this.height = height; 73 | this.moduleSize = moduleSize; 74 | this.crossCheckStateCount = new Array(0,0,0); 75 | this.resultPointCallback = resultPointCallback; 76 | 77 | this.centerFromEnd=function(stateCount, end) 78 | { 79 | return (end - stateCount[2]) - stateCount[1] / 2.0; 80 | } 81 | this.foundPatternCross = function(stateCount) 82 | { 83 | var moduleSize = this.moduleSize; 84 | var maxVariance = moduleSize / 2.0; 85 | for (var i = 0; i < 3; i++) 86 | { 87 | if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) 88 | { 89 | return false; 90 | } 91 | } 92 | return true; 93 | } 94 | 95 | this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal) 96 | { 97 | var image = this.image; 98 | 99 | var maxI = qrcode.height; 100 | var stateCount = this.crossCheckStateCount; 101 | stateCount[0] = 0; 102 | stateCount[1] = 0; 103 | stateCount[2] = 0; 104 | 105 | // Start counting up from center 106 | var i = startI; 107 | while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) 108 | { 109 | stateCount[1]++; 110 | i--; 111 | } 112 | // If already too many modules in this state or ran off the edge: 113 | if (i < 0 || stateCount[1] > maxCount) 114 | { 115 | return NaN; 116 | } 117 | while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount) 118 | { 119 | stateCount[0]++; 120 | i--; 121 | } 122 | if (stateCount[0] > maxCount) 123 | { 124 | return NaN; 125 | } 126 | 127 | // Now also count down from center 128 | i = startI + 1; 129 | while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) 130 | { 131 | stateCount[1]++; 132 | i++; 133 | } 134 | if (i == maxI || stateCount[1] > maxCount) 135 | { 136 | return NaN; 137 | } 138 | while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount) 139 | { 140 | stateCount[2]++; 141 | i++; 142 | } 143 | if (stateCount[2] > maxCount) 144 | { 145 | return NaN; 146 | } 147 | 148 | var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; 149 | if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) 150 | { 151 | return NaN; 152 | } 153 | 154 | return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN; 155 | } 156 | 157 | this.handlePossibleCenter=function( stateCount, i, j) 158 | { 159 | var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; 160 | var centerJ = this.centerFromEnd(stateCount, j); 161 | var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal); 162 | if (!isNaN(centerI)) 163 | { 164 | var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; 165 | var max = this.possibleCenters.length; 166 | for (var index = 0; index < max; index++) 167 | { 168 | var center = this.possibleCenters[index]; 169 | // Look for about the same center and module size: 170 | if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) 171 | { 172 | return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); 173 | } 174 | } 175 | // Hadn't found this before; save it 176 | var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); 177 | this.possibleCenters.push(point); 178 | if (this.resultPointCallback != null) 179 | { 180 | this.resultPointCallback.foundPossibleResultPoint(point); 181 | } 182 | } 183 | return null; 184 | } 185 | 186 | this.find = function() 187 | { 188 | var startX = this.startX; 189 | var height = this.height; 190 | var maxJ = startX + width; 191 | var middleI = startY + (height >> 1); 192 | // We are looking for black/white/black modules in 1:1:1 ratio; 193 | // this tracks the number of black/white/black modules seen so far 194 | var stateCount = new Array(0,0,0); 195 | for (var iGen = 0; iGen < height; iGen++) 196 | { 197 | // Search from middle outwards 198 | var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1)); 199 | stateCount[0] = 0; 200 | stateCount[1] = 0; 201 | stateCount[2] = 0; 202 | var j = startX; 203 | // Burn off leading white pixels before anything else; if we start in the middle of 204 | // a white run, it doesn't make sense to count its length, since we don't know if the 205 | // white run continued to the left of the start point 206 | while (j < maxJ && !image[j + qrcode.width* i]) 207 | { 208 | j++; 209 | } 210 | var currentState = 0; 211 | while (j < maxJ) 212 | { 213 | if (image[j + i*qrcode.width]) 214 | { 215 | // Black pixel 216 | if (currentState == 1) 217 | { 218 | // Counting black pixels 219 | stateCount[currentState]++; 220 | } 221 | else 222 | { 223 | // Counting white pixels 224 | if (currentState == 2) 225 | { 226 | // A winner? 227 | if (this.foundPatternCross(stateCount)) 228 | { 229 | // Yes 230 | var confirmed = this.handlePossibleCenter(stateCount, i, j); 231 | if (confirmed != null) 232 | { 233 | return confirmed; 234 | } 235 | } 236 | stateCount[0] = stateCount[2]; 237 | stateCount[1] = 1; 238 | stateCount[2] = 0; 239 | currentState = 1; 240 | } 241 | else 242 | { 243 | stateCount[++currentState]++; 244 | } 245 | } 246 | } 247 | else 248 | { 249 | // White pixel 250 | if (currentState == 1) 251 | { 252 | // Counting black pixels 253 | currentState++; 254 | } 255 | stateCount[currentState]++; 256 | } 257 | j++; 258 | } 259 | if (this.foundPatternCross(stateCount)) 260 | { 261 | var confirmed = this.handlePossibleCenter(stateCount, i, maxJ); 262 | if (confirmed != null) 263 | { 264 | return confirmed; 265 | } 266 | } 267 | } 268 | 269 | // Hmm, nothing we saw was observed and confirmed twice. If we had 270 | // any guess at all, return it. 271 | if (!(this.possibleCenters.length == 0)) 272 | { 273 | return this.possibleCenters[0]; 274 | } 275 | 276 | throw "Couldn't find enough alignment patterns"; 277 | } 278 | 279 | } -------------------------------------------------------------------------------- /public/src/js/jsqrcode/bitmat.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function BitMatrix( width, height) 27 | { 28 | if(!height) 29 | height=width; 30 | if (width < 1 || height < 1) 31 | { 32 | throw "Both dimensions must be greater than 0"; 33 | } 34 | this.width = width; 35 | this.height = height; 36 | var rowSize = width >> 5; 37 | if ((width & 0x1f) != 0) 38 | { 39 | rowSize++; 40 | } 41 | this.rowSize = rowSize; 42 | this.bits = new Array(rowSize * height); 43 | for(var i=0;i> 5); 66 | return ((URShift(this.bits[offset], (x & 0x1f))) & 1) != 0; 67 | } 68 | this.set_Renamed=function( x, y) 69 | { 70 | var offset = y * this.rowSize + (x >> 5); 71 | this.bits[offset] |= 1 << (x & 0x1f); 72 | } 73 | this.flip=function( x, y) 74 | { 75 | var offset = y * this.rowSize + (x >> 5); 76 | this.bits[offset] ^= 1 << (x & 0x1f); 77 | } 78 | this.clear=function() 79 | { 80 | var max = this.bits.length; 81 | for (var i = 0; i < max; i++) 82 | { 83 | this.bits[i] = 0; 84 | } 85 | } 86 | this.setRegion=function( left, top, width, height) 87 | { 88 | if (top < 0 || left < 0) 89 | { 90 | throw "Left and top must be nonnegative"; 91 | } 92 | if (height < 1 || width < 1) 93 | { 94 | throw "Height and width must be at least 1"; 95 | } 96 | var right = left + width; 97 | var bottom = top + height; 98 | if (bottom > this.height || right > this.width) 99 | { 100 | throw "The region must fit inside the matrix"; 101 | } 102 | for (var y = top; y < bottom; y++) 103 | { 104 | var offset = y * this.rowSize; 105 | for (var x = left; x < right; x++) 106 | { 107 | this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f); 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /public/src/js/jsqrcode/bmparser.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function BitMatrixParser(bitMatrix) 27 | { 28 | var dimension = bitMatrix.Dimension; 29 | if (dimension < 21 || (dimension & 0x03) != 1) 30 | { 31 | throw "Error BitMatrixParser"; 32 | } 33 | this.bitMatrix = bitMatrix; 34 | this.parsedVersion = null; 35 | this.parsedFormatInfo = null; 36 | 37 | this.copyBit=function( i, j, versionBits) 38 | { 39 | return this.bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1; 40 | } 41 | 42 | this.readFormatInformation=function() 43 | { 44 | if (this.parsedFormatInfo != null) 45 | { 46 | return this.parsedFormatInfo; 47 | } 48 | 49 | // Read top-left format info bits 50 | var formatInfoBits = 0; 51 | for (var i = 0; i < 6; i++) 52 | { 53 | formatInfoBits = this.copyBit(i, 8, formatInfoBits); 54 | } 55 | // .. and skip a bit in the timing pattern ... 56 | formatInfoBits = this.copyBit(7, 8, formatInfoBits); 57 | formatInfoBits = this.copyBit(8, 8, formatInfoBits); 58 | formatInfoBits = this.copyBit(8, 7, formatInfoBits); 59 | // .. and skip a bit in the timing pattern ... 60 | for (var j = 5; j >= 0; j--) 61 | { 62 | formatInfoBits = this.copyBit(8, j, formatInfoBits); 63 | } 64 | 65 | this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); 66 | if (this.parsedFormatInfo != null) 67 | { 68 | return this.parsedFormatInfo; 69 | } 70 | 71 | // Hmm, failed. Try the top-right/bottom-left pattern 72 | var dimension = this.bitMatrix.Dimension; 73 | formatInfoBits = 0; 74 | var iMin = dimension - 8; 75 | for (var i = dimension - 1; i >= iMin; i--) 76 | { 77 | formatInfoBits = this.copyBit(i, 8, formatInfoBits); 78 | } 79 | for (var j = dimension - 7; j < dimension; j++) 80 | { 81 | formatInfoBits = this.copyBit(8, j, formatInfoBits); 82 | } 83 | 84 | this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); 85 | if (this.parsedFormatInfo != null) 86 | { 87 | return this.parsedFormatInfo; 88 | } 89 | throw "Error readFormatInformation"; 90 | } 91 | this.readVersion=function() 92 | { 93 | 94 | if (this.parsedVersion != null) 95 | { 96 | return this.parsedVersion; 97 | } 98 | 99 | var dimension = this.bitMatrix.Dimension; 100 | 101 | var provisionalVersion = (dimension - 17) >> 2; 102 | if (provisionalVersion <= 6) 103 | { 104 | return Version.getVersionForNumber(provisionalVersion); 105 | } 106 | 107 | // Read top-right version info: 3 wide by 6 tall 108 | var versionBits = 0; 109 | var ijMin = dimension - 11; 110 | for (var j = 5; j >= 0; j--) 111 | { 112 | for (var i = dimension - 9; i >= ijMin; i--) 113 | { 114 | versionBits = this.copyBit(i, j, versionBits); 115 | } 116 | } 117 | 118 | this.parsedVersion = Version.decodeVersionInformation(versionBits); 119 | if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) 120 | { 121 | return this.parsedVersion; 122 | } 123 | 124 | // Hmm, failed. Try bottom left: 6 wide by 3 tall 125 | versionBits = 0; 126 | for (var i = 5; i >= 0; i--) 127 | { 128 | for (var j = dimension - 9; j >= ijMin; j--) 129 | { 130 | versionBits = this.copyBit(i, j, versionBits); 131 | } 132 | } 133 | 134 | this.parsedVersion = Version.decodeVersionInformation(versionBits); 135 | if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) 136 | { 137 | return this.parsedVersion; 138 | } 139 | throw "Error readVersion"; 140 | } 141 | this.readCodewords=function() 142 | { 143 | 144 | var formatInfo = this.readFormatInformation(); 145 | var version = this.readVersion(); 146 | 147 | // Get the data mask for the format used in this QR Code. This will exclude 148 | // some bits from reading as we wind through the bit matrix. 149 | var dataMask = DataMask.forReference( formatInfo.DataMask); 150 | var dimension = this.bitMatrix.Dimension; 151 | dataMask.unmaskBitMatrix(this.bitMatrix, dimension); 152 | 153 | var functionPattern = version.buildFunctionPattern(); 154 | 155 | var readingUp = true; 156 | var result = new Array(version.TotalCodewords); 157 | var resultOffset = 0; 158 | var currentByte = 0; 159 | var bitsRead = 0; 160 | // Read columns in pairs, from right to left 161 | for (var j = dimension - 1; j > 0; j -= 2) 162 | { 163 | if (j == 6) 164 | { 165 | // Skip whole column with vertical alignment pattern; 166 | // saves time and makes the other code proceed more cleanly 167 | j--; 168 | } 169 | // Read alternatingly from bottom to top then top to bottom 170 | for (var count = 0; count < dimension; count++) 171 | { 172 | var i = readingUp?dimension - 1 - count:count; 173 | for (var col = 0; col < 2; col++) 174 | { 175 | // Ignore bits covered by the function pattern 176 | if (!functionPattern.get_Renamed(j - col, i)) 177 | { 178 | // Read a bit 179 | bitsRead++; 180 | currentByte <<= 1; 181 | if (this.bitMatrix.get_Renamed(j - col, i)) 182 | { 183 | currentByte |= 1; 184 | } 185 | // If we've made a whole byte, save it off 186 | if (bitsRead == 8) 187 | { 188 | result[resultOffset++] = currentByte; 189 | bitsRead = 0; 190 | currentByte = 0; 191 | } 192 | } 193 | } 194 | } 195 | readingUp ^= true; // readingUp = !readingUp; // switch directions 196 | } 197 | if (resultOffset != version.TotalCodewords) 198 | { 199 | throw "Error readCodewords"; 200 | } 201 | return result; 202 | } 203 | } -------------------------------------------------------------------------------- /public/src/js/jsqrcode/datablock.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function DataBlock(numDataCodewords, codewords) 27 | { 28 | this.numDataCodewords = numDataCodewords; 29 | this.codewords = codewords; 30 | 31 | this.__defineGetter__("NumDataCodewords", function() 32 | { 33 | return this.numDataCodewords; 34 | }); 35 | this.__defineGetter__("Codewords", function() 36 | { 37 | return this.codewords; 38 | }); 39 | } 40 | 41 | DataBlock.getDataBlocks=function(rawCodewords, version, ecLevel) 42 | { 43 | 44 | if (rawCodewords.length != version.TotalCodewords) 45 | { 46 | throw "ArgumentException"; 47 | } 48 | 49 | // Figure out the number and size of data blocks used by this version and 50 | // error correction level 51 | var ecBlocks = version.getECBlocksForLevel(ecLevel); 52 | 53 | // First count the total number of data blocks 54 | var totalBlocks = 0; 55 | var ecBlockArray = ecBlocks.getECBlocks(); 56 | for (var i = 0; i < ecBlockArray.length; i++) 57 | { 58 | totalBlocks += ecBlockArray[i].Count; 59 | } 60 | 61 | // Now establish DataBlocks of the appropriate size and number of data codewords 62 | var result = new Array(totalBlocks); 63 | var numResultBlocks = 0; 64 | for (var j = 0; j < ecBlockArray.length; j++) 65 | { 66 | var ecBlock = ecBlockArray[j]; 67 | for (var i = 0; i < ecBlock.Count; i++) 68 | { 69 | var numDataCodewords = ecBlock.DataCodewords; 70 | var numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; 71 | result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords)); 72 | } 73 | } 74 | 75 | // All blocks have the same amount of data, except that the last n 76 | // (where n may be 0) have 1 more byte. Figure out where these start. 77 | var shorterBlocksTotalCodewords = result[0].codewords.length; 78 | var longerBlocksStartAt = result.length - 1; 79 | while (longerBlocksStartAt >= 0) 80 | { 81 | var numCodewords = result[longerBlocksStartAt].codewords.length; 82 | if (numCodewords == shorterBlocksTotalCodewords) 83 | { 84 | break; 85 | } 86 | longerBlocksStartAt--; 87 | } 88 | longerBlocksStartAt++; 89 | 90 | var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock; 91 | // The last elements of result may be 1 element longer; 92 | // first fill out as many elements as all of them have 93 | var rawCodewordsOffset = 0; 94 | for (var i = 0; i < shorterBlocksNumDataCodewords; i++) 95 | { 96 | for (var j = 0; j < numResultBlocks; j++) 97 | { 98 | result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; 99 | } 100 | } 101 | // Fill out the last data block in the longer ones 102 | for (var j = longerBlocksStartAt; j < numResultBlocks; j++) 103 | { 104 | result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; 105 | } 106 | // Now add in error correction blocks 107 | var max = result[0].codewords.length; 108 | for (var i = shorterBlocksNumDataCodewords; i < max; i++) 109 | { 110 | for (var j = 0; j < numResultBlocks; j++) 111 | { 112 | var iOffset = j < longerBlocksStartAt?i:i + 1; 113 | result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; 114 | } 115 | } 116 | return result; 117 | } 118 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/databr.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode) 27 | { 28 | this.blockPointer = 0; 29 | this.bitPointer = 7; 30 | this.dataLength = 0; 31 | this.blocks = blocks; 32 | this.numErrorCorrectionCode = numErrorCorrectionCode; 33 | if (version <= 9) 34 | this.dataLengthMode = 0; 35 | else if (version >= 10 && version <= 26) 36 | this.dataLengthMode = 1; 37 | else if (version >= 27 && version <= 40) 38 | this.dataLengthMode = 2; 39 | 40 | this.getNextBits = function( numBits) 41 | { 42 | var bits = 0; 43 | if (numBits < this.bitPointer + 1) 44 | { 45 | // next word fits into current data block 46 | var mask = 0; 47 | for (var i = 0; i < numBits; i++) 48 | { 49 | mask += (1 << i); 50 | } 51 | mask <<= (this.bitPointer - numBits + 1); 52 | 53 | bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1); 54 | this.bitPointer -= numBits; 55 | return bits; 56 | } 57 | else if (numBits < this.bitPointer + 1 + 8) 58 | { 59 | // next word crosses 2 data blocks 60 | var mask1 = 0; 61 | for (var i = 0; i < this.bitPointer + 1; i++) 62 | { 63 | mask1 += (1 << i); 64 | } 65 | bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); 66 | this.blockPointer++; 67 | bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1)))); 68 | 69 | this.bitPointer = this.bitPointer - numBits % 8; 70 | if (this.bitPointer < 0) 71 | { 72 | this.bitPointer = 8 + this.bitPointer; 73 | } 74 | return bits; 75 | } 76 | else if (numBits < this.bitPointer + 1 + 16) 77 | { 78 | // next word crosses 3 data blocks 79 | var mask1 = 0; // mask of first block 80 | var mask3 = 0; // mask of 3rd block 81 | //bitPointer + 1 : number of bits of the 1st block 82 | //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks) 83 | //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block 84 | for (var i = 0; i < this.bitPointer + 1; i++) 85 | { 86 | mask1 += (1 << i); 87 | } 88 | var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); 89 | this.blockPointer++; 90 | 91 | var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8)); 92 | this.blockPointer++; 93 | 94 | for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++) 95 | { 96 | mask3 += (1 << i); 97 | } 98 | mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8)); 99 | var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8))); 100 | 101 | bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock; 102 | this.bitPointer = this.bitPointer - (numBits - 8) % 8; 103 | if (this.bitPointer < 0) 104 | { 105 | this.bitPointer = 8 + this.bitPointer; 106 | } 107 | return bits; 108 | } 109 | else 110 | { 111 | return 0; 112 | } 113 | } 114 | this.NextMode=function() 115 | { 116 | if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2)) 117 | return 0; 118 | else 119 | return this.getNextBits(4); 120 | } 121 | this.getDataLength=function( modeIndicator) 122 | { 123 | var index = 0; 124 | while (true) 125 | { 126 | if ((modeIndicator >> index) == 1) 127 | break; 128 | index++; 129 | } 130 | 131 | return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]); 132 | } 133 | this.getRomanAndFigureString=function( dataLength) 134 | { 135 | var length = dataLength; 136 | var intData = 0; 137 | var strData = ""; 138 | var tableRomanAndFigure = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'); 139 | do 140 | { 141 | if (length > 1) 142 | { 143 | intData = this.getNextBits(11); 144 | var firstLetter = Math.floor(intData / 45); 145 | var secondLetter = intData % 45; 146 | strData += tableRomanAndFigure[firstLetter]; 147 | strData += tableRomanAndFigure[secondLetter]; 148 | length -= 2; 149 | } 150 | else if (length == 1) 151 | { 152 | intData = this.getNextBits(6); 153 | strData += tableRomanAndFigure[intData]; 154 | length -= 1; 155 | } 156 | } 157 | while (length > 0); 158 | 159 | return strData; 160 | } 161 | this.getFigureString=function( dataLength) 162 | { 163 | var length = dataLength; 164 | var intData = 0; 165 | var strData = ""; 166 | do 167 | { 168 | if (length >= 3) 169 | { 170 | intData = this.getNextBits(10); 171 | if (intData < 100) 172 | strData += "0"; 173 | if (intData < 10) 174 | strData += "0"; 175 | length -= 3; 176 | } 177 | else if (length == 2) 178 | { 179 | intData = this.getNextBits(7); 180 | if (intData < 10) 181 | strData += "0"; 182 | length -= 2; 183 | } 184 | else if (length == 1) 185 | { 186 | intData = this.getNextBits(4); 187 | length -= 1; 188 | } 189 | strData += intData; 190 | } 191 | while (length > 0); 192 | 193 | return strData; 194 | } 195 | this.get8bitByteArray=function( dataLength) 196 | { 197 | var length = dataLength; 198 | var intData = 0; 199 | var output = new Array(); 200 | 201 | do 202 | { 203 | intData = this.getNextBits(8); 204 | output.push( intData); 205 | length--; 206 | } 207 | while (length > 0); 208 | return output; 209 | } 210 | this.getKanjiString=function( dataLength) 211 | { 212 | var length = dataLength; 213 | var intData = 0; 214 | var unicodeString = ""; 215 | do 216 | { 217 | intData = getNextBits(13); 218 | var lowerByte = intData % 0xC0; 219 | var higherByte = intData / 0xC0; 220 | 221 | var tempWord = (higherByte << 8) + lowerByte; 222 | var shiftjisWord = 0; 223 | if (tempWord + 0x8140 <= 0x9FFC) 224 | { 225 | // between 8140 - 9FFC on Shift_JIS character set 226 | shiftjisWord = tempWord + 0x8140; 227 | } 228 | else 229 | { 230 | // between E040 - EBBF on Shift_JIS character set 231 | shiftjisWord = tempWord + 0xC140; 232 | } 233 | 234 | //var tempByte = new Array(0,0); 235 | //tempByte[0] = (sbyte) (shiftjisWord >> 8); 236 | //tempByte[1] = (sbyte) (shiftjisWord & 0xFF); 237 | //unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte))); 238 | unicodeString += String.fromCharCode(shiftjisWord); 239 | length--; 240 | } 241 | while (length > 0); 242 | 243 | 244 | return unicodeString; 245 | } 246 | 247 | this.__defineGetter__("DataByte", function() 248 | { 249 | var output = new Array(); 250 | var MODE_NUMBER = 1; 251 | var MODE_ROMAN_AND_NUMBER = 2; 252 | var MODE_8BIT_BYTE = 4; 253 | var MODE_KANJI = 8; 254 | do 255 | { 256 | var mode = this.NextMode(); 257 | //canvas.println("mode: " + mode); 258 | if (mode == 0) 259 | { 260 | if (output.length > 0) 261 | break; 262 | else 263 | throw "Empty data block"; 264 | } 265 | //if (mode != 1 && mode != 2 && mode != 4 && mode != 8) 266 | // break; 267 | //} 268 | if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI) 269 | { 270 | /* canvas.println("Invalid mode: " + mode); 271 | mode = guessMode(mode); 272 | canvas.println("Guessed mode: " + mode); */ 273 | throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")"; 274 | } 275 | dataLength = this.getDataLength(mode); 276 | if (dataLength < 1) 277 | throw "Invalid data length: " + dataLength; 278 | //canvas.println("length: " + dataLength); 279 | switch (mode) 280 | { 281 | 282 | case MODE_NUMBER: 283 | //canvas.println("Mode: Figure"); 284 | var temp_str = this.getFigureString(dataLength); 285 | var ta = new Array(temp_str.length); 286 | for(var j=0;j 7) 31 | { 32 | throw "System.ArgumentException"; 33 | } 34 | return DataMask.DATA_MASKS[reference]; 35 | } 36 | 37 | function DataMask000() 38 | { 39 | this.unmaskBitMatrix=function(bits, dimension) 40 | { 41 | for (var i = 0; i < dimension; i++) 42 | { 43 | for (var j = 0; j < dimension; j++) 44 | { 45 | if (this.isMasked(i, j)) 46 | { 47 | bits.flip(j, i); 48 | } 49 | } 50 | } 51 | } 52 | this.isMasked=function( i, j) 53 | { 54 | return ((i + j) & 0x01) == 0; 55 | } 56 | } 57 | 58 | function DataMask001() 59 | { 60 | this.unmaskBitMatrix=function(bits, dimension) 61 | { 62 | for (var i = 0; i < dimension; i++) 63 | { 64 | for (var j = 0; j < dimension; j++) 65 | { 66 | if (this.isMasked(i, j)) 67 | { 68 | bits.flip(j, i); 69 | } 70 | } 71 | } 72 | } 73 | this.isMasked=function( i, j) 74 | { 75 | return (i & 0x01) == 0; 76 | } 77 | } 78 | 79 | function DataMask010() 80 | { 81 | this.unmaskBitMatrix=function(bits, dimension) 82 | { 83 | for (var i = 0; i < dimension; i++) 84 | { 85 | for (var j = 0; j < dimension; j++) 86 | { 87 | if (this.isMasked(i, j)) 88 | { 89 | bits.flip(j, i); 90 | } 91 | } 92 | } 93 | } 94 | this.isMasked=function( i, j) 95 | { 96 | return j % 3 == 0; 97 | } 98 | } 99 | 100 | function DataMask011() 101 | { 102 | this.unmaskBitMatrix=function(bits, dimension) 103 | { 104 | for (var i = 0; i < dimension; i++) 105 | { 106 | for (var j = 0; j < dimension; j++) 107 | { 108 | if (this.isMasked(i, j)) 109 | { 110 | bits.flip(j, i); 111 | } 112 | } 113 | } 114 | } 115 | this.isMasked=function( i, j) 116 | { 117 | return (i + j) % 3 == 0; 118 | } 119 | } 120 | 121 | function DataMask100() 122 | { 123 | this.unmaskBitMatrix=function(bits, dimension) 124 | { 125 | for (var i = 0; i < dimension; i++) 126 | { 127 | for (var j = 0; j < dimension; j++) 128 | { 129 | if (this.isMasked(i, j)) 130 | { 131 | bits.flip(j, i); 132 | } 133 | } 134 | } 135 | } 136 | this.isMasked=function( i, j) 137 | { 138 | return (((URShift(i, 1)) + (j / 3)) & 0x01) == 0; 139 | } 140 | } 141 | 142 | function DataMask101() 143 | { 144 | this.unmaskBitMatrix=function(bits, dimension) 145 | { 146 | for (var i = 0; i < dimension; i++) 147 | { 148 | for (var j = 0; j < dimension; j++) 149 | { 150 | if (this.isMasked(i, j)) 151 | { 152 | bits.flip(j, i); 153 | } 154 | } 155 | } 156 | } 157 | this.isMasked=function( i, j) 158 | { 159 | var temp = i * j; 160 | return (temp & 0x01) + (temp % 3) == 0; 161 | } 162 | } 163 | 164 | function DataMask110() 165 | { 166 | this.unmaskBitMatrix=function(bits, dimension) 167 | { 168 | for (var i = 0; i < dimension; i++) 169 | { 170 | for (var j = 0; j < dimension; j++) 171 | { 172 | if (this.isMasked(i, j)) 173 | { 174 | bits.flip(j, i); 175 | } 176 | } 177 | } 178 | } 179 | this.isMasked=function( i, j) 180 | { 181 | var temp = i * j; 182 | return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; 183 | } 184 | } 185 | function DataMask111() 186 | { 187 | this.unmaskBitMatrix=function(bits, dimension) 188 | { 189 | for (var i = 0; i < dimension; i++) 190 | { 191 | for (var j = 0; j < dimension; j++) 192 | { 193 | if (this.isMasked(i, j)) 194 | { 195 | bits.flip(j, i); 196 | } 197 | } 198 | } 199 | } 200 | this.isMasked=function( i, j) 201 | { 202 | return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; 203 | } 204 | } 205 | 206 | DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111()); 207 | 208 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/decoder.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | Decoder={}; 27 | Decoder.rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD); 28 | 29 | Decoder.correctErrors=function( codewordBytes, numDataCodewords) 30 | { 31 | var numCodewords = codewordBytes.length; 32 | // First read into an array of ints 33 | var codewordsInts = new Array(numCodewords); 34 | for (var i = 0; i < numCodewords; i++) 35 | { 36 | codewordsInts[i] = codewordBytes[i] & 0xFF; 37 | } 38 | var numECCodewords = codewordBytes.length - numDataCodewords; 39 | try 40 | { 41 | Decoder.rsDecoder.decode(codewordsInts, numECCodewords); 42 | //var corrector = new ReedSolomon(codewordsInts, numECCodewords); 43 | //corrector.correct(); 44 | } 45 | catch ( rse) 46 | { 47 | throw rse; 48 | } 49 | // Copy back into array of bytes -- only need to worry about the bytes that were data 50 | // We don't care about errors in the error-correction codewords 51 | for (var i = 0; i < numDataCodewords; i++) 52 | { 53 | codewordBytes[i] = codewordsInts[i]; 54 | } 55 | } 56 | 57 | Decoder.decode=function(bits) 58 | { 59 | var parser = new BitMatrixParser(bits); 60 | var version = parser.readVersion(); 61 | var ecLevel = parser.readFormatInformation().ErrorCorrectionLevel; 62 | 63 | // Read codewords 64 | var codewords = parser.readCodewords(); 65 | 66 | // Separate into data blocks 67 | var dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); 68 | 69 | // Count total number of data bytes 70 | var totalBytes = 0; 71 | for (var i = 0; i < dataBlocks.length; i++) 72 | { 73 | totalBytes += dataBlocks[i].NumDataCodewords; 74 | } 75 | var resultBytes = new Array(totalBytes); 76 | var resultOffset = 0; 77 | 78 | // Error-correct and copy data blocks together into a stream of bytes 79 | for (var j = 0; j < dataBlocks.length; j++) 80 | { 81 | var dataBlock = dataBlocks[j]; 82 | var codewordBytes = dataBlock.Codewords; 83 | var numDataCodewords = dataBlock.NumDataCodewords; 84 | Decoder.correctErrors(codewordBytes, numDataCodewords); 85 | for (var i = 0; i < numDataCodewords; i++) 86 | { 87 | resultBytes[resultOffset++] = codewordBytes[i]; 88 | } 89 | } 90 | 91 | // Decode the contents of that stream of bytes 92 | var reader = new QRCodeDataBlockReader(resultBytes, version.VersionNumber, ecLevel.Bits); 93 | return reader; 94 | //return DecodedBitStreamParser.decode(resultBytes, version, ecLevel); 95 | } 96 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/errorlevel.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function ErrorCorrectionLevel(ordinal, bits, name) 27 | { 28 | this.ordinal_Renamed_Field = ordinal; 29 | this.bits = bits; 30 | this.name = name; 31 | this.__defineGetter__("Bits", function() 32 | { 33 | return this.bits; 34 | }); 35 | this.__defineGetter__("Name", function() 36 | { 37 | return this.name; 38 | }); 39 | this.ordinal=function() 40 | { 41 | return this.ordinal_Renamed_Field; 42 | } 43 | } 44 | 45 | ErrorCorrectionLevel.forBits=function( bits) 46 | { 47 | if (bits < 0 || bits >= FOR_BITS.length) 48 | { 49 | throw "ArgumentException"; 50 | } 51 | return FOR_BITS[bits]; 52 | } 53 | 54 | var L = new ErrorCorrectionLevel(0, 0x01, "L"); 55 | var M = new ErrorCorrectionLevel(1, 0x00, "M"); 56 | var Q = new ErrorCorrectionLevel(2, 0x03, "Q"); 57 | var H = new ErrorCorrectionLevel(3, 0x02, "H"); 58 | var FOR_BITS = new Array( M, L, H, Q); 59 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/formatinf.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | var FORMAT_INFO_MASK_QR = 0x5412; 27 | var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F)); 28 | var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); 29 | 30 | 31 | function FormatInformation(formatInfo) 32 | { 33 | this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); 34 | this.dataMask = (formatInfo & 0x07); 35 | 36 | this.__defineGetter__("ErrorCorrectionLevel", function() 37 | { 38 | return this.errorCorrectionLevel; 39 | }); 40 | this.__defineGetter__("DataMask", function() 41 | { 42 | return this.dataMask; 43 | }); 44 | this.GetHashCode=function() 45 | { 46 | return (this.errorCorrectionLevel.ordinal() << 3) | dataMask; 47 | } 48 | this.Equals=function( o) 49 | { 50 | var other = o; 51 | return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; 52 | } 53 | } 54 | 55 | FormatInformation.numBitsDiffering=function( a, b) 56 | { 57 | a ^= b; // a now has a 1 bit exactly where its bit differs with b's 58 | // Count bits set quickly with a series of lookups: 59 | return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 28) & 0x0F)]; 60 | } 61 | 62 | FormatInformation.decodeFormatInformation=function( maskedFormatInfo) 63 | { 64 | var formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo); 65 | if (formatInfo != null) 66 | { 67 | return formatInfo; 68 | } 69 | // Should return null, but, some QR codes apparently 70 | // do not mask this info. Try again by actually masking the pattern 71 | // first 72 | return FormatInformation.doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR); 73 | } 74 | FormatInformation.doDecodeFormatInformation=function( maskedFormatInfo) 75 | { 76 | // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing 77 | var bestDifference = 0xffffffff; 78 | var bestFormatInfo = 0; 79 | for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) 80 | { 81 | var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; 82 | var targetInfo = decodeInfo[0]; 83 | if (targetInfo == maskedFormatInfo) 84 | { 85 | // Found an exact match 86 | return new FormatInformation(decodeInfo[1]); 87 | } 88 | var bitsDifference = this.numBitsDiffering(maskedFormatInfo, targetInfo); 89 | if (bitsDifference < bestDifference) 90 | { 91 | bestFormatInfo = decodeInfo[1]; 92 | bestDifference = bitsDifference; 93 | } 94 | } 95 | // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits 96 | // differing means we found a match 97 | if (bestDifference <= 3) 98 | { 99 | return new FormatInformation(bestFormatInfo); 100 | } 101 | return null; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/gf256.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function GF256( primitive) 27 | { 28 | this.expTable = new Array(256); 29 | this.logTable = new Array(256); 30 | var x = 1; 31 | for (var i = 0; i < 256; i++) 32 | { 33 | this.expTable[i] = x; 34 | x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 35 | if (x >= 0x100) 36 | { 37 | x ^= primitive; 38 | } 39 | } 40 | for (var i = 0; i < 255; i++) 41 | { 42 | this.logTable[this.expTable[i]] = i; 43 | } 44 | // logTable[0] == 0 but this should never be used 45 | var at0=new Array(1);at0[0]=0; 46 | this.zero = new GF256Poly(this, new Array(at0)); 47 | var at1=new Array(1);at1[0]=1; 48 | this.one = new GF256Poly(this, new Array(at1)); 49 | 50 | this.__defineGetter__("Zero", function() 51 | { 52 | return this.zero; 53 | }); 54 | this.__defineGetter__("One", function() 55 | { 56 | return this.one; 57 | }); 58 | this.buildMonomial=function( degree, coefficient) 59 | { 60 | if (degree < 0) 61 | { 62 | throw "System.ArgumentException"; 63 | } 64 | if (coefficient == 0) 65 | { 66 | return zero; 67 | } 68 | var coefficients = new Array(degree + 1); 69 | for(var i=0;i 1 && coefficients[0] == 0) 35 | { 36 | // Leading term must be non-zero for anything except the constant polynomial "0" 37 | var firstNonZero = 1; 38 | while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) 39 | { 40 | firstNonZero++; 41 | } 42 | if (firstNonZero == coefficientsLength) 43 | { 44 | this.coefficients = field.Zero.coefficients; 45 | } 46 | else 47 | { 48 | this.coefficients = new Array(coefficientsLength - firstNonZero); 49 | for(var i=0;i largerCoefficients.length) 121 | { 122 | var temp = smallerCoefficients; 123 | smallerCoefficients = largerCoefficients; 124 | largerCoefficients = temp; 125 | } 126 | var sumDiff = new Array(largerCoefficients.length); 127 | var lengthDiff = largerCoefficients.length - smallerCoefficients.length; 128 | // Copy high-order terms only found in higher-degree polynomial's coefficients 129 | //Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); 130 | for(var ci=0;ci= other.Degree && !remainder.Zero) 219 | { 220 | var degreeDifference = remainder.Degree - other.Degree; 221 | var scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm); 222 | var term = other.multiplyByMonomial(degreeDifference, scale); 223 | var iterationQuotient = this.field.buildMonomial(degreeDifference, scale); 224 | quotient = quotient.addOrSubtract(iterationQuotient); 225 | remainder = remainder.addOrSubtract(term); 226 | } 227 | 228 | return new Array(quotient, remainder); 229 | } 230 | } -------------------------------------------------------------------------------- /public/src/js/jsqrcode/grid.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | GridSampler = {}; 27 | 28 | GridSampler.checkAndNudgePoints=function( image, points) 29 | { 30 | var width = qrcode.width; 31 | var height = qrcode.height; 32 | // Check and nudge points from start until we see some that are OK: 33 | var nudged = true; 34 | for (var offset = 0; offset < points.length && nudged; offset += 2) 35 | { 36 | var x = Math.floor (points[offset]); 37 | var y = Math.floor( points[offset + 1]); 38 | if (x < - 1 || x > width || y < - 1 || y > height) 39 | { 40 | throw "Error.checkAndNudgePoints "; 41 | } 42 | nudged = false; 43 | if (x == - 1) 44 | { 45 | points[offset] = 0.0; 46 | nudged = true; 47 | } 48 | else if (x == width) 49 | { 50 | points[offset] = width - 1; 51 | nudged = true; 52 | } 53 | if (y == - 1) 54 | { 55 | points[offset + 1] = 0.0; 56 | nudged = true; 57 | } 58 | else if (y == height) 59 | { 60 | points[offset + 1] = height - 1; 61 | nudged = true; 62 | } 63 | } 64 | // Check and nudge points from end: 65 | nudged = true; 66 | for (var offset = points.length - 2; offset >= 0 && nudged; offset -= 2) 67 | { 68 | var x = Math.floor( points[offset]); 69 | var y = Math.floor( points[offset + 1]); 70 | if (x < - 1 || x > width || y < - 1 || y > height) 71 | { 72 | throw "Error.checkAndNudgePoints "; 73 | } 74 | nudged = false; 75 | if (x == - 1) 76 | { 77 | points[offset] = 0.0; 78 | nudged = true; 79 | } 80 | else if (x == width) 81 | { 82 | points[offset] = width - 1; 83 | nudged = true; 84 | } 85 | if (y == - 1) 86 | { 87 | points[offset + 1] = 0.0; 88 | nudged = true; 89 | } 90 | else if (y == height) 91 | { 92 | points[offset + 1] = height - 1; 93 | nudged = true; 94 | } 95 | } 96 | } 97 | 98 | 99 | 100 | GridSampler.sampleGrid3=function( image, dimension, transform) 101 | { 102 | var bits = new BitMatrix(dimension); 103 | var points = new Array(dimension << 1); 104 | for (var y = 0; y < dimension; y++) 105 | { 106 | var max = points.length; 107 | var iValue = y + 0.5; 108 | for (var x = 0; x < max; x += 2) 109 | { 110 | points[x] = (x >> 1) + 0.5; 111 | points[x + 1] = iValue; 112 | } 113 | transform.transformPoints1(points); 114 | // Quick check to see if points transformed to something inside the image; 115 | // sufficient to check the endpoints 116 | GridSampler.checkAndNudgePoints(image, points); 117 | try 118 | { 119 | for (var x = 0; x < max; x += 2) 120 | { 121 | var xpoint = (Math.floor( points[x]) * 4) + (Math.floor( points[x + 1]) * qrcode.width * 4); 122 | var bit = image[Math.floor( points[x])+ qrcode.width* Math.floor( points[x + 1])]; 123 | qrcode.imagedata.data[xpoint] = bit?255:0; 124 | qrcode.imagedata.data[xpoint+1] = bit?255:0; 125 | qrcode.imagedata.data[xpoint+2] = 0; 126 | qrcode.imagedata.data[xpoint+3] = 255; 127 | //bits[x >> 1][ y]=bit; 128 | if(bit) 129 | bits.set_Renamed(x >> 1, y); 130 | } 131 | } 132 | catch ( aioobe) 133 | { 134 | // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting 135 | // transform gets "twisted" such that it maps a straight line of points to a set of points 136 | // whose endpoints are in bounds, but others are not. There is probably some mathematical 137 | // way to detect this about the transformation that I don't know yet. 138 | // This results in an ugly runtime exception despite our clever checks above -- can't have 139 | // that. We could check each point's coordinates but that feels duplicative. We settle for 140 | // catching and wrapping ArrayIndexOutOfBoundsException. 141 | throw "Error.checkAndNudgePoints"; 142 | } 143 | } 144 | return bits; 145 | } 146 | 147 | GridSampler.sampleGridx=function( image, dimension, p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY) 148 | { 149 | var transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); 150 | 151 | return GridSampler.sampleGrid3(image, dimension, transform); 152 | } 153 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/qrcode.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Lazar Laszlo (lazarsoft@gmail.com, www.lazarsoft.info) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | 18 | qrcode = window.qrcode || {}; 19 | qrcode.imagedata = null; 20 | qrcode.width = 0; 21 | qrcode.height = 0; 22 | qrcode.qrCodeSymbol = null; 23 | qrcode.debug = false; 24 | qrcode.maxImgSize = 1024*1024; 25 | 26 | qrcode.sizeOfDataLengthInfo = [ [ 10, 9, 8, 8 ], [ 12, 11, 16, 10 ], [ 14, 13, 16, 12 ] ]; 27 | 28 | qrcode.callback = null; 29 | 30 | qrcode.decode = function(src){ 31 | 32 | if(arguments.length==0) 33 | { 34 | var canvas_qr = document.getElementById("qr-canvas"); 35 | var context = canvas_qr.getContext('2d'); 36 | qrcode.width = canvas_qr.width; 37 | qrcode.height = canvas_qr.height; 38 | qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height); 39 | qrcode.result = qrcode.process(context); 40 | if(qrcode.callback!=null) 41 | qrcode.callback(qrcode.result); 42 | return qrcode.result; 43 | } 44 | else 45 | { 46 | var image = new Image(); 47 | image.onload=function(){ 48 | //var canvas_qr = document.getElementById("qr-canvas"); 49 | var canvas_qr = document.createElement('canvas'); 50 | var context = canvas_qr.getContext('2d'); 51 | var nheight = image.height; 52 | var nwidth = image.width; 53 | if(image.width*image.height>qrcode.maxImgSize) 54 | { 55 | var ir = image.width / image.height; 56 | nheight = Math.sqrt(qrcode.maxImgSize/ir); 57 | nwidth=ir*nheight; 58 | } 59 | 60 | canvas_qr.width = nwidth; 61 | canvas_qr.height = nheight; 62 | 63 | context.drawImage(image, 0, 0, canvas_qr.width, canvas_qr.height ); 64 | qrcode.width = canvas_qr.width; 65 | qrcode.height = canvas_qr.height; 66 | try{ 67 | qrcode.imagedata = context.getImageData(0, 0, canvas_qr.width, canvas_qr.height); 68 | }catch(e){ 69 | qrcode.result = "Cross domain image reading not supported in your browser! Save it to your computer then drag and drop the file!"; 70 | if(qrcode.callback!=null) 71 | qrcode.callback(qrcode.result); 72 | return; 73 | } 74 | 75 | try 76 | { 77 | qrcode.result = qrcode.process(context); 78 | } 79 | catch(e) 80 | { 81 | console.log(e); 82 | qrcode.result = "error decoding QR Code"; 83 | } 84 | if(qrcode.callback!=null) 85 | qrcode.callback(qrcode.result); 86 | } 87 | image.src = src; 88 | } 89 | } 90 | 91 | qrcode.isUrl = function(s) 92 | { 93 | var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; 94 | return regexp.test(s); 95 | } 96 | 97 | qrcode.decode_url = function (s) 98 | { 99 | var escaped = ""; 100 | try{ 101 | escaped = escape( s ); 102 | } 103 | catch(e) 104 | { 105 | console.log(e); 106 | escaped = s; 107 | } 108 | var ret = ""; 109 | try{ 110 | ret = decodeURIComponent( escaped ); 111 | } 112 | catch(e) 113 | { 114 | console.log(e); 115 | ret = escaped; 116 | } 117 | return ret; 118 | } 119 | 120 | qrcode.decode_utf8 = function ( s ) 121 | { 122 | if(qrcode.isUrl(s)) 123 | return qrcode.decode_url(s); 124 | else 125 | return s; 126 | } 127 | 128 | qrcode.process = function(ctx){ 129 | 130 | var start = new Date().getTime(); 131 | 132 | var image = qrcode.grayScaleToBitmap(qrcode.grayscale()); 133 | //var image = qrcode.binarize(128); 134 | 135 | if(qrcode.debug) 136 | { 137 | for (var y = 0; y < qrcode.height; y++) 138 | { 139 | for (var x = 0; x < qrcode.width; x++) 140 | { 141 | var point = (x * 4) + (y * qrcode.width * 4); 142 | qrcode.imagedata.data[point] = image[x+y*qrcode.width]?0:0; 143 | qrcode.imagedata.data[point+1] = image[x+y*qrcode.width]?0:0; 144 | qrcode.imagedata.data[point+2] = image[x+y*qrcode.width]?255:0; 145 | } 146 | } 147 | ctx.putImageData(qrcode.imagedata, 0, 0); 148 | } 149 | 150 | //var finderPatternInfo = new FinderPatternFinder().findFinderPattern(image); 151 | 152 | var detector = new Detector(image); 153 | 154 | var qRCodeMatrix = detector.detect(); 155 | 156 | /*for (var y = 0; y < qRCodeMatrix.bits.Height; y++) 157 | { 158 | for (var x = 0; x < qRCodeMatrix.bits.Width; x++) 159 | { 160 | var point = (x * 4*2) + (y*2 * qrcode.width * 4); 161 | qrcode.imagedata.data[point] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0; 162 | qrcode.imagedata.data[point+1] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0; 163 | qrcode.imagedata.data[point+2] = qRCodeMatrix.bits.get_Renamed(x,y)?255:0; 164 | } 165 | }*/ 166 | if(qrcode.debug) 167 | ctx.putImageData(qrcode.imagedata, 0, 0); 168 | 169 | var reader = Decoder.decode(qRCodeMatrix.bits); 170 | var data = reader.DataByte; 171 | var str=""; 172 | for(var i=0;i minmax[ax][ay][1]) 240 | minmax[ax][ay][1] = target; 241 | } 242 | } 243 | //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2; 244 | } 245 | } 246 | var middle = new Array(numSqrtArea); 247 | for (var i3 = 0; i3 < numSqrtArea; i3++) 248 | { 249 | middle[i3] = new Array(numSqrtArea); 250 | } 251 | for (var ay = 0; ay < numSqrtArea; ay++) 252 | { 253 | for (var ax = 0; ax < numSqrtArea; ax++) 254 | { 255 | middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2); 256 | //Console.out.print(middle[ax][ay] + ","); 257 | } 258 | //Console.out.println(""); 259 | } 260 | //Console.out.println(""); 261 | 262 | return middle; 263 | } 264 | 265 | qrcode.grayScaleToBitmap=function(grayScale) 266 | { 267 | var middle = qrcode.getMiddleBrightnessPerArea(grayScale); 268 | var sqrtNumArea = middle.length; 269 | var areaWidth = Math.floor(qrcode.width / sqrtNumArea); 270 | var areaHeight = Math.floor(qrcode.height / sqrtNumArea); 271 | var bitmap = new Array(qrcode.height*qrcode.width); 272 | 273 | for (var ay = 0; ay < sqrtNumArea; ay++) 274 | { 275 | for (var ax = 0; ax < sqrtNumArea; ax++) 276 | { 277 | for (var dy = 0; dy < areaHeight; dy++) 278 | { 279 | for (var dx = 0; dx < areaWidth; dx++) 280 | { 281 | bitmap[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] = (grayScale[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] < middle[ax][ay])?true:false; 282 | } 283 | } 284 | } 285 | } 286 | return bitmap; 287 | } 288 | 289 | qrcode.grayscale = function(){ 290 | var ret = new Array(qrcode.width*qrcode.height); 291 | for (var y = 0; y < qrcode.height; y++) 292 | { 293 | for (var x = 0; x < qrcode.width; x++) 294 | { 295 | var gray = qrcode.getPixel(x, y); 296 | 297 | ret[x+y*qrcode.width] = gray; 298 | } 299 | } 300 | return ret; 301 | } 302 | 303 | 304 | 305 | 306 | function URShift( number, bits) 307 | { 308 | if (number >= 0) 309 | return number >> bits; 310 | else 311 | return (number >> bits) + (2 << ~bits); 312 | } 313 | 314 | 315 | Array.prototype.remove = function(from, to) { 316 | var rest = this.slice((to || from) + 1 || this.length); 317 | this.length = from < 0 ? this.length + from : from; 318 | return this.push.apply(this, rest); 319 | }; 320 | -------------------------------------------------------------------------------- /public/src/js/jsqrcode/rsdecoder.js: -------------------------------------------------------------------------------- 1 | /* 2 | Ported to JavaScript by Lazar Laszlo 2011 3 | 4 | lazarsoft@gmail.com, www.lazarsoft.info 5 | 6 | */ 7 | 8 | /* 9 | * 10 | * Copyright 2007 ZXing authors 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | function ReedSolomonDecoder(field) 27 | { 28 | this.field = field; 29 | this.decode=function(received, twoS) 30 | { 31 | var poly = new GF256Poly(this.field, received); 32 | var syndromeCoefficients = new Array(twoS); 33 | for(var i=0;i= b's 70 | if (a.Degree < b.Degree) 71 | { 72 | var temp = a; 73 | a = b; 74 | b = temp; 75 | } 76 | 77 | var rLast = a; 78 | var r = b; 79 | var sLast = this.field.One; 80 | var s = this.field.Zero; 81 | var tLast = this.field.Zero; 82 | var t = this.field.One; 83 | 84 | // Run Euclidean algorithm until r's degree is less than R/2 85 | while (r.Degree >= Math.floor(R / 2)) 86 | { 87 | var rLastLast = rLast; 88 | var sLastLast = sLast; 89 | var tLastLast = tLast; 90 | rLast = r; 91 | sLast = s; 92 | tLast = t; 93 | 94 | // Divide rLastLast by rLast, with quotient in q and remainder in r 95 | if (rLast.Zero) 96 | { 97 | // Oops, Euclidean algorithm already terminated? 98 | throw "r_{i-1} was zero"; 99 | } 100 | r = rLastLast; 101 | var q = this.field.Zero; 102 | var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); 103 | var dltInverse = this.field.inverse(denominatorLeadingTerm); 104 | while (r.Degree >= rLast.Degree && !r.Zero) 105 | { 106 | var degreeDiff = r.Degree - rLast.Degree; 107 | var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse); 108 | q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale)); 109 | r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); 110 | //r.EXE(); 111 | } 112 | 113 | s = q.multiply1(sLast).addOrSubtract(sLastLast); 114 | t = q.multiply1(tLast).addOrSubtract(tLastLast); 115 | } 116 | 117 | var sigmaTildeAtZero = t.getCoefficient(0); 118 | if (sigmaTildeAtZero == 0) 119 | { 120 | throw "ReedSolomonException sigmaTilde(0) was zero"; 121 | } 122 | 123 | var inverse = this.field.inverse(sigmaTildeAtZero); 124 | var sigma = t.multiply2(inverse); 125 | var omega = r.multiply2(inverse); 126 | return new Array(sigma, omega); 127 | } 128 | this.findErrorLocations=function( errorLocator) 129 | { 130 | // This is a direct application of Chien's search 131 | var numErrors = errorLocator.Degree; 132 | if (numErrors == 1) 133 | { 134 | // shortcut 135 | return new Array(errorLocator.getCoefficient(1)); 136 | } 137 | var result = new Array(numErrors); 138 | var e = 0; 139 | for (var i = 1; i < 256 && e < numErrors; i++) 140 | { 141 | if (errorLocator.evaluateAt(i) == 0) 142 | { 143 | result[e] = this.field.inverse(i); 144 | e++; 145 | } 146 | } 147 | if (e != numErrors) 148 | { 149 | throw "Error locator degree does not match number of roots"; 150 | } 151 | return result; 152 | } 153 | this.findErrorMagnitudes=function( errorEvaluator, errorLocations, dataMatrix) 154 | { 155 | // This is directly applying Forney's Formula 156 | var s = errorLocations.length; 157 | var result = new Array(s); 158 | for (var i = 0; i < s; i++) 159 | { 160 | var xiInverse = this.field.inverse(errorLocations[i]); 161 | var denominator = 1; 162 | for (var j = 0; j < s; j++) 163 | { 164 | if (i != j) 165 | { 166 | denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse))); 167 | } 168 | } 169 | result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator)); 170 | // Thanks to sanfordsquires for this fix: 171 | if (dataMatrix) 172 | { 173 | result[i] = this.field.multiply(result[i], xiInverse); 174 | } 175 | } 176 | return result; 177 | } 178 | } -------------------------------------------------------------------------------- /public/src/js/jsqrcode/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | QRCODE 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 131 | 132 | 133 | 134 | 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 |
145 |
146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /public/src/js/services/address.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.address').factory('Address', 4 | function($resource) { 5 | return $resource(window.apiPrefix + '/addr/:addrStr/?noTxList=1', { 6 | addrStr: '@addStr' 7 | }, { 8 | get: { 9 | method: 'GET', 10 | interceptor: { 11 | response: function (res) { 12 | return res.data; 13 | }, 14 | responseError: function (res) { 15 | if (res.status === 404) { 16 | return res; 17 | } 18 | } 19 | } 20 | } 21 | }); 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /public/src/js/services/blocks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.blocks') 4 | .factory('Block', 5 | function($resource) { 6 | return $resource(window.apiPrefix + '/block/:blockHash', { 7 | blockHash: '@blockHash' 8 | }, { 9 | get: { 10 | method: 'GET', 11 | interceptor: { 12 | response: function (res) { 13 | return res.data; 14 | }, 15 | responseError: function (res) { 16 | if (res.status === 404) { 17 | return res; 18 | } 19 | } 20 | } 21 | } 22 | }); 23 | }) 24 | .factory('Blocks', 25 | function($resource) { 26 | return $resource(window.apiPrefix + '/blocks'); 27 | }) 28 | .factory('BlockByHeight', 29 | function($resource) { 30 | return $resource(window.apiPrefix + '/block-index/:blockHeight'); 31 | }); 32 | -------------------------------------------------------------------------------- /public/src/js/services/charts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.charts') 4 | .factory('Chart', 5 | function($resource) { 6 | return $resource(window.apiPrefix + '/chart/:chartType', { 7 | chartType: '@chartType' 8 | }, { 9 | get: { 10 | method: 'GET', 11 | interceptor: { 12 | response: function (res) { 13 | return res.data; 14 | }, 15 | responseError: function (res) { 16 | if (res.status === 404) { 17 | return res; 18 | } 19 | } 20 | } 21 | } 22 | }); 23 | }) 24 | .factory('Charts', 25 | function($resource) { 26 | return $resource(window.apiPrefix + '/charts'); 27 | }); 28 | -------------------------------------------------------------------------------- /public/src/js/services/currency.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.currency').factory('Currency', 4 | function($resource) { 5 | return $resource(window.apiPrefix + '/currency'); 6 | }); 7 | -------------------------------------------------------------------------------- /public/src/js/services/global.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //Global service for global variables 4 | angular.module('insight.system') 5 | .factory('Global',[ 6 | function() { 7 | return {}; 8 | } 9 | ]) 10 | .factory('Version', 11 | function($resource) { 12 | return $resource(window.apiPrefix + '/version'); 13 | }); 14 | -------------------------------------------------------------------------------- /public/src/js/services/socket.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ScopedSocket = function(socket, $rootScope) { 4 | this.socket = socket; 5 | this.$rootScope = $rootScope; 6 | this.listeners = []; 7 | }; 8 | 9 | ScopedSocket.prototype.removeAllListeners = function(opts) { 10 | if (!opts) opts = {}; 11 | for (var i = 0; i < this.listeners.length; i++) { 12 | var details = this.listeners[i]; 13 | if (opts.skipConnect && details.event === 'connect') { 14 | continue; 15 | } 16 | this.socket.removeListener(details.event, details.fn); 17 | } 18 | this.listeners = []; 19 | }; 20 | 21 | ScopedSocket.prototype.on = function(event, callback) { 22 | var socket = this.socket; 23 | var $rootScope = this.$rootScope; 24 | 25 | var wrapped_callback = function() { 26 | var args = arguments; 27 | $rootScope.$apply(function() { 28 | callback.apply(socket, args); 29 | }); 30 | }; 31 | socket.on(event, wrapped_callback); 32 | 33 | this.listeners.push({ 34 | event: event, 35 | fn: wrapped_callback 36 | }); 37 | }; 38 | 39 | ScopedSocket.prototype.emit = function(event, data, callback) { 40 | var socket = this.socket; 41 | var $rootScope = this.$rootScope; 42 | var args = Array.prototype.slice.call(arguments); 43 | 44 | args.push(function() { 45 | var args = arguments; 46 | $rootScope.$apply(function() { 47 | if (callback) { 48 | callback.apply(socket, args); 49 | } 50 | }); 51 | }); 52 | 53 | socket.emit.apply(socket, args); 54 | }; 55 | 56 | angular.module('insight.socket').factory('getSocket', 57 | function($rootScope) { 58 | var socket = io.connect(null, { 59 | 'reconnect': true, 60 | 'reconnection delay': 500, 61 | }); 62 | return function(scope) { 63 | var scopedSocket = new ScopedSocket(socket, $rootScope); 64 | scope.$on('$destroy', function() { 65 | scopedSocket.removeAllListeners(); 66 | }); 67 | socket.on('connect', function() { 68 | scopedSocket.removeAllListeners({ 69 | skipConnect: true 70 | }); 71 | }); 72 | return scopedSocket; 73 | }; 74 | }); 75 | -------------------------------------------------------------------------------- /public/src/js/services/status.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.status') 4 | .factory('Status', 5 | function($resource) { 6 | return $resource(window.apiPrefix + '/status', { 7 | q: '@q' 8 | }); 9 | }) 10 | .factory('Sync', 11 | function($resource) { 12 | return $resource(window.apiPrefix + '/sync'); 13 | }) 14 | .factory('PeerSync', 15 | function($resource) { 16 | return $resource(window.apiPrefix + '/peer'); 17 | }); 18 | -------------------------------------------------------------------------------- /public/src/js/services/transactions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('insight.transactions') 4 | .factory('Transaction', 5 | function($resource) { 6 | return $resource(window.apiPrefix + '/tx/:txId', { 7 | txId: '@txId' 8 | }, { 9 | get: { 10 | method: 'GET', 11 | interceptor: { 12 | response: function (res) { 13 | return res.data; 14 | }, 15 | responseError: function (res) { 16 | if (res.status === 404) { 17 | return res; 18 | } 19 | } 20 | } 21 | } 22 | }); 23 | }) 24 | .factory('TransactionsByBlock', 25 | function($resource) { 26 | return $resource(window.apiPrefix + '/txs', { 27 | block: '@block' 28 | }); 29 | }) 30 | .factory('TransactionsByAddress', 31 | function($resource) { 32 | return $resource(window.apiPrefix + '/txs', { 33 | address: '@address' 34 | }); 35 | }) 36 | .factory('Transactions', 37 | function($resource) { 38 | return $resource(window.apiPrefix + '/txs'); 39 | }); 40 | -------------------------------------------------------------------------------- /public/views/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Ooops!

4 |

404 Page not found :(

5 |

Go to home

6 |
7 | -------------------------------------------------------------------------------- /public/views/address.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 20 |

Address {{$root.currency.getConvertion(address.balance)}}

21 |
22 | Loading Address Information 23 |
24 |
25 |
26 | Address 27 | {{address.addrStr}} 28 | 29 |
30 |

Summary confirmed

31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
Total Received{{$root.currency.getConvertion(address.totalReceived)}}
Total Sent{{$root.currency.getConvertion(address.totalSent)}}
Final Balance{{$root.currency.getConvertion(address.balance)}}
No. Transactions{{address.txApperances}}
53 |
54 |
55 | 56 |
57 |
58 |
59 |

Unconfirmed

60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
Unconfirmed Txs Balance{{$root.currency.getConvertion(address.unconfirmedBalance)}}
No. Transactions{{address.unconfirmedTxApperances}}
73 |
74 |
75 |
76 |

Transactions

77 |
78 |
79 |
80 | 81 | -------------------------------------------------------------------------------- /public/views/block.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 34 |

Block #{{block.height}}

35 |
36 | Loading Block Information 37 |
38 |
39 |
40 | BlockHash 41 | {{block.hash}} 42 | 43 |
44 |

Summary

45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 73 | 74 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
Number Of Transactions{{block.tx.length}}
Height{{block.height}} 56 | (Mainchain) 57 | (Orphaned) 58 |
Block Reward{{$root.currency.getConvertion(block.reward)}}
Timestamp{{block.time * 1000 | date:'medium'}}
Mined by 71 | {{block.poolInfo.poolName}} 72 |
Merkle Root 77 |
78 | 79 | {{block.merkleroot}} 80 |
81 |
Previous Block{{block.height-1}}
89 |
90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 117 | 118 | 119 | 120 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |
Difficulty{{block.difficulty}}
Bits{{block.bits}}
Size (bytes){{block.size}}
Version{{block.version}}
Nonce 112 |
113 | 114 | {{block.nonce}} 115 |
116 |
Solution 121 |
122 | 123 | {{block.solution}} 124 |
125 |
Next Block{{block.height+1}}
133 |
134 |
135 |
136 |
137 |

Transactions

138 |
139 |
140 | 141 |
142 | 143 | -------------------------------------------------------------------------------- /public/views/block_list.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | 8 |

Blocks
9 | mined on:

10 |
11 |
12 |

13 | {{pagination.current}} UTC 14 | 15 |

16 |
17 | Loading Selected Date... 18 |
19 |
20 |

 

21 |

Today

22 |

{{humanSince(pagination.currentTs)}} 23 |

 

24 | 28 |
29 |
30 |
31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
HeightTimestampTransactionsSize
Waiting for blocks...
{{b.height}}{{b.time * 1000 | date:'medium'}}{{b.txlength}}{{b.size}}
60 | 64 |
65 |
66 |

No blocks yet.

68 |
69 | 70 | -------------------------------------------------------------------------------- /public/views/charts.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /public/views/dummy-translations.html: -------------------------------------------------------------------------------- 1 | {{'Blocks'|translate}} 2 | {{'Status'|translate}} 3 | -------------------------------------------------------------------------------- /public/views/includes/connection.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
6 | 7 | Error! 8 | 9 |

10 | Can't connect to zcashd to get live updates from the p2p network. (Tried connecting to zcashd at {{host}}:{{port}} and failed.) 11 |

12 | 13 |

14 | Can't connect to insight server. Attempting to reconnect... 15 |

16 | 17 |

18 | Can't connect to internet. Please, check your connection. 19 |

20 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /public/views/includes/currency.html: -------------------------------------------------------------------------------- 1 |
2 | {{currency.symbol}} 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /public/views/includes/header.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 | 47 |
48 |
49 | -------------------------------------------------------------------------------- /public/views/includes/infoStatus.html: -------------------------------------------------------------------------------- 1 | Loading... 2 | {{error}} 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/views/includes/search.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /public/views/index.html: -------------------------------------------------------------------------------- 1 |
2 | {{$root.flashMessage}} 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |

Latest Blocks

13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
HeightAgeTransactionsSize
Waiting for blocks...
27 | {{b.height}} 28 | {{humanSince(b.time)}}{{b.txlength}}{{b.size}}
36 |
37 | See all blocks 38 |
39 | 40 |

Latest Transactions

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 |
HashValue Out
Waiting for transactions...
53 | {{tx.txid}} 54 | {{$root.currency.getConvertion(tx.valueOut)}}
59 | 60 |
61 | 62 |
63 |

About

64 |

insight is an open-source Zcash blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by zcashd RPC. Check out the source code.

66 |

insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

67 |

This explorer is currently showing testnet Zcash!

68 |
69 |
70 | Powered by 71 |
72 | 73 | 74 | 75 | 76 |
77 |
78 |
79 |
80 |
81 | -------------------------------------------------------------------------------- /public/views/messages_verify.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 |
9 |
10 |
11 | 14 |
15 | 17 |
18 |
19 |
20 | 23 |
24 | 26 |
27 |
28 |
29 | 32 |
33 | 35 |
36 |
37 |
38 |
39 | 43 |
44 |
45 |
46 |
47 |
49 |
50 | Loading... 51 |
52 |
54 | The message is verifiably from {{verification.address}}. 55 |
56 |
58 | The message failed to verify. 59 |
60 |
62 |

An error occured in the verification process.

63 |

64 | Error message: 65 | {{verification.error}} 66 |

67 |
68 |
69 |
70 |
71 |
72 |

73 | Zcash comes with a way of signing arbitrary messages. 74 |

75 |

76 | This form can be used to verify that a message comes from 77 | a specific Zcash address. 78 |

79 |
80 |
81 |
82 | -------------------------------------------------------------------------------- /public/views/redirect.html: -------------------------------------------------------------------------------- 1 |
Redirecting...
2 | -------------------------------------------------------------------------------- /public/views/status.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
7 | 8 |
9 |

Sync Status

10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Sync Progress 15 |
16 |
17 | {{sync.syncPercentage}}% 18 | Complete 19 | 20 |
21 |
22 |
Current Sync Status 27 | {{sync.status}} 28 | 29 | 30 | {{sync.error}} 31 | 32 |
Start Date
Finish Date
Initial Block Chain Height{{sync.blockChainHeight}}
Synced Blocks{{sync.syncedBlocks}}
Skipped Blocks (previously synced){{sync.skippedBlocks}}
Sync Type{{sync.type}}
60 | 61 |

Last Block

62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
Last Block Hash (Zcashd){{lastblockhash}}
Current Blockchain Tip (insight){{syncTipHash}}
75 | 76 |
77 | 78 |
79 |

Zcash node information

80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |
Version{{info.version}}
Protocol version{{info.protocolversion}}
Blocks{{info.blocks}}
Time Offset{{info.timeoffset}}
Connections to other nodes{{info.connections}}
Mining Difficulty{{info.difficulty}}
Network{{info.network}}
Proxy setting{{info.proxy}}
Info Errors{{info.infoErrors}}
121 |
122 |
123 |
124 | 125 | -------------------------------------------------------------------------------- /public/views/transaction.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 29 |
30 |

Transaction 31 | 32 | Input 33 | Output 34 | {{v_index}} 35 | 36 |

37 |
38 |
39 | Loading Transaction Details 40 |
41 |
42 |
43 |
44 | Transaction 45 | {{tx.txid}} 46 | 47 |
48 |

Summary

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 112 | 113 | 114 |
Size{{tx.size}} (bytes)
Fee Rate{{$root.currency.getConvertion((tx.fees * 1000) / tx.size) + ' per kB'}}
Received Time{{tx.time * 1000|date:'medium'}}N/A
Mined Time{{tx.blocktime * 1000|date:'medium'}}N/A
Included in Block 72 |
73 | {{tx.blockhash}} 74 |
75 |
Unconfirmed
LockTime{{tx.locktime}}
Version{{tx.version}}
Overwintered{{tx.fOverwintered}}
VersionGroupId 94 | 0x{{tx.nVersionGroupId.toString(16).padStart(8, "0")}} 95 | N/A
Expiry Height{{tx.nExpiryHeight}}
Coinbase 107 |
108 | 109 | {{tx.vin[0].coinbase}} 110 |
111 |
115 |
116 |

Details

117 |
118 |
119 |
120 |
121 |
122 | -------------------------------------------------------------------------------- /public/views/transaction/list.html: -------------------------------------------------------------------------------- 1 |
There are no transactions involving this address.
4 |
5 |
6 |
7 |
8 |
9 | Loading Transactions... 10 |
11 |
12 | -------------------------------------------------------------------------------- /public/views/transaction_sendraw.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 |
9 |
10 |
12 | 15 |
16 | 19 | 20 | Raw transaction data must be a valid hexadecimal string. 21 | 22 |
23 |
24 |
25 |
26 | 30 |
31 |
32 |
33 |
34 |
36 |
37 | Loading... 38 |
39 |
40 | Transaction succesfully broadcast.
Transaction id: {{txid}} 41 |
42 |
43 | An error occured:
{{error}} 44 |
45 |
46 |
47 |
48 |
49 |

50 | This form can be used to broadcast a raw transaction in hex format over 51 | the Zcash network. 52 |

53 |
54 |
55 |
56 | --------------------------------------------------------------------------------