From 7325bafd453c03a55ae2c5e29d952484e3faf3ac Mon Sep 17 00:00:00 2001 From: Alasdair Mercer Date: Thu, 1 Jun 2017 15:53:11 +0100 Subject: [PATCH 1/3] prepare for v4.0.0 --- .editorconfig | 12 + .eslintrc.json | 21 + .npmignore | 5 + .travis.yml | 17 + AUTHORS.md | 8 + CONTRIBUTING.md | 26 + LICENSE.md | 16 + README.md | 93 +++ index.js | 22 + package-lock.json | 858 ++++++++++++++++++++++++ package.json | 38 ++ src/Alignment.js | 51 ++ src/ErrorCorrection.js | 125 ++++ src/Frame.js | 911 ++++++++++++++++++++++++++ src/Galois.js | 89 +++ src/QRious.js | 208 ++++++ src/Version.js | 49 ++ src/option/Option.js | 107 +++ src/option/OptionManager.js | 268 ++++++++ src/renderer/CanvasRenderer.js | 81 +++ src/renderer/ImageRenderer.js | 61 ++ src/renderer/Renderer.js | 193 ++++++ src/service/Service.js | 45 ++ src/service/ServiceManager.js | 76 +++ src/service/element/ElementService.js | 92 +++ src/util/Utilities.js | 90 +++ 26 files changed, 3562 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintrc.json create mode 100644 .npmignore create mode 100644 .travis.yml create mode 100644 AUTHORS.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 index.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/Alignment.js create mode 100644 src/ErrorCorrection.js create mode 100644 src/Frame.js create mode 100644 src/Galois.js create mode 100644 src/QRious.js create mode 100644 src/Version.js create mode 100644 src/option/Option.js create mode 100644 src/option/OptionManager.js create mode 100644 src/renderer/CanvasRenderer.js create mode 100644 src/renderer/ImageRenderer.js create mode 100644 src/renderer/Renderer.js create mode 100644 src/service/Service.js create mode 100644 src/service/ServiceManager.js create mode 100644 src/service/element/ElementService.js create mode 100644 src/util/Utilities.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8c52ff9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ef2425e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "extends": "notninja/es5", + "env": { + "node": true + }, + "rules": { + "max-params": [ + "error", + 5 + ], + "no-bitwise": "off", + "no-empty-function": "off", + "no-invalid-this": "off", + "no-unused-vars": [ + "warn", + { + "args": "none" + } + ] + } +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..d37db43 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +.* +AUTHORS.md +CHANGES.md +CONTRIBUTING.md +README.md diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..26fba35 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +sudo: false +language: node_js +node_js: + - "4" + - "6" + - "8" +before_script: + - npm install -g npm@latest +script: + - npm run ci +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/f1c9df131febcfade24c + on_success: always + on_failure: always + on_start: never diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..91065f8 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,8 @@ +# Authors ordered by first contribution + +* Tom Zerucha +* Alasdair Mercer +* Alexandre Perrin +* Michael Mason +* Benjamin Besse +* Marek Vavrecan diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8f28585 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing + +If you have any questions about [QRious Core](https://github.com/neocotic/qrious-core) please feel free to +[raise an issue](https://github.com/neocotic/qrious-core/issues/new). + +Please [search existing issues](https://github.com/neocotic/qrious-core/issues) for the same feature and/or issue before +raising a new issue. Commenting on an existing issue is usually preferred over raising duplicate issues. + +Please ensure that all files conform to the coding standards, using the same coding style as the rest of the code base. +This can be done easily via command-line: + +``` bash +# install/update package dependencies +$ npm install +# run test suite +$ npm test +``` + +You must have at least [Node.js](https://nodejs.org) version 4 or newer and [npm](https://npmjs.com) installed version 5 +or newer installed. + +All pull requests should be made to the `develop` branch. + +Don't forget to add your details to the list of +[AUTHORS.md](https://github.com/neocotic/qrious-core/blob/master/AUTHORS.md) if you want your contribution to be +recognized by others. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c275508 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,16 @@ +QRious +Copyright (C) 2017 Alasdair Mercer +Copyright (C) 2010 Tom Zerucha + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/README.md b/README.md index e69de29..f6212b9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,93 @@ + .d88888b. 8888888b. d8b .d8888b. + d88P" "Y88b 888 Y88b Y8P d88P Y88b + 888 888 888 888 888 888 + 888 888 888 d88P 888 .d88b. 888 888 .d8888b 888 .d88b. 888d888 .d88b. + 888 888 8888888P" 888 d88""88b 888 888 88K 888 d88""88b 888P" d8P Y8b + 888 Y8b 888 888 T88b 888 888 888 888 888 "Y8888b. 888 888 888 888 888 88888888 + Y88b.Y8b88P 888 T88b 888 Y88..88P Y88b 888 X88 Y88b d88P Y88..88P 888 Y8b. + "Y888888" 888 T88b 888 "Y88P" "Y88888 88888P' "Y8888P" "Y88P" 888 "Y8888 + Y8b + +[QRious Core](https://github.com/neocotic/qrious-core) is the core engine for +[QRious](https://github.com/neocotic/qrious)' QR code generation as well as modules to support other environments (e.g. +[QRious Node](https://github.com/neocotic/node-qrious)). + +[![Chat](https://img.shields.io/gitter/room/neocotic/qrious.svg?style=flat-square)](https://gitter.im/neocotic/qrious) +[![Build Status](https://img.shields.io/travis/neocotic/qrious-core/develop.svg?style=flat-square)](https://travis-ci.org/neocotic/qrious-core) +[![Dependency Status](https://img.shields.io/david/neocotic/qrious-core.svg?style=flat-square)](https://david-dm.org/neocotic/qrious-core) +[![Dev Dependency Status](https://img.shields.io/david/dev/neocotic/qrious-core.svg?style=flat-square)](https://david-dm.org/neocotic/qrious-core?type=dev) +[![License](https://img.shields.io/npm/l/qrious-core.svg?style=flat-square)](https://github.com/neocotic/qrious-core/blob/master/LICENSE.md) +[![Release](https://img.shields.io/npm/v/qrious-core.svg?style=flat-square)](https://www.npmjs.com/package/qrious-core) + +* [Install](#install) +* [API](#api) +* [Bugs](#bugs) +* [Contributors](#contributors) +* [License](#license) + +## Install + +Install using `npm`: + +``` bash +$ npm install --save qrious-core +``` + +You will most likely never need to depend on `qrious-core` directly. Instead, you will probably want to install a module +that supports your desired environment. For example: + +* [qrious](https://github.com/neocotic/qrious) for browser +* [node-qrious](https://github.com/neocotic/node-qrious) for Node.js + +## API + +As this is the core of QRious, it contains all of the QR code generation logic and, since it's designed to use HTML5 +canvas to render the QR code, all that consumers need to do is define and register an implementation of +`ElementService`. + +Most modules that use QRious Core will look something like the following: + +``` javascript +var ElementService = require('qrious-core/src/service/element/ElementService'); +var QRious = require('qrious-core'); + +var ExampleElementService = ElementService.extend({ + createCanvas: function() { /* ... */ }, + createImage: function() { /* ... */ }, + isCanvas: function(element) { /* ... */ }, + isImage: function(element) { /* ... */ } +}); + +QRious.use(new ExampleElementService()); + +module.exports = QRious; +``` + +This allows the core to control the primary API and keep it consistent across all environments. With the above in place, +you are free to import QRious and use it as you would anywhere else. + +You will find the primary API documentation on [QRious](https://github.com/neocotic/qrious). All direct consumers of +core should also reference this to help developers find the information easily. However, they are encouraged to provide +environment-specific examples. + +## Bugs + +If you have any problems with QRious Core or would like to see changes currently in development you can do so +[here](https://github.com/neocotic/qrious-core/issues). + +## Contributors + +If you want to contribute, you're a legend! Information on how you can do so can be found in +[CONTRIBUTING.md](https://github.com/neocotic/qrious-core/blob/master/CONTRIBUTING.md). We want your suggestions and +pull requests! + +A list of QRious Core contributors can be found in +[AUTHORS.md](https://github.com/neocotic/qrious-core/blob/master/AUTHORS.md). + +## License + +Copyright © 2017 Alasdair Mercer +Copyright © 2010 Tom Zerucha + +See [LICENSE.md](https://github.com/neocotic/qrious-core/blob/master/LICENSE.md) for more information on our GPLv3 +license. diff --git a/index.js b/index.js new file mode 100644 index 0000000..280b74d --- /dev/null +++ b/index.js @@ -0,0 +1,22 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +module.exports = require('./src/QRious'); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..bfa7dbe --- /dev/null +++ b/package-lock.json @@ -0,0 +1,858 @@ +{ + "name": "qrious-core", + "version": "4.0.0-alpha", + "lockfileVersion": 1, + "dependencies": { + "acorn": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", + "integrity": "sha1-xGDfCEkUY/AozLguqzcwvwEIez0=", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "babel-code-frame": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "circular-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", + "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true + }, + "cli-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true + }, + "doctrine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", + "dev": true + }, + "es5-ext": { + "version": "0.10.22", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.22.tgz", + "integrity": "sha512-YXTXSlZkJsVwMEVljp1Bh5P9+Raa3524OMl9kywGMp1aazKTCnAqORRL/8dkuqNHk+LRYe0LezuS8PlUt3+mOw==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true + }, + "eslint-config-notninja": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-notninja/-/eslint-config-notninja-0.1.1.tgz", + "integrity": "sha1-bD7LRHTEN7RXuwSog6oiXBQTdSA=", + "dev": true + }, + "espree": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", + "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "dev": true + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true + }, + "esrecurse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", + "integrity": "sha1-RxO2U2rffyrE8yfVWed1a/9kgiA=", + "dev": true, + "dependencies": { + "estraverse": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", + "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", + "dev": true + } + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true + }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true + }, + "globals": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "integrity": "sha1-DAymltm5u2lNLlRwvTd3fKrVAoY=", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "ignore": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", + "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true + }, + "interpret": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", + "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true + }, + "is-my-json-valid": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "js-tokens": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", + "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", + "dev": true + }, + "js-yaml": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", + "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nevis": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/nevis/-/nevis-0.5.0.tgz", + "integrity": "sha1-7a64i4zTL+vaixUxT/iGJ4PUbRo=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "readable-stream": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", + "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "dev": true + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true + }, + "resolve": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", + "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "dev": true + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "safe-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=", + "dev": true + }, + "shelljs": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", + "integrity": "sha1-svXHfvlxSPS09uImguELuoZnz/E=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string_decoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", + "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", + "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..32a303c --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "qrious-core", + "version": "4.0.0-alpha", + "description": "QRious core engine for QR code generation", + "homepage": "https://github.com/neocotic/qrious-core", + "bugs": { + "url": "https://github.com/neocotic/qrious-core/issues" + }, + "author": { + "name": "Alasdair Mercer", + "email": "mercer.alasdair@gmail.com", + "url": "https://neocotic.com" + }, + "license": "GPL-3.0", + "keywords": [ + "qr", + "code", + "qrious", + "core", + "engine" + ], + "repository": { + "type": "git", + "url": "https://github.com/neocotic/qrious-core.git" + }, + "dependencies": { + "nevis": "^0.5.0" + }, + "devDependencies": { + "eslint": "^3.19.0", + "eslint-config-notninja": "^0.1.1" + }, + "main": "index.js", + "scripts": { + "ci": "npm run test", + "test": "eslint \"index.js\" \"src/**/*.js\"" + } +} diff --git a/src/Alignment.js b/src/Alignment.js new file mode 100644 index 0000000..83adce2 --- /dev/null +++ b/src/Alignment.js @@ -0,0 +1,51 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +/* eslint no-multi-spaces: "off" */ + +var Nevis = require('nevis/lite'); + +/** + * Contains alignment pattern information. + * + * @public + * @class + * @extends Nevis + */ +var Alignment = Nevis.extend(null, { + + /** + * The alignment pattern block. + * + * @public + * @static + * @type {number[]} + * @memberof Alignment + */ + BLOCK: [ + 0, 11, 15, 19, 23, 27, 31, + 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, + 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28 + ] + +}); + +module.exports = Alignment; diff --git a/src/ErrorCorrection.js b/src/ErrorCorrection.js new file mode 100644 index 0000000..48dcf07 --- /dev/null +++ b/src/ErrorCorrection.js @@ -0,0 +1,125 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +/* eslint no-multi-spaces: "off" */ + +var Nevis = require('nevis/lite'); + +/** + * Contains error correction information. + * + * @public + * @class + * @extends Nevis + */ +var ErrorCorrection = Nevis.extend(null, { + + /** + * The error correction blocks. + * + * There are four elements per version. The first two indicate the number of blocks, then the data width, and finally + * the ECC width. + * + * @public + * @static + * @type {number[]} + * @memberof ErrorCorrection + */ + BLOCKS: [ + 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, + 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, + 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22, + 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, + 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, + 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, + 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, + 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26, + 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, + 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, + 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24, + 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, + 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, + 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, + 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, + 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30, + 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, + 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, + 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, + 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, + 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30, + 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, + 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, + 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, + 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, + 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30, + 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, + 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30, + 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, + 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, + 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, + 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, + 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30, + 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, + 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30, + 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, + 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, + 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, + 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, + 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30 + ], + + /** + * The final format bits with mask (level << 3 | mask). + * + * @public + * @static + * @type {number[]} + * @memberof ErrorCorrection + */ + FINAL_FORMAT: [ + // L + 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, + // M + 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, + // Q + 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, + // H + 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b + ], + + /** + * A map of human-readable ECC levels. + * + * @public + * @static + * @type {Object.} + * @memberof ErrorCorrection + */ + LEVELS: { + L: 1, + M: 2, + Q: 3, + H: 4 + } + +}); + +module.exports = ErrorCorrection; diff --git a/src/Frame.js b/src/Frame.js new file mode 100644 index 0000000..8ccede7 --- /dev/null +++ b/src/Frame.js @@ -0,0 +1,911 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +var Alignment = require('./Alignment'); +var ErrorCorrection = require('./ErrorCorrection'); +var Galois = require('./Galois'); +var Version = require('./Version'); + +/** + * Generates information for a QR code frame based on a specific value to be encoded. + * + * @param {Frame~Options} options - the options to be used + * @public + * @class + * @extends Nevis + */ +var Frame = Nevis.extend(function(options) { + var dataBlock, eccBlock, index, neccBlock1, neccBlock2; + var valueLength = options.value.length; + + this._badness = []; + this._level = ErrorCorrection.LEVELS[options.level]; + this._polynomial = []; + this._value = options.value; + this._version = 0; + this._stringBuffer = []; + + while (this._version < 40) { + this._version++; + + index = ((this._level - 1) * 4) + ((this._version - 1) * 16); + + neccBlock1 = ErrorCorrection.BLOCKS[index++]; + neccBlock2 = ErrorCorrection.BLOCKS[index++]; + dataBlock = ErrorCorrection.BLOCKS[index++]; + eccBlock = ErrorCorrection.BLOCKS[index]; + + index = (dataBlock * (neccBlock1 + neccBlock2)) + neccBlock2 - 3 + (this._version <= 9); + + if (valueLength <= index) { + break; + } + } + + this._dataBlock = dataBlock; + this._eccBlock = eccBlock; + this._neccBlock1 = neccBlock1; + this._neccBlock2 = neccBlock2; + + /** + * The data width is based on version. + * + * @public + * @type {number} + * @memberof Frame# + */ + // FIXME: Ensure that it fits instead of being truncated. + var width = this.width = 17 + (4 * this._version); + + /** + * The image buffer. + * + * @public + * @type {number[]} + * @memberof Frame# + */ + this.buffer = Frame._createArray(width * width); + + this._ecc = Frame._createArray(dataBlock + ((dataBlock + eccBlock) * (neccBlock1 + neccBlock2)) + neccBlock2); + this._mask = Frame._createArray(((width * (width + 1)) + 1) / 2); + + this._insertFinders(); + this._insertAlignments(); + + // Insert single foreground cell. + this.buffer[8 + (width * (width - 8))] = 1; + + this._insertTimingGap(); + this._reverseMask(); + this._insertTimingRowAndColumn(); + this._insertVersion(); + this._syncMask(); + this._convertBitStream(valueLength); + this._calculatePolynomial(); + this._appendEccToData(); + this._interleaveBlocks(); + this._pack(); + this._finish(); +}, { + + _addAlignment: function(x, y) { + var i; + var buffer = this.buffer; + var width = this.width; + + buffer[x + (width * y)] = 1; + + for (i = -2; i < 2; i++) { + buffer[x + i + (width * (y - 2))] = 1; + buffer[x - 2 + (width * (y + i + 1))] = 1; + buffer[x + 2 + (width * (y + i))] = 1; + buffer[x + i + 1 + (width * (y + 2))] = 1; + } + + for (i = 0; i < 2; i++) { + this._setMask(x - 1, y + i); + this._setMask(x + 1, y - i); + this._setMask(x - i, y - 1); + this._setMask(x + i, y + 1); + } + }, + + _appendData: function(data, dataLength, ecc, eccLength) { + var bit, i, j; + var polynomial = this._polynomial; + var stringBuffer = this._stringBuffer; + + for (i = 0; i < eccLength; i++) { + stringBuffer[ecc + i] = 0; + } + + for (i = 0; i < dataLength; i++) { + bit = Galois.LOG[stringBuffer[data + i] ^ stringBuffer[ecc]]; + + if (bit !== 255) { + for (j = 1; j < eccLength; j++) { + stringBuffer[ecc + j - 1] = stringBuffer[ecc + j] ^ + Galois.EXPONENT[Frame._modN(bit + polynomial[eccLength - j])]; + } + } else { + for (j = ecc; j < ecc + eccLength; j++) { + stringBuffer[j] = stringBuffer[j + 1]; + } + } + + stringBuffer[ecc + eccLength - 1] = bit === 255 ? 0 : Galois.EXPONENT[Frame._modN(bit + polynomial[0])]; + } + }, + + _appendEccToData: function() { + var i; + var data = 0; + var dataBlock = this._dataBlock; + var ecc = this._calculateMaxLength(); + var eccBlock = this._eccBlock; + + for (i = 0; i < this._neccBlock1; i++) { + this._appendData(data, dataBlock, ecc, eccBlock); + + data += dataBlock; + ecc += eccBlock; + } + + for (i = 0; i < this._neccBlock2; i++) { + this._appendData(data, dataBlock + 1, ecc, eccBlock); + + data += dataBlock + 1; + ecc += eccBlock; + } + }, + + _applyMask: function(mask) { + var r3x, r3y, x, y; + var buffer = this.buffer; + var width = this.width; + + switch (mask) { + case 0: + for (y = 0; y < width; y++) { + for (x = 0; x < width; x++) { + if (!((x + y) & 1) && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 1: + for (y = 0; y < width; y++) { + for (x = 0; x < width; x++) { + if (!(y & 1) && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 2: + for (y = 0; y < width; y++) { + for (r3x = 0, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + } + + if (!r3x && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 3: + for (r3y = 0, y = 0; y < width; y++, r3y++) { + if (r3y === 3) { + r3y = 0; + } + + for (r3x = r3y, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + } + + if (!r3x && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 4: + for (y = 0; y < width; y++) { + for (r3x = 0, r3y = (y >> 1) & 1, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + r3y = !r3y; + } + + if (!r3y && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 5: + for (r3y = 0, y = 0; y < width; y++, r3y++) { + if (r3y === 3) { + r3y = 0; + } + + for (r3x = 0, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + } + + if (!((x & y & 1) + !(!r3x | !r3y)) && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 6: + for (r3y = 0, y = 0; y < width; y++, r3y++) { + if (r3y === 3) { + r3y = 0; + } + + for (r3x = 0, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + } + + if (!((x & y & 1) + (r3x && r3x === r3y) & 1) && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + case 7: + for (r3y = 0, y = 0; y < width; y++, r3y++) { + if (r3y === 3) { + r3y = 0; + } + + for (r3x = 0, x = 0; x < width; x++, r3x++) { + if (r3x === 3) { + r3x = 0; + } + + if (!((r3x && r3x === r3y) + (x + y & 1) & 1) && !this._isMasked(x, y)) { + buffer[x + (y * width)] ^= 1; + } + } + } + + break; + } + }, + + _calculateMaxLength: function() { + return (this._dataBlock * (this._neccBlock1 + this._neccBlock2)) + this._neccBlock2; + }, + + _calculatePolynomial: function() { + var i, j; + var eccBlock = this._eccBlock; + var polynomial = this._polynomial; + + polynomial[0] = 1; + + for (i = 0; i < eccBlock; i++) { + polynomial[i + 1] = 1; + + for (j = i; j > 0; j--) { + polynomial[j] = polynomial[j] ? polynomial[j - 1] ^ + Galois.EXPONENT[Frame._modN(Galois.LOG[polynomial[j]] + i)] : polynomial[j - 1]; + } + + polynomial[0] = Galois.EXPONENT[Frame._modN(Galois.LOG[polynomial[0]] + i)]; + } + + // Use logs for generator polynomial to save calculation step. + for (i = 0; i <= eccBlock; i++) { + polynomial[i] = Galois.LOG[polynomial[i]]; + } + }, + + _checkBadness: function() { + var b, b1, h, x, y; + var bad = 0; + var badness = this._badness; + var buffer = this.buffer; + var width = this.width; + + // Blocks of same colour. + for (y = 0; y < width - 1; y++) { + for (x = 0; x < width - 1; x++) { + // All foreground colour. + if ((buffer[x + (width * y)] && + buffer[x + 1 + (width * y)] && + buffer[x + (width * (y + 1))] && + buffer[x + 1 + (width * (y + 1))]) || + // All background colour. + !(buffer[x + (width * y)] || + buffer[x + 1 + (width * y)] || + buffer[x + (width * (y + 1))] || + buffer[x + 1 + (width * (y + 1))])) { + bad += Frame.N2; + } + } + } + + var bw = 0; + + // X runs. + for (y = 0; y < width; y++) { + h = 0; + + badness[0] = 0; + + for (b = 0, x = 0; x < width; x++) { + b1 = buffer[x + (width * y)]; + + if (b === b1) { + badness[h]++; + } else { + badness[++h] = 1; + } + + b = b1; + bw += b ? 1 : -1; + } + + bad += this._getBadness(h); + } + + if (bw < 0) { + bw = -bw; + } + + var count = 0; + var big = bw; + big += big << 2; + big <<= 1; + + while (big > width * width) { + big -= width * width; + count++; + } + + bad += count * Frame.N4; + + // Y runs. + for (x = 0; x < width; x++) { + h = 0; + + badness[0] = 0; + + for (b = 0, y = 0; y < width; y++) { + b1 = buffer[x + (width * y)]; + + if (b === b1) { + badness[h]++; + } else { + badness[++h] = 1; + } + + b = b1; + } + + bad += this._getBadness(h); + } + + return bad; + }, + + _convertBitStream: function(length) { + var bit, i; + var ecc = this._ecc; + var version = this._version; + + // Convert string to bit stream. 8-bit data to QR-coded 8-bit data (numeric, alphanumeric, or kanji not supported). + for (i = 0; i < length; i++) { + ecc[i] = this._value.charCodeAt(i); + } + + var stringBuffer = this._stringBuffer = ecc.slice(); + var maxLength = this._calculateMaxLength(); + + if (length >= maxLength - 2) { + length = maxLength - 2; + + if (version > 9) { + length--; + } + } + + // Shift and re-pack to insert length prefix. + var index = length; + + if (version > 9) { + stringBuffer[index + 2] = 0; + stringBuffer[index + 3] = 0; + + while (index--) { + bit = stringBuffer[index]; + + stringBuffer[index + 3] |= 255 & (bit << 4); + stringBuffer[index + 2] = bit >> 4; + } + + stringBuffer[2] |= 255 & (length << 4); + stringBuffer[1] = length >> 4; + stringBuffer[0] = 0x40 | (length >> 12); + } else { + stringBuffer[index + 1] = 0; + stringBuffer[index + 2] = 0; + + while (index--) { + bit = stringBuffer[index]; + + stringBuffer[index + 2] |= 255 & (bit << 4); + stringBuffer[index + 1] = bit >> 4; + } + + stringBuffer[1] |= 255 & (length << 4); + stringBuffer[0] = 0x40 | (length >> 4); + } + + // Fill to end with pad pattern. + index = length + 3 - (version < 10); + + while (index < maxLength) { + stringBuffer[index++] = 0xec; + stringBuffer[index++] = 0x11; + } + }, + + _getBadness: function(length) { + var i; + var badRuns = 0; + var badness = this._badness; + + for (i = 0; i <= length; i++) { + if (badness[i] >= 5) { + badRuns += Frame.N1 + badness[i] - 5; + } + } + + // FBFFFBF as in finder. + for (i = 3; i < length - 1; i += 2) { + if (badness[i - 2] === badness[i + 2] && + badness[i + 2] === badness[i - 1] && + badness[i - 1] === badness[i + 1] && + badness[i - 1] * 3 === badness[i] && + // Background around the foreground pattern? Not part of the specs. + (badness[i - 3] === 0 || i + 3 > length || + badness[i - 3] * 3 >= badness[i] * 4 || + badness[i + 3] * 3 >= badness[i] * 4)) { + badRuns += Frame.N3; + } + } + + return badRuns; + }, + + _finish: function() { + // Save pre-mask copy of frame. + this._stringBuffer = this.buffer.slice(); + + var currentMask, i; + var bit = 0; + var mask = 30000; + + /* + * Using for instead of while since in original Arduino code if an early mask was "good enough" it wouldn't try for + * a better one since they get more complex and take longer. + */ + for (i = 0; i < 8; i++) { + // Returns foreground-background imbalance. + this._applyMask(i); + + currentMask = this._checkBadness(); + + // Is current mask better than previous best? + if (currentMask < mask) { + mask = currentMask; + bit = i; + } + + // Don't increment "i" to a void redoing mask. + if (bit === 7) { + break; + } + + // Reset for next pass. + this.buffer = this._stringBuffer.slice(); + } + + // Redo best mask as none were "good enough" (i.e. last wasn't bit). + if (bit !== i) { + this._applyMask(bit); + } + + // Add in final mask/ECC level bytes. + mask = ErrorCorrection.FINAL_FORMAT[bit + (this._level - 1 << 3)]; + + var buffer = this.buffer; + var width = this.width; + + // Low byte. + for (i = 0; i < 8; i++, mask >>= 1) { + if (mask & 1) { + buffer[width - 1 - i + (width * 8)] = 1; + + if (i < 6) { + buffer[8 + (width * i)] = 1; + } else { + buffer[8 + (width * (i + 1))] = 1; + } + } + } + + // High byte. + for (i = 0; i < 7; i++, mask >>= 1) { + if (mask & 1) { + buffer[8 + (width * (width - 7 + i))] = 1; + + if (i) { + buffer[6 - i + (width * 8)] = 1; + } else { + buffer[7 + (width * 8)] = 1; + } + } + } + }, + + _interleaveBlocks: function() { + var i, j; + var dataBlock = this._dataBlock; + var ecc = this._ecc; + var eccBlock = this._eccBlock; + var k = 0; + var maxLength = this._calculateMaxLength(); + var neccBlock1 = this._neccBlock1; + var neccBlock2 = this._neccBlock2; + var stringBuffer = this._stringBuffer; + + for (i = 0; i < dataBlock; i++) { + for (j = 0; j < neccBlock1; j++) { + ecc[k++] = stringBuffer[i + (j * dataBlock)]; + } + + for (j = 0; j < neccBlock2; j++) { + ecc[k++] = stringBuffer[(neccBlock1 * dataBlock) + i + (j * (dataBlock + 1))]; + } + } + + for (j = 0; j < neccBlock2; j++) { + ecc[k++] = stringBuffer[(neccBlock1 * dataBlock) + i + (j * (dataBlock + 1))]; + } + + for (i = 0; i < eccBlock; i++) { + for (j = 0; j < neccBlock1 + neccBlock2; j++) { + ecc[k++] = stringBuffer[maxLength + i + (j * eccBlock)]; + } + } + + this._stringBuffer = ecc; + }, + + _insertAlignments: function() { + var i, x, y; + var version = this._version; + var width = this.width; + + if (version > 1) { + i = Alignment.BLOCK[version]; + y = width - 7; + + for (;;) { + x = width - 7; + + while (x > i - 3) { + this._addAlignment(x, y); + + if (x < i) { + break; + } + + x -= i; + } + + if (y <= i + 9) { + break; + } + + y -= i; + + this._addAlignment(6, y); + this._addAlignment(y, 6); + } + } + }, + + _insertFinders: function() { + var i, j, x, y; + var buffer = this.buffer; + var width = this.width; + + for (i = 0; i < 3; i++) { + j = 0; + y = 0; + + if (i === 1) { + j = width - 7; + } + if (i === 2) { + y = width - 7; + } + + buffer[y + 3 + (width * (j + 3))] = 1; + + for (x = 0; x < 6; x++) { + buffer[y + x + (width * j)] = 1; + buffer[y + (width * (j + x + 1))] = 1; + buffer[y + 6 + (width * (j + x))] = 1; + buffer[y + x + 1 + (width * (j + 6))] = 1; + } + + for (x = 1; x < 5; x++) { + this._setMask(y + x, j + 1); + this._setMask(y + 1, j + x + 1); + this._setMask(y + 5, j + x); + this._setMask(y + x + 1, j + 5); + } + + for (x = 2; x < 4; x++) { + buffer[y + x + (width * (j + 2))] = 1; + buffer[y + 2 + (width * (j + x + 1))] = 1; + buffer[y + 4 + (width * (j + x))] = 1; + buffer[y + x + 1 + (width * (j + 4))] = 1; + } + } + }, + + _insertTimingGap: function() { + var x, y; + var width = this.width; + + for (y = 0; y < 7; y++) { + this._setMask(7, y); + this._setMask(width - 8, y); + this._setMask(7, y + width - 7); + } + + for (x = 0; x < 8; x++) { + this._setMask(x, 7); + this._setMask(x + width - 8, 7); + this._setMask(x, width - 8); + } + }, + + _insertTimingRowAndColumn: function() { + var x; + var buffer = this.buffer; + var width = this.width; + + for (x = 0; x < width - 14; x++) { + if (x & 1) { + this._setMask(8 + x, 6); + this._setMask(6, 8 + x); + } else { + buffer[8 + x + (width * 6)] = 1; + buffer[6 + (width * (8 + x))] = 1; + } + } + }, + + _insertVersion: function() { + var i, j, x, y; + var buffer = this.buffer; + var version = this._version; + var width = this.width; + + if (version > 6) { + i = Version.BLOCK[version - 7]; + j = 17; + + for (x = 0; x < 6; x++) { + for (y = 0; y < 3; y++, j--) { + if (1 & (j > 11 ? version >> j - 12 : i >> j)) { + buffer[5 - x + (width * (2 - y + width - 11))] = 1; + buffer[2 - y + width - 11 + (width * (5 - x))] = 1; + } else { + this._setMask(5 - x, 2 - y + width - 11); + this._setMask(2 - y + width - 11, 5 - x); + } + } + } + } + }, + + _isMasked: function(x, y) { + var bit = Frame._getMaskBit(x, y); + + return this._mask[bit] === 1; + }, + + _pack: function() { + var bit, i, j; + var k = 1; + var v = 1; + var width = this.width; + var x = width - 1; + var y = width - 1; + + // Interleaved data and ECC codes. + var length = ((this._dataBlock + this._eccBlock) * (this._neccBlock1 + this._neccBlock2)) + this._neccBlock2; + + for (i = 0; i < length; i++) { + bit = this._stringBuffer[i]; + + for (j = 0; j < 8; j++, bit <<= 1) { + if (0x80 & bit) { + this.buffer[x + (width * y)] = 1; + } + + // Find next fill position. + do { + if (v) { + x--; + } else { + x++; + + if (k) { + if (y !== 0) { + y--; + } else { + x -= 2; + k = !k; + + if (x === 6) { + x--; + y = 9; + } + } + } else if (y !== width - 1) { + y++; + } else { + x -= 2; + k = !k; + + if (x === 6) { + x--; + y -= 8; + } + } + } + + v = !v; + } while (this._isMasked(x, y)); + } + } + }, + + _reverseMask: function() { + var x, y; + var width = this.width; + + for (x = 0; x < 9; x++) { + this._setMask(x, 8); + } + + for (x = 0; x < 8; x++) { + this._setMask(x + width - 8, 8); + this._setMask(8, x); + } + + for (y = 0; y < 7; y++) { + this._setMask(8, y + width - 7); + } + }, + + _setMask: function(x, y) { + var bit = Frame._getMaskBit(x, y); + + this._mask[bit] = 1; + }, + + _syncMask: function() { + var x, y; + var width = this.width; + + for (y = 0; y < width; y++) { + for (x = 0; x <= y; x++) { + if (this.buffer[x + (width * y)]) { + this._setMask(x, y); + } + } + } + } + +}, { + + _createArray: function(length) { + var i; + var array = []; + + for (i = 0; i < length; i++) { + array[i] = 0; + } + + return array; + }, + + _getMaskBit: function(x, y) { + var bit; + + if (x > y) { + bit = x; + x = y; + y = bit; + } + + bit = y; + bit += y * y; + bit >>= 1; + bit += x; + + return bit; + }, + + _modN: function(x) { + while (x >= 255) { + x -= 255; + x = (x >> 8) + (x & 255); + } + + return x; + }, + + // *Badness* coefficients. + N1: 3, + N2: 3, + N3: 40, + N4: 10 + +}); + +module.exports = Frame; + +/** + * The options used by {@link Frame}. + * + * @typedef {Object} Frame~Options + * @property {string} level - The ECC level to be used. + * @property {string} value - The value to be encoded. + */ diff --git a/src/Galois.js b/src/Galois.js new file mode 100644 index 0000000..edbe3f9 --- /dev/null +++ b/src/Galois.js @@ -0,0 +1,89 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Contains Galois field information. + * + * @public + * @class + * @extends Nevis + */ +var Galois = Nevis.extend(null, { + + /** + * The Galois field exponent table. + * + * @public + * @static + * @type {number[]} + * @memberof Galois + */ + EXPONENT: [ + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, + 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, + 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, + 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, + 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, + 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, + 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, + 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, + 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, + 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, + 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, + 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, + 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, + 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, + 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, + 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00 + ], + + /** + * The Galois field log table. + * + * @public + * @static + * @type {number[]} + * @memberof Galois + */ + LOG: [ + 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, + 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, + 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, + 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, + 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, + 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, + 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, + 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, + 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, + 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, + 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, + 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, + 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, + 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, + 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, + 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf + ] + +}); + +module.exports = Galois; diff --git a/src/QRious.js b/src/QRious.js new file mode 100644 index 0000000..01c3579 --- /dev/null +++ b/src/QRious.js @@ -0,0 +1,208 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +var CanvasRenderer = require('./renderer/CanvasRenderer'); +var Frame = require('./Frame'); +var ImageRenderer = require('./renderer/ImageRenderer'); +var Option = require('./option/Option'); +var OptionManager = require('./option/OptionManager'); +var ServiceManager = require('./service/ServiceManager'); +var Utilities = require('./util/Utilities'); + +var optionManager = new OptionManager([ + new Option('background', true, 'white'), + new Option('backgroundAlpha', true, 1, Utilities.abs), + new Option('element'), + new Option('foreground', true, 'black'), + new Option('foregroundAlpha', true, 1, Utilities.abs), + new Option('level', true, 'L', Utilities.toUpperCase), + new Option('mime', true, 'image/png'), + new Option('padding', true, null, Utilities.abs), + new Option('size', true, 100, Utilities.abs), + new Option('value', true, '') +]); +var serviceManager = new ServiceManager(); + +/** + * Enables configuration of a QR code generator which uses HTML5 canvas for rendering. + * + * @param {QRious~Options} [options] - the options to be used + * @throws {Error} If any options are invalid. + * @public + * @class + * @extends Nevis + */ +var QRious = Nevis.extend(function(options) { + optionManager.init(options, this, this.update.bind(this)); + + var element = optionManager.get('element', this); + var elementService = serviceManager.getService('element'); + var canvas = element && elementService.isCanvas(element) ? element : elementService.createCanvas(); + var image = element && elementService.isImage(element) ? element : elementService.createImage(); + + this._canvasRenderer = new CanvasRenderer(this, canvas, true); + this._imageRenderer = new ImageRenderer(this, image, image === element); + + this.update(); +}, { + + /** + * Returns all of the options configured for this {@link QRious}. + * + * Any changes made to the returned object will not be reflected in the options themselves or their corresponding + * underlying fields. + * + * @return {Object.} A copy of the applied options. + * @public + * @memberof QRious# + */ + get: function() { + return optionManager.getAll(this); + }, + + /** + * Sets all of the specified options and automatically updates this {@link QRious} if any of the + * underlying fields are changed as a result. + * + * This is the preferred method for updating multiple options at one time to avoid unnecessary updates between + * changes. + * + * @param {QRious~Options} options - the options to be set + * @return {void} + * @throws {Error} If any options are invalid or cannot be modified. + * @public + * @memberof QRious# + */ + set: function(options) { + if (optionManager.setAll(options, this)) { + this.update(); + } + }, + + /** + * Returns the image data URI for the generated QR code using the mime provided. + * + * @param {string} [mime] - the MIME type for the image + * @return {string} The image data URI for the QR code. + * @public + * @memberof QRious# + */ + toDataURL: function(mime) { + return this.canvas.toDataURL(mime || this.mime); + }, + + /** + * Updates this {@link QRious} by generating a new {@link Frame} and re-rendering the QR code. + * + * @return {void} + * @protected + * @memberof QRious# + */ + update: function() { + var frame = new Frame({ + level: this.level, + value: this.value + }); + + this._canvasRenderer.render(frame); + this._imageRenderer.render(frame); + } + +}, { + + /** + * The current version of {@link QRious}. + * + * @public + * @static + * @type {string} + * @memberof QRious + */ + VERSION: '3.0.1', + + /** + * Configures the service provided to be used by all {@link QRious} instances. + * + * @param {Service} service - the {@link Service} to be configured + * @return {void} + * @throws {Error} If a {@link Service} has already been configured with the same name. + * @public + * @static + * @memberof QRious + */ + use: function(service) { + serviceManager.setService(service.getName(), service); + } + +}); + +Object.defineProperties(QRious.prototype, { + + canvas: { + /** + * Returns the canvas element being used to render the QR code for this {@link QRious}. + * + * @return {*} The canvas element. + * @public + * @memberof QRious# + * @alias canvas + */ + get: function() { + return this._canvasRenderer.getElement(); + } + }, + + image: { + /** + * Returns the img element being used to render the QR code for this {@link QRious}. + * + * @return {*} The img element. + * @public + * @memberof QRious# + * @alias image + */ + get: function() { + return this._imageRenderer.getElement(); + } + } + +}); + +module.exports = QRious; + +/** + * The options used by {@link QRious}. + * + * @typedef {Object} QRious~Options + * @property {string} [background="white"] - The background color to be applied to the QR code. + * @property {number} [backgroundAlpha=1] - The background alpha to be applied to the QR code. + * @property {*} [element] - The element to be used to render the QR code which may either be an canvas or + * img. The element(s) will be created if needed. + * @property {string} [foreground="black"] - The foreground color to be applied to the QR code. + * @property {number} [foregroundAlpha=1] - The foreground alpha to be applied to the QR code. + * @property {string} [level="L"] - The error correction level to be applied to the QR code. + * @property {string} [mime="image/png"] - The MIME type to be used to render the image for the QR code. + * @property {number} [padding] - The padding for the QR code in pixels. + * @property {number} [size=100] - The size of the QR code in pixels. + * @property {string} [value=""] - The value to be encoded within the QR code. + */ diff --git a/src/Version.js b/src/Version.js new file mode 100644 index 0000000..e9ec9eb --- /dev/null +++ b/src/Version.js @@ -0,0 +1,49 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Contains version pattern information. + * + * @public + * @class + * @extends Nevis + */ +var Version = Nevis.extend(null, { + + /** + * The version pattern block. + * + * @public + * @static + * @type {number[]} + * @memberof Version + */ + BLOCK: [ + 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, 0x928, 0xb78, 0x45d, 0xa17, 0x532, + 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5, + 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69 + ] + +}); + +module.exports = Version; diff --git a/src/option/Option.js b/src/option/Option.js new file mode 100644 index 0000000..7d13dbc --- /dev/null +++ b/src/option/Option.js @@ -0,0 +1,107 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Defines an available option while also configuring how values are applied to the target object. + * + * Optionally, a default value can be specified as well a value transformer for greater control over how the option + * value is applied. + * + * If no value transformer is specified, then any specified option will be applied directly. All values are maintained + * on the target object itself as a field using the option name prefixed with a single underscore. + * + * When an option is specified as modifiable, the {@link OptionManager} will be required to include a setter for the + * property that is defined on the target object that uses the option name. + * + * @param {string} name - the name to be used + * @param {boolean} [modifiable] - true if the property defined on target objects should include a setter; + * otherwise false + * @param {*} [defaultValue] - the default value to be used + * @param {Option~ValueTransformer} [valueTransformer] - the value transformer to be used + * @public + * @class + * @extends Nevis + */ +var Option = Nevis.extend(function(name, modifiable, defaultValue, valueTransformer) { + /** + * The name for this {@link Option}. + * + * @public + * @type {string} + * @memberof Option# + */ + this.name = name; + + /** + * Whether a setter should be included on the property defined on target objects for this {@link Option}. + * + * @public + * @type {boolean} + * @memberof Option# + */ + this.modifiable = Boolean(modifiable); + + /** + * The default value for this {@link Option}. + * + * @public + * @type {*} + * @memberof Option# + */ + this.defaultValue = defaultValue; + + this._valueTransformer = valueTransformer; +}, { + + /** + * Transforms the specified value so that it can be applied for this {@link Option}. + * + * If a value transformer has been specified for this {@link Option}, it will be called upon to transform + * value. Otherwise, value will be returned directly. + * + * @param {*} value - the value to be transformed + * @return {*} The transformed value or value if no value transformer is specified. + * @public + * @memberof Option# + */ + transform: function(value) { + var transformer = this._valueTransformer; + if (typeof transformer === 'function') { + return transformer(value, this); + } + + return value; + } + +}); + +module.exports = Option; + +/** + * Returns a transformed value for the specified value to be applied for the option provided. + * + * @callback Option~ValueTransformer + * @param {*} value - the value to be transformed + * @param {Option} option - the {@link Option} for which value is being transformed + * @return {*} The transform value. + */ diff --git a/src/option/OptionManager.js b/src/option/OptionManager.js new file mode 100644 index 0000000..7648c40 --- /dev/null +++ b/src/option/OptionManager.js @@ -0,0 +1,268 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +var Utilities = require('../util/Utilities'); + +/** + * Manages multiple {@link Option} instances that are intended to be used by multiple implementations. + * + * Although the option definitions are shared between targets, the values are maintained on the targets themselves. + * + * @param {Option[]} options - the options to be used + * @public + * @class + * @extends Nevis + */ +var OptionManager = Nevis.extend(function(options) { + /** + * The available options for this {@link OptionManager}. + * + * @public + * @type {Object.} + * @memberof OptionManager# + */ + this.options = {}; + + options.forEach(function(option) { + this.options[option.name] = option; + }, this); +}, { + + /** + * Returns whether an option with the specified name is available. + * + * @param {string} name - the name of the {@link Option} whose existence is to be checked + * @return {boolean} true if an {@link Option} exists with name; otherwise + * false. + * @public + * @memberof OptionManager# + */ + exists: function(name) { + return this.options[name] != null; + }, + + /** + * Returns the value of the option with the specified name on the target object provided. + * + * @param {string} name - the name of the {@link Option} whose value on target is to be returned + * @param {Object} target - the object from which the value of the named {@link Option} is to be returned + * @return {*} The value of the {@link Option} with name on target. + * @public + * @memberof OptionManager# + */ + get: function(name, target) { + return OptionManager._get(this.options[name], target); + }, + + /** + * Returns a copy of all of the available options on the target object provided. + * + * @param {Object} target - the object from which the option name/value pairs are to be returned + * @return {Object.} A hash containing the name/value pairs of all options on target. + * @public + * @memberof OptionManager# + */ + getAll: function(target) { + var name; + var options = this.options; + var result = {}; + + for (name in options) { + if (Utilities.hasOwn(options, name)) { + result[name] = OptionManager._get(options[name], target); + } + } + + return result; + }, + + /** + * Initializes the available options for the target object provided and then applies the initial values + * within the speciifed options. + * + * This method will throw an error if any of the names within options does not match an available option. + * + * This involves setting the default values and defining properties for all of the available options on + * target before finally calling {@link OptionMananger#setAll} with options and + * target. Any options that are configured to be modifiable will have a setter included in their defined + * property that will allow its corresponding value to be modified. + * + * If a change handler is specified, it will be called whenever the value changes on target for a + * modifiable option, but only when done so via the defined property's setter. + * + * @param {Object.} options - the name/value pairs of the initial options to be set + * @param {Object} target - the object on which the options are to be initialized + * @param {Function} [changeHandler] - the function to be called whenever the value of an modifiable option changes on + * target + * @return {void} + * @throws {Error} If options contains an invalid option name. + * @public + * @memberof OptionManager# + */ + init: function(options, target, changeHandler) { + if (typeof changeHandler !== 'function') { + changeHandler = Utilities.noop; + } + + var name, option; + + for (name in this.options) { + if (Utilities.hasOwn(this.options, name)) { + option = this.options[name]; + + OptionManager._set(option, option.defaultValue, target); + OptionManager._createAccessor(option, target, changeHandler); + } + } + + this._setAll(options, target, true); + }, + + /** + * Sets the value of the option with the specified name on the target object provided to + * value. + * + * This method will throw an error if name does not match an available option or matches an option that + * cannot be modified. + * + * If value is null and the {@link Option} has a default value configured, then that default + * value will be used instead. If the {@link Option} also has a value transformer configured, it will be used to + * transform whichever value was determined to be used. + * + * This method returns whether the value of the underlying field on target was changed as a result. + * + * @param {string} name - the name of the {@link Option} whose value is to be set + * @param {*} value - the value to be set for the named {@link Option} on target + * @param {Object} target - the object on which value is to be set for the named {@link Option} + * @return {boolean} true if the underlying field on target was changed; otherwise + * false. + * @throws {Error} If name is invalid or is for an option that cannot be modified. + * @public + * @memberof OptionManager# + */ + set: function(name, value, target) { + return this._set(name, value, target); + }, + + /** + * Sets all of the specified options on the target object provided to their corresponding + * values. + * + * This method will throw an error if any of the names within options does not match an available option + * or matches an option that cannot be modified. + * + * If any value within options is null and the corresponding {@link Option} has a default + * value configured, then that default value will be used instead. If an {@link Option} also has a value transformer + * configured, it will be used to transform whichever value was determined to be used. + * + * This method returns whether the value for any of the underlying fields on target were changed as a + * result. + * + * @param {Object.} options - the name/value pairs of options to be set + * @param {Object} target - the object on which the options are to be set + * @return {boolean} true if any of the underlying fields on target were changed; otherwise + * false. + * @throws {Error} If options contains an invalid option name or an option that cannot be modiifed. + * @public + * @memberof OptionManager# + */ + setAll: function(options, target) { + return this._setAll(options, target); + }, + + _set: function(name, value, target, allowUnmodifiable) { + var option = this.options[name]; + if (!option) { + throw new Error('Invalid option: ' + name); + } + if (!option.modifiable && !allowUnmodifiable) { + throw new Error('Option cannot be modified: ' + name); + } + + return OptionManager._set(option, value, target); + }, + + _setAll: function(options, target, allowUnmodifiable) { + if (!options) { + return false; + } + + var name; + var changed = false; + + for (name in options) { + if (Utilities.hasOwn(options, name) && this._set(name, options[name], target, allowUnmodifiable)) { + changed = true; + } + } + + return changed; + } + +}, { + + _createAccessor: function(option, target, changeHandler) { + var descriptor = { + get: function() { + return OptionManager._get(option, target); + } + }; + + if (option.modifiable) { + descriptor.set = function(value) { + if (OptionManager._set(option, value, target)) { + changeHandler(value, option); + } + }; + } + + Object.defineProperty(target, option.name, descriptor); + }, + + _get: function(option, target) { + return target['_' + option.name]; + }, + + _set: function(option, value, target) { + var fieldName = '_' + option.name; + var oldValue = target[fieldName]; + var newValue = option.transform(value != null ? value : option.defaultValue); + + target[fieldName] = newValue; + + return newValue !== oldValue; + } + +}); + +module.exports = OptionManager; + +/** + * Called whenever the value of a modifiable {@link Option} is changed on a target object via the defined property's + * setter. + * + * @callback OptionManager~ChangeHandler + * @param {*} value - the new value for option on the target object + * @param {Option} option - the modifable {@link Option} whose value has changed on the target object. + * @return {void} + */ diff --git a/src/renderer/CanvasRenderer.js b/src/renderer/CanvasRenderer.js new file mode 100644 index 0000000..3ec594c --- /dev/null +++ b/src/renderer/CanvasRenderer.js @@ -0,0 +1,81 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Renderer = require('./Renderer'); + +/** + * An implementation of {@link Renderer} for working with canvas elements. + * + * @public + * @class + * @extends Renderer + */ +var CanvasRenderer = Renderer.extend({ + + /** + * @override + */ + draw: function(frame) { + var i, j; + var qrious = this.qrious; + var moduleSize = this.getModuleSize(frame); + var offset = this.getOffset(frame); + var context = this.element.getContext('2d'); + + context.fillStyle = qrious.foreground; + context.globalAlpha = qrious.foregroundAlpha; + + for (i = 0; i < frame.width; i++) { + for (j = 0; j < frame.width; j++) { + if (frame.buffer[(j * frame.width) + i]) { + context.fillRect((moduleSize * i) + offset, (moduleSize * j) + offset, moduleSize, moduleSize); + } + } + } + }, + + /** + * @override + */ + reset: function() { + var qrious = this.qrious; + var context = this.element.getContext('2d'); + var size = qrious.size; + + context.lineWidth = 1; + context.clearRect(0, 0, size, size); + context.fillStyle = qrious.background; + context.globalAlpha = qrious.backgroundAlpha; + context.fillRect(0, 0, size, size); + }, + + /** + * @override + */ + resize: function() { + var element = this.element; + + element.width = element.height = this.qrious.size; + } + +}); + +module.exports = CanvasRenderer; diff --git a/src/renderer/ImageRenderer.js b/src/renderer/ImageRenderer.js new file mode 100644 index 0000000..dfff217 --- /dev/null +++ b/src/renderer/ImageRenderer.js @@ -0,0 +1,61 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Renderer = require('./Renderer'); + +/** + * An implementation of {@link Renderer} for working with img elements. + * + * This depends on {@link CanvasRenderer} being executed first as this implementation simply applies the data URL from + * the rendered canvas element as the src for the img element being rendered. + * + * @public + * @class + * @extends Renderer + */ +var ImageRenderer = Renderer.extend({ + + /** + * @override + */ + draw: function() { + this.element.src = this.qrious.toDataURL(); + }, + + /** + * @override + */ + reset: function() { + this.element.src = ''; + }, + + /** + * @override + */ + resize: function() { + var element = this.element; + + element.width = element.height = this.qrious.size; + } + +}); + +module.exports = ImageRenderer; diff --git a/src/renderer/Renderer.js b/src/renderer/Renderer.js new file mode 100644 index 0000000..a87f613 --- /dev/null +++ b/src/renderer/Renderer.js @@ -0,0 +1,193 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Responsible for rendering a QR code {@link Frame} on a specific type of element. + * + * A renderer may be dependant on the rendering of another element, so the ordering of their execution is important. + * + * The rendering of a element can be deferred by disabling the renderer initially, however, any attempt get the element + * from the renderer will result in it being immediately enabled and the element being rendered. + * + * @param {QRious} qrious - the {@link QRious} instance to be used + * @param {*} element - the element onto which the QR code is to be rendered + * @param {boolean} [enabled] - true this {@link Renderer} is enabled; otherwise false. + * @public + * @class + * @extends Nevis + */ +var Renderer = Nevis.extend(function(qrious, element, enabled) { + /** + * The {@link QRious} instance. + * + * @protected + * @type {QRious} + * @memberof Renderer# + */ + this.qrious = qrious; + + /** + * The element onto which this {@link Renderer} is rendering the QR code. + * + * @protected + * @type {*} + * @memberof Renderer# + */ + this.element = element; + this.element.qrious = qrious; + + /** + * Whether this {@link Renderer} is enabled. + * + * @protected + * @type {boolean} + * @memberof Renderer# + */ + this.enabled = Boolean(enabled); +}, { + + /** + * Draws the specified QR code frame on the underlying element. + * + * Implementations of {@link Renderer} must override this method with their own specific logic. + * + * @param {Frame} frame - the {@link Frame} to be drawn + * @return {void} + * @protected + * @abstract + * @memberof Renderer# + */ + draw: function(frame) {}, + + /** + * Returns the element onto which this {@link Renderer} is rendering the QR code. + * + * If this method is called while this {@link Renderer} is disabled, it will be immediately enabled and rendered + * before the element is returned. + * + * @return {*} The element. + * @public + * @memberof Renderer# + */ + getElement: function() { + if (!this.enabled) { + this.enabled = true; + this.render(); + } + + return this.element; + }, + + /** + * Calculates the size (in pixel units) to represent an individual module within the QR code based on the + * frame provided. + * + * Any configured padding will be excluded from the returned size. + * + * The returned value will be at least one, even in cases where the size of the QR code does not fit its contents. + * This is done so that the inevitable clipping is handled more gracefully since this way at least something is + * displayed instead of just a blank space filled by the background color. + * + * @param {Frame} frame - the {@link Frame} from which the module size is to be derived + * @return {number} The pixel size for each module in the QR code which will be no less than one. + * @protected + * @memberof Renderer# + */ + getModuleSize: function(frame) { + var qrious = this.qrious; + var padding = qrious.padding || 0; + var pixels = Math.floor((qrious.size - (padding * 2)) / frame.width); + + return Math.max(1, pixels); + }, + + /** + * Calculates the offset/padding (in pixel units) to be inserted before the QR code based on the frame + * provided. + * + * The returned value will be zero if there is no available offset or if the size of the QR code does not fit its + * contents. It will never be a negative value. This is done so that the inevitable clipping appears more naturally + * and it is not clipped from all directions. + * + * @param {Frame} frame - the {@link Frame} from which the offset is to be derived + * @return {number} The pixel offset for the QR code which will be no less than zero. + * @protected + * @memberof Renderer# + */ + getOffset: function(frame) { + var qrious = this.qrious; + var padding = qrious.padding; + + if (padding != null) { + return padding; + } + + var moduleSize = this.getModuleSize(frame); + var offset = Math.floor((qrious.size - (moduleSize * frame.width)) / 2); + + return Math.max(0, offset); + }, + + /** + * Renders a QR code on the underlying element based on the frame provided. + * + * @param {Frame} frame - the {@link Frame} to be rendered + * @return {void} + * @public + * @memberof Renderer# + */ + render: function(frame) { + if (this.enabled) { + this.resize(); + this.reset(); + this.draw(frame); + } + }, + + /** + * Resets the underlying element, effectively clearing any previously rendered QR code. + * + * Implementations of {@link Renderer} must override this method with their own specific logic. + * + * @return {void} + * @protected + * @abstract + * @memberof Renderer# + */ + reset: function() {}, + + /** + * Ensures that the size of the underlying element matches that defined on the associated {@link QRious} instance. + * + * Implementations of {@link Renderer} must override this method with their own specific logic. + * + * @return {void} + * @protected + * @abstract + * @memberof Renderer# + */ + resize: function() {} + +}); + +module.exports = Renderer; diff --git a/src/service/Service.js b/src/service/Service.js new file mode 100644 index 0000000..cacfbac --- /dev/null +++ b/src/service/Service.js @@ -0,0 +1,45 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Defines a service contract that must be met by all implementations. + * + * @public + * @class + * @extends Nevis + */ +var Service = Nevis.extend({ + + /** + * Returns the name of this {@link Service}. + * + * @return {string} The service name. + * @public + * @abstract + * @memberof Service# + */ + getName: function() {} + +}); + +module.exports = Service; diff --git a/src/service/ServiceManager.js b/src/service/ServiceManager.js new file mode 100644 index 0000000..64844da --- /dev/null +++ b/src/service/ServiceManager.js @@ -0,0 +1,76 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * A basic manager for {@link Service} implementations that are mapped to simple names. + * + * @public + * @class + * @extends Nevis + */ +var ServiceManager = Nevis.extend(function() { + this._services = {}; +}, { + + /** + * Returns the {@link Service} being managed with the specified name. + * + * @param {string} name - the name of the {@link Service} to be returned + * @return {Service} The {@link Service} is being managed with name. + * @throws {Error} If no {@link Service} is being managed with name. + * @public + * @memberof ServiceManager# + */ + getService: function(name) { + var service = this._services[name]; + if (!service) { + throw new Error('Service is not being managed with name: ' + name); + } + + return service; + }, + + /** + * Sets the {@link Service} implementation to be managed for the specified name to the + * service provided. + * + * @param {string} name - the name of the {@link Service} to be managed with name + * @param {Service} service - the {@link Service} implementation to be managed + * @return {void} + * @throws {Error} If a {@link Service} is already being managed with the same name. + * @public + * @memberof ServiceManager# + */ + setService: function(name, service) { + if (this._services[name]) { + throw new Error('Service is already managed with name: ' + name); + } + + if (service) { + this._services[name] = service; + } + } + +}); + +module.exports = ServiceManager; diff --git a/src/service/element/ElementService.js b/src/service/element/ElementService.js new file mode 100644 index 0000000..cf731be --- /dev/null +++ b/src/service/element/ElementService.js @@ -0,0 +1,92 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Service = require('../Service'); + +/** + * A service for working with elements. + * + * @public + * @class + * @extends Service + */ +var ElementService = Service.extend({ + + /** + * Creates an instance of a canvas element. + * + * Implementations of {@link ElementService} must override this method with their own specific logic. + * + * @return {*} The newly created canvas element. + * @public + * @abstract + * @memberof ElementService# + */ + createCanvas: function() {}, + + /** + * Creates an instance of a image element. + * + * Implementations of {@link ElementService} must override this method with their own specific logic. + * + * @return {*} The newly created image element. + * @public + * @abstract + * @memberof ElementService# + */ + createImage: function() {}, + + /** + * @override + */ + getName: function() { + return 'element'; + }, + + /** + * Returns whether the specified element is a canvas. + * + * Implementations of {@link ElementService} must override this method with their own specific logic. + * + * @param {*} element - the element to be checked + * @return {boolean} true if element is a canvas; otherwise false. + * @public + * @abstract + * @memberof ElementService# + */ + isCanvas: function(element) {}, + + /** + * Returns whether the specified element is an image. + * + * Implementations of {@link ElementService} must override this method with their own specific logic. + * + * @param {*} element - the element to be checked + * @return {boolean} true if element is an image; otherwise false. + * @public + * @abstract + * @memberof ElementService# + */ + isImage: function(element) {} + +}); + +module.exports = ElementService; diff --git a/src/util/Utilities.js b/src/util/Utilities.js new file mode 100644 index 0000000..e809b6a --- /dev/null +++ b/src/util/Utilities.js @@ -0,0 +1,90 @@ +/* + * QRious + * Copyright (C) 2017 Alasdair Mercer + * Copyright (C) 2010 Tom Zerucha + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +'use strict'; + +var Nevis = require('nevis/lite'); + +/** + * Contains utility methods that are useful throughout the library. + * + * @public + * @class + * @extends Nevis + */ +var Utilities = Nevis.extend(null, { + + /** + * Returns the absolute value of a given number. + * + * This method is simply a convenient shorthand for Math.abs while ensuring that nulls are returned as + * null instead of zero. + * + * @param {number} value - the number whose absolute value is to be returned + * @return {number} The absolute value of value or null if value is + * null. + * @public + * @static + * @memberof Utilities + */ + abs: function(value) { + return value != null ? Math.abs(value) : null; + }, + + /** + * Returns whether the specified object has a property with the specified name as an own + * (not inherited) property. + * + * @param {Object} object - the object on which the property is to be checked + * @param {string} name - the name of the property to be checked + * @return {boolean} true if object has an own property with name. + * @public + * @static + * @memberof Utilities + */ + hasOwn: function(object, name) { + return Object.prototype.hasOwnProperty.call(object, name); + }, + + /** + * A non-operation method that does absolutely nothing. + * + * @return {void} + * @public + * @static + * @memberof Utilities + */ + noop: function() {}, + + /** + * Transforms the specified string to upper case while remaining null-safe. + * + * @param {string} string - the string to be transformed to upper case + * @return {string} string transformed to upper case if string is not null. + * @public + * @static + * @memberof Utilities + */ + toUpperCase: function(string) { + return string != null ? string.toUpperCase() : null; + } + +}); + +module.exports = Utilities; From 6e07d1fa5a8dd18d91d3e9da857bcf5a356ec331 Mon Sep 17 00:00:00 2001 From: Alasdair Mercer Date: Thu, 1 Jun 2017 15:57:14 +0100 Subject: [PATCH 2/3] removed QRious.VERSION for qrious#84 --- src/QRious.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/QRious.js b/src/QRious.js index 01c3579..14abd67 100644 --- a/src/QRious.js +++ b/src/QRious.js @@ -130,16 +130,6 @@ var QRious = Nevis.extend(function(options) { }, { - /** - * The current version of {@link QRious}. - * - * @public - * @static - * @type {string} - * @memberof QRious - */ - VERSION: '3.0.1', - /** * Configures the service provided to be used by all {@link QRious} instances. * From b24162482e2b65a6a74fb7e76192bbba455588a7 Mon Sep 17 00:00:00 2001 From: Alasdair Mercer Date: Thu, 1 Jun 2017 16:16:43 +0100 Subject: [PATCH 3/3] roll 4.0.0 --- CHANGES.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 CHANGES.md diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..2fe5e99 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,110 @@ +## Version 4.0.0, 2017.06.02 + +* Split into multiple modules [#53](https://github.com/neocotic/qrious/issues/53) (**breaking change**) +* Remove QRious.VERSION [#84](https://github.com/neocotic/qrious/issues/84) (**breaking change**) + +## Version 3.0.1, 2017.06.01 + +* Correct file sizes of distribution files in README [#82](https://github.com/neocotic/qrious/issues/82) + +## Version 3.0.0, 2017.06.01 + +* Reduce size of distribution files [#59](https://github.com/neocotic/qrious/issues/59) (**breaking change**) +* Drop support for Node.js < 4 [#74](https://github.com/neocotic/qrious/issues/74) (**breaking change**) +* Remove QRious.DEFAULTS [#77](https://github.com/neocotic/qrious/issues/77) (**breaking change**) +* Rewrite code in ES5 [#81](https://github.com/neocotic/qrious/issues/81) (**breaking change**) + +## Version 2.3.0, 2017.05.31 + +* Enable setting of multiple properties at once resulting in a single re-render [#69](https://github.com/neocotic/qrious/issues/69) +* Deferring or avoiding ImageRenderer [#71](https://github.com/neocotic/qrious/issues/71) +* Switch to container-based Travis builds for faster boot times [#73](https://github.com/neocotic/qrious/issues/73) +* Change code style to be more contributor-friendly [#75](https://github.com/neocotic/qrious/issues/75) +* Improve download links in README [#76](https://github.com/neocotic/qrious/issues/76) + +## Version 2.2.0, 2016.10.30 + +* Add `backgroundAlpha` and `foregroundAlpha` options to control transparency [#63](https://github.com/neocotic/qrious/issues/63) + +## Version 2.1.0, 2016.10.04 + +* Allow `padding` to be set explicitly [#44](https://github.com/neocotic/qrious/issues/44) +* Fix support for older browsers [#55](https://github.com/neocotic/qrious/issues/55) +* Update code style to fit with other projects +* Update build system to run on older Node.js versions at a reduced capacity + +## Version 2.0.2, 2016.08.05 + +* Fix bug where mask is incorrectly applied [#50](https://github.com/neocotic/qrious/issues/50) + +## Version 2.0.1, 2016.07.03 + +* Correct license mentioned into `README.md` + +## Version 2.0.0, 2016.06.26 + +* Rename library to QRious and move package from `qr-js` to `qrious` +* Completely redesign API to follow OOP pattern for simplicity +* Remove `save` and `saveSync` method +* Remove `noConflict` method +* Remove documentation generated by `docco` +* Restructure code base to make it more maintainable and use [Rollup](http://rollupjs.org) to build it +* Provide better built-in support for [Browserify](http://browserify.org) and [Webpack](http://webpack.github.io) etc +* Switch from [JSHint](https://github.com/jshint/jshint) to [ESLint](http://eslint.org) +* Add `demo.html` to allow contributors to experiment and test with changes due to lack of unit tests +* Remove `INSTALL.md` and consolidate contents into `README.md` and `CONTRIBUTING.md` +* Add [EditorConfig](http://editorconfig.org) file +* Add support for [Travis CI](https://travis-ci.org) + +## Version 1.1.4, 2015.11.11 + +* Fix padding issues [#2](https://github.com/neocotic/qrious/issues/2) +* Make the QR code center-aligned [#35](https://github.com/neocotic/qrious/pull/35) +* Update [node-canvas](https://github.com/Automattic/node-canvas) dependency version to support [Node.js](https://nodejs.org) v4 and above [#38](https://github.com/neocotic/qrious/pull/38) + +## Version 1.1.3, 2014.09.01 + +* Revert back to [GPL License](http://www.gnu.org/licenses/) [#23](https://github.com/neocotic/qrious/issues/23) + +## Version 1.1.2, 2014.04.27 + +* Fix "too many open files" bug [#20](https://github.com/neocotic/qrious/issues/20) + +## Version 1.1.1, 2013.12.03 + +* Fix bug with IIFE + +## Version 1.1.0, 2013.12.02 + +* Fix [RequireJS](http://requirejs.org) support [#9](https://github.com/neocotic/qrious/issues/9) +* Remove [Ender](http://enderjs.com) support [#13](https://github.com/neocotic/qrious/issues/13) +* Improve code formatting and style [#14](https://github.com/neocotic/qrious/issues/14) +* Support different MIME types for `toDataURL` and other related functions [#16](https://github.com/neocotic/qrious/issues/16) +* Remove unnecessary callback arguments from synchronous functions [#17](https://github.com/neocotic/qrious/issues/17) +* Make `save` fully asynchronous [#17](https://github.com/neocotic/qrious/issues/17) +* Add `saveSync` for synchronous saving [#17](https://github.com/neocotic/qrious/issues/17) +* Add [Grunt](http://gruntjs.com) build system [#18](https://github.com/neocotic/qrious/issues/18) +* Generate source map as part of build [#18](https://github.com/neocotic/qrious/issues/18) +* Improve developer documentation [#18](https://github.com/neocotic/qrious/issues/18) +* Add support for [Bower](https://bower.io) [#19](https://github.com/neocotic/qrious/issues/19) +* Many small fixes and tweaks + +## Version 1.0.3, 2011.12.19 + +* Rename `QRCode` to `qr` [#3](https://github.com/neocotic/qrious/issues/3) +* Remove all deprecated methods [#3](https://github.com/neocotic/qrious/issues/3) +* Reformat code and add additional, along with some original, code comments [#4](https://github.com/neocotic/qrious/issues/4) +* Add support for [Node.js](https://nodejs.org), [CommonJS](http://www.commonjs.org) and [Ender](http://enderjs.com) [#6](https://github.com/neocotic/qrious/issues/6) +* Add optional `callback` functionality to API methods [#6](https://github.com/neocotic/qrious/issues/6) +* Allow `data` arguments to be an object or string value [#7](https://github.com/neocotic/qrious/issues/7) +* Add `VERSION` property to the API [#8](https://github.com/neocotic/qrious/issues/8) +* Add `toDataURL`, `save` and `noConflict` methods to the API [#8](https://github.com/neocotic/qrious/issues/8) +* Now distributed under the MIT license + +## Version 1.0.2, 2011.08.31 + +* Deprecate `generateCanvas` and `generateImage` and replaced with `canvas` and `image` respectively [#1](https://github.com/neocotic/qrious/issues/1) + +## Version 1.0.1, 2011.08.12 + +* Allow customisation of colours used when rendering diff --git a/package-lock.json b/package-lock.json index bfa7dbe..b8796c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "qrious-core", - "version": "4.0.0-alpha", + "version": "4.0.0", "lockfileVersion": 1, "dependencies": { "acorn": { diff --git a/package.json b/package.json index 32a303c..f995749 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qrious-core", - "version": "4.0.0-alpha", + "version": "4.0.0", "description": "QRious core engine for QR code generation", "homepage": "https://github.com/neocotic/qrious-core", "bugs": {