From c648add9631b999db953c666aeb83a54140252be Mon Sep 17 00:00:00 2001 From: Andrey Antukh <niwi@niwi.nz> Date: Sun, 10 Jan 2021 19:11:22 +0100 Subject: [PATCH] :tada: Add svgclean (svgo graalvm/browser ready fork). --- vendor/svgclean/.gitignore | 11 + vendor/svgclean/LICENSE | 25 + vendor/svgclean/examples/test.js | 101 + vendor/svgclean/examples/test.svg | 3 + vendor/svgclean/main.js | 43 + vendor/svgclean/package-lock.json | 3488 +++++++++++++++++ vendor/svgclean/package.json | 34 + vendor/svgclean/src/svgclean.js | 59 + vendor/svgclean/src/svgclean/config.js | 269 ++ .../svgclean/src/svgclean/css-class-list.js | 138 + .../src/svgclean/css-select-adapter.js | 53 + .../src/svgclean/css-style-declaration.js | 285 ++ vendor/svgclean/src/svgclean/css-tools.js | 222 ++ vendor/svgclean/src/svgclean/js2svg.js | 346 ++ vendor/svgclean/src/svgclean/jsAPI.js | 372 ++ .../src/svgclean/plugins/_collections.js | 2558 ++++++++++++ vendor/svgclean/src/svgclean/plugins/_path.js | 988 +++++ .../src/svgclean/plugins/_transforms.js | 310 ++ .../plugins/addAttributesToSVGElement.js | 82 + .../plugins/addClassesToSVGElement.js | 50 + .../src/svgclean/plugins/cleanupAttrs.js | 56 + .../plugins/cleanupEnableBackground.js | 84 + .../src/svgclean/plugins/cleanupIDs.js | 212 + .../svgclean/plugins/cleanupListOfValues.js | 139 + .../svgclean/plugins/cleanupNumericValues.js | 88 + .../src/svgclean/plugins/collapseGroups.js | 87 + .../src/svgclean/plugins/convertColors.js | 130 + .../plugins/convertEllipseToCircle.js | 39 + .../src/svgclean/plugins/convertPathData.js | 971 +++++ .../svgclean/plugins/convertShapeToPath.js | 149 + .../svgclean/plugins/convertStyleToAttrs.js | 125 + .../src/svgclean/plugins/convertTransform.js | 363 ++ .../src/svgclean/plugins/inlineStyles.js | 245 ++ .../src/svgclean/plugins/mergePaths.js | 73 + .../src/svgclean/plugins/minifyStyles.js | 160 + .../svgclean/plugins/moveElemsAttrsToGroup.js | 126 + .../svgclean/plugins/moveGroupAttrsToElems.js | 63 + .../src/svgclean/plugins/prefixIds.js | 274 ++ .../plugins/removeAttributesBySelector.js | 70 + .../src/svgclean/plugins/removeAttrs.js | 150 + .../src/svgclean/plugins/removeComments.js | 27 + .../src/svgclean/plugins/removeDesc.js | 32 + .../src/svgclean/plugins/removeDimensions.js | 49 + .../src/svgclean/plugins/removeDoctype.js | 40 + .../svgclean/plugins/removeEditorsNSData.js | 65 + .../svgclean/plugins/removeElementsByAttr.js | 80 + .../src/svgclean/plugins/removeEmptyAttrs.js | 29 + .../svgclean/plugins/removeEmptyContainers.js | 32 + .../src/svgclean/plugins/removeEmptyText.js | 59 + .../src/svgclean/plugins/removeHiddenElems.js | 225 ++ .../src/svgclean/plugins/removeMetadata.js | 23 + .../plugins/removeNonInheritableGroupAttrs.js | 37 + .../svgclean/plugins/removeOffCanvasPaths.js | 134 + .../svgclean/plugins/removeRasterImages.js | 28 + .../svgclean/plugins/removeScriptElement.js | 23 + .../svgclean/plugins/removeStyleElement.js | 23 + .../src/svgclean/plugins/removeTitle.js | 23 + .../plugins/removeUnknownsAndDefaults.js | 150 + .../src/svgclean/plugins/removeUnusedNS.js | 109 + .../src/svgclean/plugins/removeUselessDefs.js | 53 + .../plugins/removeUselessStrokeAndFill.js | 100 + .../src/svgclean/plugins/removeViewBox.js | 48 + .../src/svgclean/plugins/removeXMLNS.js | 28 + .../src/svgclean/plugins/removeXMLProcInst.js | 24 + .../src/svgclean/plugins/reusePaths.js | 169 + .../src/svgclean/plugins/sortAttrs.js | 84 + .../src/svgclean/plugins/sortDefsChildren.js | 47 + vendor/svgclean/src/svgclean/svg2js.js | 190 + vendor/svgclean/src/svgclean/tools.js | 152 + vendor/svgclean/test.js | 8 + vendor/svgclean/test.svg | 3 + 71 files changed, 15135 insertions(+) create mode 100644 vendor/svgclean/.gitignore create mode 100644 vendor/svgclean/LICENSE create mode 100644 vendor/svgclean/examples/test.js create mode 100644 vendor/svgclean/examples/test.svg create mode 100644 vendor/svgclean/main.js create mode 100644 vendor/svgclean/package-lock.json create mode 100644 vendor/svgclean/package.json create mode 100755 vendor/svgclean/src/svgclean.js create mode 100644 vendor/svgclean/src/svgclean/config.js create mode 100644 vendor/svgclean/src/svgclean/css-class-list.js create mode 100644 vendor/svgclean/src/svgclean/css-select-adapter.js create mode 100644 vendor/svgclean/src/svgclean/css-style-declaration.js create mode 100644 vendor/svgclean/src/svgclean/css-tools.js create mode 100644 vendor/svgclean/src/svgclean/js2svg.js create mode 100644 vendor/svgclean/src/svgclean/jsAPI.js create mode 100644 vendor/svgclean/src/svgclean/plugins/_collections.js create mode 100644 vendor/svgclean/src/svgclean/plugins/_path.js create mode 100644 vendor/svgclean/src/svgclean/plugins/_transforms.js create mode 100644 vendor/svgclean/src/svgclean/plugins/addAttributesToSVGElement.js create mode 100644 vendor/svgclean/src/svgclean/plugins/addClassesToSVGElement.js create mode 100644 vendor/svgclean/src/svgclean/plugins/cleanupAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/cleanupEnableBackground.js create mode 100644 vendor/svgclean/src/svgclean/plugins/cleanupIDs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/cleanupListOfValues.js create mode 100644 vendor/svgclean/src/svgclean/plugins/cleanupNumericValues.js create mode 100644 vendor/svgclean/src/svgclean/plugins/collapseGroups.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertColors.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertEllipseToCircle.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertPathData.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertShapeToPath.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertStyleToAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/convertTransform.js create mode 100644 vendor/svgclean/src/svgclean/plugins/inlineStyles.js create mode 100644 vendor/svgclean/src/svgclean/plugins/mergePaths.js create mode 100755 vendor/svgclean/src/svgclean/plugins/minifyStyles.js create mode 100644 vendor/svgclean/src/svgclean/plugins/moveElemsAttrsToGroup.js create mode 100644 vendor/svgclean/src/svgclean/plugins/moveGroupAttrsToElems.js create mode 100755 vendor/svgclean/src/svgclean/plugins/prefixIds.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeAttributesBySelector.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeComments.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeDesc.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeDimensions.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeDoctype.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeEditorsNSData.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeElementsByAttr.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeEmptyAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeEmptyContainers.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeEmptyText.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeHiddenElems.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeMetadata.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeNonInheritableGroupAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeOffCanvasPaths.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeRasterImages.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeScriptElement.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeStyleElement.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeTitle.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeUnknownsAndDefaults.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeUnusedNS.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeUselessDefs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeUselessStrokeAndFill.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeViewBox.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeXMLNS.js create mode 100644 vendor/svgclean/src/svgclean/plugins/removeXMLProcInst.js create mode 100644 vendor/svgclean/src/svgclean/plugins/reusePaths.js create mode 100644 vendor/svgclean/src/svgclean/plugins/sortAttrs.js create mode 100644 vendor/svgclean/src/svgclean/plugins/sortDefsChildren.js create mode 100644 vendor/svgclean/src/svgclean/svg2js.js create mode 100644 vendor/svgclean/src/svgclean/tools.js create mode 100644 vendor/svgclean/test.js create mode 100644 vendor/svgclean/test.svg diff --git a/vendor/svgclean/.gitignore b/vendor/svgclean/.gitignore new file mode 100644 index 000000000..285888763 --- /dev/null +++ b/vendor/svgclean/.gitignore @@ -0,0 +1,11 @@ +node_modules/ +lib-cov/ +html-report/ +lcov.info +bin/svgo-profiling +*.sublime-* +*.log +.DS_Store +.idea +.vscode +.npmrc diff --git a/vendor/svgclean/LICENSE b/vendor/svgclean/LICENSE new file mode 100644 index 000000000..10ba902be --- /dev/null +++ b/vendor/svgclean/LICENSE @@ -0,0 +1,25 @@ +The MIT License + +Copyright © 2021 Andrey Antukh <niwi@niwi.nz> +Copyright © 2012–2016 Kir Belevich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/svgclean/examples/test.js b/vendor/svgclean/examples/test.js new file mode 100644 index 000000000..e4f4fa43b --- /dev/null +++ b/vendor/svgclean/examples/test.js @@ -0,0 +1,101 @@ +'use strict'; + +var FS = require('fs'), + PATH = require('path'), + SVGO = require('../lib/svgo'), + filepath = PATH.resolve(__dirname, 'test.svg'), + svgo = new SVGO({ + plugins: [{ + cleanupAttrs: true, + }, { + removeDoctype: true, + },{ + removeXMLProcInst: true, + },{ + removeComments: true, + },{ + removeMetadata: true, + },{ + removeTitle: true, + },{ + removeDesc: true, + },{ + removeUselessDefs: true, + },{ + removeEditorsNSData: true, + },{ + removeEmptyAttrs: true, + },{ + removeHiddenElems: true, + },{ + removeEmptyText: true, + },{ + removeEmptyContainers: true, + },{ + removeViewBox: false, + },{ + cleanupEnableBackground: true, + },{ + convertStyleToAttrs: true, + },{ + convertColors: true, + },{ + convertPathData: true, + },{ + convertTransform: true, + },{ + removeUnknownsAndDefaults: true, + },{ + removeNonInheritableGroupAttrs: true, + },{ + removeUselessStrokeAndFill: true, + },{ + removeUnusedNS: true, + },{ + cleanupIDs: true, + },{ + cleanupNumericValues: true, + },{ + moveElemsAttrsToGroup: true, + },{ + moveGroupAttrsToElems: true, + },{ + collapseGroups: true, + },{ + removeRasterImages: false, + },{ + mergePaths: true, + },{ + convertShapeToPath: true, + },{ + sortAttrs: true, + },{ + removeDimensions: true, + },{ + removeAttrs: {attrs: '(stroke|fill)'}, + }] + }); + +FS.readFile(filepath, 'utf8', function(err, data) { + + if (err) { + throw err; + } + + svgo.optimize(data, {path: filepath}).then(function(result) { + + console.log(result); + + // { + // // optimized SVG data string + // data: '<svg width="10" height="20">test</svg>' + // // additional info such as width/height + // info: { + // width: '10', + // height: '20' + // } + // } + + }); + +}); diff --git a/vendor/svgclean/examples/test.svg b/vendor/svgclean/examples/test.svg new file mode 100644 index 000000000..c539cd408 --- /dev/null +++ b/vendor/svgclean/examples/test.svg @@ -0,0 +1,3 @@ +<svg version="1.1" width="10" height="20"> + test +</svg> diff --git a/vendor/svgclean/main.js b/vendor/svgclean/main.js new file mode 100644 index 000000000..48a9198b0 --- /dev/null +++ b/vendor/svgclean/main.js @@ -0,0 +1,43 @@ +const plugins = { + prefixIds: true, + cleanupAttrs: true, + cleanupEnableBackground: true, + cleanupIDs: true, + cleanupNumericValues: true, + collapseGroups: true, + convertColors: true, + convertEllipseToCircle: true, + convertPathData: true, + convertShapeToPath: true, + convertStyleToAttrs: true, + convertTransform: true, + inlineStyles: true, + mergePaths: false, + minifyStyles: true, + removeComments: true, + removeDesc: true, + removeDimensions: false, + removeDoctype: true, + removeEditorsNSData: true, + removeEmptyAttrs: true, + removeEmptyContainers: true, + removeEmptyText: true, + removeHiddenElems: true, + removeNonInheritableGroupAttrs: true, + removeRasterImages: true, + removeTitle: true, + removeUnknownsAndDefaults: true, + removeUnusedNS: true, + removeUselessDefs: true, + removeUselessStrokeAndFill: true, + removeXMLNS: true, + removeXMLProcInst: true +}; + +const svgc = require("./src/svgclean.js"); +const inst = svgc.configure({plugins}); + +exports.optimize = function(data) { + return svgc.optimize(inst, data) + .then((result) => result.data); +}; diff --git a/vendor/svgclean/package-lock.json b/vendor/svgclean/package-lock.json new file mode 100644 index 000000000..54f08f180 --- /dev/null +++ b/vendor/svgclean/package-lock.json @@ -0,0 +1,3488 @@ +{ + "name": "svgclean", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", + "requires": { + "array-filter": "^1.0.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "requires": { + "JSONStream": "^1.0.3", + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "requires": { + "resolve": "^1.17.0" + }, + "dependencies": { + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + } + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" + }, + "call-bind": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.1.tgz", + "integrity": "sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + }, + "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=" + }, + "coveralls": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.0.tgz", + "integrity": "sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==", + "dev": true, + "requires": { + "js-yaml": "^3.13.1", + "lcov-parse": "^1.0.0", + "log-driver": "^1.2.7", + "minimist": "^1.2.5", + "request": "^2.88.2" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-select": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz", + "integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^4.0.0", + "domhandler": "^4.0.0", + "domutils": "^2.4.3", + "nth-check": "^2.0.0" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz", + "integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==" + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + } + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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 + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "dom-serializer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + }, + "domutils": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", + "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "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 + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", + "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + }, + "dependencies": { + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", + "dev": true + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "~0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "requires": { + "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "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 + }, + "is-generator-function": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.4.tgz", + "integrity": "sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA==", + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jshint": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", + "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.19", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "requires": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "lcov-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", + "dev": true + }, + "mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "dev": true, + "requires": { + "mime-db": "1.45.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "mocha-istanbul": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mocha-istanbul/-/mocha-istanbul-0.3.0.tgz", + "integrity": "sha1-U8dNPoX/bix9EHWw5X4xdKvqZEY=", + "dev": true, + "requires": { + "istanbul": "*" + } + }, + "mock-stdin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mock-stdin/-/mock-stdin-1.0.0.tgz", + "integrity": "sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q==", + "dev": true + }, + "module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "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=" + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", + "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "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=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "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": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "requires": { + "minimist": "^1.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "requires": { + "acorn-node": "^1.2.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "~0.11.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "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, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "3.12.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.4.tgz", + "integrity": "sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A==", + "dev": true, + "optional": true + }, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz", + "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "for-each": "^0.3.3", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "which-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/vendor/svgclean/package.json b/vendor/svgclean/package.json new file mode 100644 index 000000000..af4cf28d5 --- /dev/null +++ b/vendor/svgclean/package.json @@ -0,0 +1,34 @@ +{ + "name": "svgclean", + "version": "1.0.0", + "description": "SVG Cleaner (SVGO Fork)", + "main": "./src/svgo.js", + "scripts": { + "test": "set NODE_ENV=test && mocha", + "lint": "jshint --show-non-errors ." + }, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^3.1.2", + "css-select-base-adapter": "^0.1.1", + "css-tree": "^1.1.2", + "csso": "^4.2.0", + "object.values": "^1.1.2", + "sax": "^1.2.4", + "stable": "^0.1.8", + "unquote": "^1.1.1", + "util.promisify": "^1.1.1" + }, + "devDependencies": { + "browserify": "^17.0.0", + "coveralls": "^3.1.0", + "fs-extra": "^9.0.1", + "istanbul": "^0.4.5", + "jshint": "^2.12.0", + "mocha": "^8.2.1", + "mocha-istanbul": "^0.3.0", + "mock-stdin": "^1.0.0", + "should": "~13.2.3" + }, + "license": "MIT" +} diff --git a/vendor/svgclean/src/svgclean.js b/vendor/svgclean/src/svgclean.js new file mode 100755 index 000000000..62582d616 --- /dev/null +++ b/vendor/svgclean/src/svgclean.js @@ -0,0 +1,59 @@ +'use strict'; + +// encodeSVGDatauri = require('./svgclean/tools.js').encodeSVGDatauri, + +const cfg = require("./svgclean/config.js"); +const svgToJs = require('./svgclean/svg2js.js'); +const jsToSvg = require('./svgclean/js2svg.js'); + +exports.configure = function(config={}) { + const plugins = cfg.loadPlugins(config); + return Object.assign({}, config, {plugins}); +}; + +exports.optimize = function(config, svgstr) { + const info = {}; + + return new Promise((resolve, reject) => { + let maxPassCount = config.multipass ? 10 : 1; + let counter = 0; + let prevResultSize = Number.POSITIVE_INFINITY; + + function optimize(root) { + if (root.error) { + reject(root.error); + return; + } + + info.multipassCount = counter; + if (++counter < maxPassCount && root.data.length < prevResultSize) { + prevResultSize = root.data.length; + runOptimizations(config, root.data, info, optimize); + } else { + // if (config.datauri) { + // root.data = encodeSVGDatauri(root.data, config.datauri); + // } + if (info && info.path) { + root.path = info.path; + } + + resolve(root); + } + }; + + runOptimizations(config, svgstr, info, optimize); + }); +}; + +function runOptimizations(config, svgstr, info, callback) { + const plugins = config.plugins; + + svgToJs(svgstr).then(function(doc) { + doc = cfg.executePlugins(plugins, doc, info); + // TODO: pass formating (js2svg) config + callback(jsToSvg(doc, config.format || {})); + }, function(error) { + callback({error: error}); + }); +}; + diff --git a/vendor/svgclean/src/svgclean/config.js b/vendor/svgclean/src/svgclean/config.js new file mode 100644 index 000000000..ce0652842 --- /dev/null +++ b/vendor/svgclean/src/svgclean/config.js @@ -0,0 +1,269 @@ +'use strict'; + +const _collections = require('./plugins/_collections'); +const _path = require('./plugins/_path'); +const _transforms = require('./plugins/_transforms'); +const addAttributesToSVGElement = require('./plugins/addAttributesToSVGElement'); +const addClassesToSVGElement = require('./plugins/addClassesToSVGElement'); +const cleanupAttrs = require('./plugins/cleanupAttrs'); +const cleanupEnableBackground = require('./plugins/cleanupEnableBackground'); +const cleanupIDs = require('./plugins/cleanupIDs'); +const cleanupListOfValues = require('./plugins/cleanupListOfValues'); +const cleanupNumericValues = require('./plugins/cleanupNumericValues'); +const collapseGroups = require('./plugins/collapseGroups'); +const convertColors = require('./plugins/convertColors'); +const convertEllipseToCircle = require('./plugins/convertEllipseToCircle'); +const convertPathData = require('./plugins/convertPathData'); +const convertShapeToPath = require('./plugins/convertShapeToPath'); +const convertStyleToAttrs = require('./plugins/convertStyleToAttrs'); +const convertTransform = require('./plugins/convertTransform'); +const inlineStyles = require('./plugins/inlineStyles'); +const mergePaths = require('./plugins/mergePaths'); +const minifyStyles = require('./plugins/minifyStyles'); +const moveElemsAttrsToGroup = require('./plugins/moveElemsAttrsToGroup'); +const moveGroupAttrsToElems = require('./plugins/moveGroupAttrsToElems'); +const prefixIds = require('./plugins/prefixIds'); +const removeAttributesBySelector = require('./plugins/removeAttributesBySelector'); +const removeAttrs = require('./plugins/removeAttrs'); +const removeComments = require('./plugins/removeComments'); +const removeDesc = require('./plugins/removeDesc'); +const removeDimensions = require('./plugins/removeDimensions'); +const removeDoctype = require('./plugins/removeDoctype'); +const removeEditorsNSData = require('./plugins/removeEditorsNSData'); +const removeElementsByAttr = require('./plugins/removeElementsByAttr'); +const removeEmptyAttrs = require('./plugins/removeEmptyAttrs'); +const removeEmptyContainers = require('./plugins/removeEmptyContainers'); +const removeEmptyText = require('./plugins/removeEmptyText'); +const removeHiddenElems = require('./plugins/removeHiddenElems'); +const removeMetadata = require('./plugins/removeMetadata'); +const removeNonInheritableGroupAttrs = require('./plugins/removeNonInheritableGroupAttrs'); +const removeOffCanvasPaths = require('./plugins/removeOffCanvasPaths'); +const removeRasterImages = require('./plugins/removeRasterImages'); +const removeScriptElement = require('./plugins/removeScriptElement'); +const removeStyleElement = require('./plugins/removeStyleElement'); +const removeTitle = require('./plugins/removeTitle'); +const removeUnknownsAndDefaults = require('./plugins/removeUnknownsAndDefaults'); +const removeUnusedNS = require('./plugins/removeUnusedNS'); +const removeUselessDefs = require('./plugins/removeUselessDefs'); +const removeUselessStrokeAndFill = require('./plugins/removeUselessStrokeAndFill'); +const removeViewBox = require('./plugins/removeViewBox'); +const removeXMLNS = require('./plugins/removeXMLNS'); +const removeXMLProcInst = require('./plugins/removeXMLProcInst'); +const reusePaths = require('./plugins/reusePaths'); +const sortAttrs = require('./plugins/sortAttrs'); +const sortDefsChildren = require('./plugins/sortDefsChildren'); + +const builtinPlugins = { + removeOffCanvasPaths, + _collections, + _path, + _transforms, + addAttributesToSVGElement, + addClassesToSVGElement, + cleanupAttrs, + cleanupEnableBackground, + cleanupIDs, + cleanupListOfValues, + cleanupNumericValues, + collapseGroups, + convertColors, + convertEllipseToCircle, + convertPathData, + convertShapeToPath, + convertStyleToAttrs, + convertTransform, + inlineStyles, + mergePaths, + minifyStyles, + moveElemsAttrsToGroup, + moveGroupAttrsToElems, + prefixIds, + removeAttributesBySelector, + removeAttrs, + removeComments, + removeDesc, + removeDimensions, + removeDoctype, + removeEditorsNSData, + removeElementsByAttr, + removeEmptyAttrs, + removeEmptyContainers, + removeEmptyText, + removeHiddenElems, + removeMetadata, + removeNonInheritableGroupAttrs, + removeRasterImages, + removeScriptElement, + removeStyleElement, + removeTitle, + removeUnknownsAndDefaults, + removeUnusedNS, + removeUselessDefs, + removeUselessStrokeAndFill, + removeViewBox, + removeXMLNS, + removeXMLProcInst, + reusePaths, + sortAttrs, + sortDefsChildren, +}; + +const defaultPlugins = { + prefixIds: true, + cleanupAttrs: true, + cleanupEnableBackground: true, + cleanupIDs: true, + cleanupNumericValues: true, + collapseGroups: true, + convertColors: true, + convertEllipseToCircle: true, + convertPathData: true, + convertShapeToPath: true, + convertStyleToAttrs: true, + convertTransform: true, + inlineStyles: true, + mergePaths: false, + minifyStyles: true, + moveElemsAttrsToGroup: false, + moveGroupAttrsToElems: false, + removeComments: true, + removeDesc: true, + removeDimensions: false, + removeDoctype: true, + removeEditorsNSData: true, + removeEmptyAttrs: true, + removeEmptyContainers: true, + removeEmptyText: true, + removeHiddenElems: true, + removeNonInheritableGroupAttrs: true, + removeRasterImages: true, + removeTitle: true, + removeUnknownsAndDefaults: true, + removeUnusedNS: true, + removeUselessDefs: true, + removeUselessStrokeAndFill: true, + removeViewBox: false, + removeXMLNS: true, + removeXMLProcInst: true, + sortAttrs: false, + sortDefsChildren: true +}; + +function optimizePlugins(plugins) { + let prev; + + return plugins.reduce(function(plugins, item) { + if (prev && item.type == prev[0].type) { + prev.push(item); + } else { + plugins.push(prev = [item]); + } + return plugins; + }, []); +} + +exports.loadPlugins = function(config={}) { + let plugins = Object.assign({}, config.plugins || defaultPlugins); + let configuredPlugins = []; + + for (let key of Object.keys(plugins)) { + let pluginOpt = plugins[key]; + let plugin = null; + + if (typeof pluginOpt === "object") { + plugin = Object.assign({}, builtinPlugins[key]); + plugin.params = Object.assign({}, pluginOpt); + } else if (pluginOpt === true) { + plugin = Object.assign({}, builtinPlugins[key]); + } else { + continue; + } + + plugin.active = true; + configuredPlugins.push(plugin); + } + + return optimizePlugins(configuredPlugins); +}; + +exports.executePlugins = function(plugins, data, info) { + plugins.forEach(function(group) { + switch(group[0].type) { + case 'perItem': + data = perItem(data, info, group); + break; + case 'perItemReverse': + data = perItem(data, info, group, true); + break; + case 'full': + data = full(data, info, group); + break; + } + + }); + + return data; +} + +/** + * Direct or reverse per-item loop. + * + * @param {Object} data input data + * @param {Object} info extra information + * @param {Array} plugins plugins list to process + * @param {Boolean} [reverse] reverse pass? + * @return {Object} output data + */ +function perItem(data, info, plugins, reverse) { + + function monkeys(items) { + items.content = items.content.filter(function(item) { + + // reverse pass + if (reverse && item.content) { + monkeys(item); + } + + // main filter + let filter = true; + + for (let i = 0; filter && i < plugins.length; i++) { + let plugin = plugins[i]; + + if (plugin.active && plugin.fn(item, plugin.params, info) === false) { + filter = false; + } + } + + // direct pass + if (!reverse && item.content) { + monkeys(item); + } + + return filter; + + }); + + return items; + + } + + return monkeys(data); +} + +/** + * "Full" plugins. + * + * @param {Object} data input data + * @param {Object} info extra information + * @param {Array} plugins plugins list to process + * @return {Object} output data + */ +function full(data, info, plugins) { + plugins.forEach(function(plugin) { + if (plugin.active) { + data = plugin.fn(data, plugin.params, info); + } + }); + return data; +} diff --git a/vendor/svgclean/src/svgclean/css-class-list.js b/vendor/svgclean/src/svgclean/css-class-list.js new file mode 100644 index 000000000..8401a9f84 --- /dev/null +++ b/vendor/svgclean/src/svgclean/css-class-list.js @@ -0,0 +1,138 @@ +'use strict'; + +var values = require('object.values'); +if (!Object.values) { + values.shim(); +} + + +var CSSClassList = function(node) { + this.parentNode = node; + this.classNames = new Set(); + this.classAttr = null; + //this.classValue = null; +}; + +/** + * Performs a deep clone of this object. + * + * @param parentNode the parentNode to assign to the cloned result + */ +CSSClassList.prototype.clone = function(parentNode) { + var node = this; + var nodeData = {}; + + Object.keys(node).forEach(function(key) { + if (key !== 'parentNode') { + nodeData[key] = node[key]; + } + }); + + // Deep-clone node data. + nodeData = JSON.parse(JSON.stringify(nodeData)); + + var clone = new CSSClassList(parentNode); + Object.assign(clone, nodeData); + return clone; +}; + +CSSClassList.prototype.hasClass = function() { + this.classAttr = { // empty class attr + 'name': 'class', + 'value': null + }; + + this.addClassHandler(); +}; + + +// attr.class + +CSSClassList.prototype.addClassHandler = function() { + + Object.defineProperty(this.parentNode.attrs, 'class', { + get: this.getClassAttr.bind(this), + set: this.setClassAttr.bind(this), + enumerable: true, + configurable: true + }); + + this.addClassValueHandler(); +}; + +// attr.class.value + +CSSClassList.prototype.addClassValueHandler = function() { + + Object.defineProperty(this.classAttr, 'value', { + get: this.getClassValue.bind(this), + set: this.setClassValue.bind(this), + enumerable: true, + configurable: true + }); +}; + +CSSClassList.prototype.getClassAttr = function() { + return this.classAttr; +}; + +CSSClassList.prototype.setClassAttr = function(newClassAttr) { + this.setClassValue(newClassAttr.value); // must before applying value handler! + + this.classAttr = newClassAttr; + this.addClassValueHandler(); +}; + +CSSClassList.prototype.getClassValue = function() { + var arrClassNames = Array.from(this.classNames); + return arrClassNames.join(' '); +}; + +CSSClassList.prototype.setClassValue = function(newValue) { + if(typeof newValue === 'undefined') { + this.classNames.clear(); + return; + } + var arrClassNames = newValue.split(' '); + this.classNames = new Set(arrClassNames); +}; + + +CSSClassList.prototype.add = function(/* variadic */) { + this.hasClass(); + Object.values(arguments).forEach(this._addSingle.bind(this)); +}; + +CSSClassList.prototype._addSingle = function(className) { + this.classNames.add(className); +}; + + +CSSClassList.prototype.remove = function(/* variadic */) { + this.hasClass(); + Object.values(arguments).forEach(this._removeSingle.bind(this)); +}; + +CSSClassList.prototype._removeSingle = function(className) { + this.classNames.delete(className); +}; + + +CSSClassList.prototype.item = function(index) { + var arrClassNames = Array.from(this.classNames); + return arrClassNames[index]; +}; + +CSSClassList.prototype.toggle = function(className, force) { + if(this.contains(className) || force === false) { + this.classNames.delete(className); + } + this.classNames.add(className); +}; + +CSSClassList.prototype.contains = function(className) { + return this.classNames.has(className); +}; + + +module.exports = CSSClassList; \ No newline at end of file diff --git a/vendor/svgclean/src/svgclean/css-select-adapter.js b/vendor/svgclean/src/svgclean/css-select-adapter.js new file mode 100644 index 000000000..c37678cbf --- /dev/null +++ b/vendor/svgclean/src/svgclean/css-select-adapter.js @@ -0,0 +1,53 @@ +'use strict'; + +var baseCssAdapter = require('css-select-base-adapter'); + +/** + * DOMUtils API for SVGO AST (used by css-select) + */ +var svgoCssSelectAdapterMin = { + + // is the node a tag? + // isTag: ( node:Node ) => isTag:Boolean + isTag: function(node) { + return node.isElem(); + }, + + // get the parent of the node + // getParent: ( node:Node ) => parentNode:Node + // returns null when no parent exists + getParent: function(node) { + return node.parentNode || null; + }, + + // get the node's children + // getChildren: ( node:Node ) => children:[Node] + getChildren: function(node) { + return node.content || []; + }, + + // get the name of the tag + // getName: ( elem:ElementNode ) => tagName:String + getName: function(elemAst) { + return elemAst.elem; + }, + + // get the text content of the node, and its children if it has any + // getText: ( node:Node ) => text:String + // returns empty string when there is no text + getText: function(node) { + return node.content[0].text || node.content[0].cdata || ''; + }, + + // get the attribute value + // getAttributeValue: ( elem:ElementNode, name:String ) => value:String + // returns null when attribute doesn't exist + getAttributeValue: function(elem, name) { + return elem.hasAttr(name) ? elem.attr(name).value : null; + } +}; + +// use base adapter for default implementation +var svgoCssSelectAdapter = baseCssAdapter(svgoCssSelectAdapterMin); + +module.exports = svgoCssSelectAdapter; diff --git a/vendor/svgclean/src/svgclean/css-style-declaration.js b/vendor/svgclean/src/svgclean/css-style-declaration.js new file mode 100644 index 000000000..ea389114c --- /dev/null +++ b/vendor/svgclean/src/svgclean/css-style-declaration.js @@ -0,0 +1,285 @@ +'use strict'; + +var csstree = require('css-tree'), + csstools = require('./css-tools'); + + +var CSSStyleDeclaration = function(node) { + this.parentNode = node; + + this.properties = new Map(); + this.hasSynced = false; + + this.styleAttr = null; + this.styleValue = null; + + this.parseError = false; +}; + +/** + * Performs a deep clone of this object. + * + * @param parentNode the parentNode to assign to the cloned result + */ +CSSStyleDeclaration.prototype.clone = function(parentNode) { + var node = this; + var nodeData = {}; + + Object.keys(node).forEach(function(key) { + if (key !== 'parentNode') { + nodeData[key] = node[key]; + } + }); + + // Deep-clone node data. + nodeData = JSON.parse(JSON.stringify(nodeData)); + + var clone = new CSSStyleDeclaration(parentNode); + Object.assign(clone, nodeData); + return clone; +}; + +CSSStyleDeclaration.prototype.hasStyle = function() { + this.addStyleHandler(); +}; + + + + +// attr.style + +CSSStyleDeclaration.prototype.addStyleHandler = function() { + + this.styleAttr = { // empty style attr + 'name': 'style', + 'value': null + }; + + Object.defineProperty(this.parentNode.attrs, 'style', { + get: this.getStyleAttr.bind(this), + set: this.setStyleAttr.bind(this), + enumerable: true, + configurable: true + }); + + this.addStyleValueHandler(); +}; + +// attr.style.value + +CSSStyleDeclaration.prototype.addStyleValueHandler = function() { + + Object.defineProperty(this.styleAttr, 'value', { + get: this.getStyleValue.bind(this), + set: this.setStyleValue.bind(this), + enumerable: true, + configurable: true + }); +}; + +CSSStyleDeclaration.prototype.getStyleAttr = function() { + return this.styleAttr; +}; + +CSSStyleDeclaration.prototype.setStyleAttr = function(newStyleAttr) { + this.setStyleValue(newStyleAttr.value); // must before applying value handler! + + this.styleAttr = newStyleAttr; + this.addStyleValueHandler(); + this.hasSynced = false; // raw css changed +}; + +CSSStyleDeclaration.prototype.getStyleValue = function() { + return this.getCssText(); +}; + +CSSStyleDeclaration.prototype.setStyleValue = function(newValue) { + this.properties.clear(); // reset all existing properties + this.styleValue = newValue; + this.hasSynced = false; // raw css changed +}; + + + + +CSSStyleDeclaration.prototype._loadCssText = function() { + if (this.hasSynced) { + return; + } + this.hasSynced = true; // must be set here to prevent loop in setProperty(...) + + if (!this.styleValue || this.styleValue.length === 0) { + return; + } + var inlineCssStr = this.styleValue; + + var declarations = {}; + try { + declarations = csstree.parse(inlineCssStr, { + context: 'declarationList', + parseValue: false + }); + } catch (parseError) { + this.parseError = parseError; + return; + } + this.parseError = false; + + var self = this; + declarations.children.each(function(declaration) { + try { + var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration); + self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); + } catch(styleError) { + if(styleError.message !== 'Unknown node type: undefined') { + self.parseError = styleError; + } + } + }); +}; + + +// only reads from properties + +/** + * Get the textual representation of the declaration block (equivalent to .cssText attribute). + * + * @return {String} Textual representation of the declaration block (empty string for no properties) + */ +CSSStyleDeclaration.prototype.getCssText = function() { + var properties = this.getProperties(); + + if (this.parseError) { + // in case of a parse error, pass through original styles + return this.styleValue; + } + + var cssText = []; + properties.forEach(function(property, propertyName) { + var strImportant = property.priority === 'important' ? '!important' : ''; + cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant); + }); + return cssText.join(';'); +}; + +CSSStyleDeclaration.prototype._handleParseError = function() { + if (this.parseError) { + console.warn('Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr(\'style\').value. Error details: ' + this.parseError); + } +}; + + +CSSStyleDeclaration.prototype._getProperty = function(propertyName) { + if(typeof propertyName === 'undefined') { + throw Error('1 argument required, but only 0 present.'); + } + + var properties = this.getProperties(); + this._handleParseError(); + + var property = properties.get(propertyName.trim()); + return property; +}; + +/** + * Return the optional priority, "important". + * + * @param {String} propertyName representing the property name to be checked. + * @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string. + */ +CSSStyleDeclaration.prototype.getPropertyPriority = function(propertyName) { + var property = this._getProperty(propertyName); + return property ? property.priority : ''; +}; + +/** + * Return the property value given a property name. + * + * @param {String} propertyName representing the property name to be checked. + * @return {String} value containing the value of the property. If not set, returns the empty string. + */ +CSSStyleDeclaration.prototype.getPropertyValue = function(propertyName) { + var property = this._getProperty(propertyName); + return property ? property.value : null; +}; + +/** + * Return a property name. + * + * @param {Number} index of the node to be fetched. The index is zero-based. + * @return {String} propertyName that is the name of the CSS property at the specified index. + */ +CSSStyleDeclaration.prototype.item = function(index) { + if(typeof index === 'undefined') { + throw Error('1 argument required, but only 0 present.'); + } + + var properties = this.getProperties(); + this._handleParseError(); + + return Array.from(properties.keys())[index]; +}; + +/** + * Return all properties of the node. + * + * @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value. + */ +CSSStyleDeclaration.prototype.getProperties = function() { + this._loadCssText(); + return this.properties; +}; + + +// writes to properties + +/** + * Remove a property from the CSS declaration block. + * + * @param {String} propertyName representing the property name to be removed. + * @return {String} oldValue equal to the value of the CSS property before it was removed. + */ +CSSStyleDeclaration.prototype.removeProperty = function(propertyName) { + if(typeof propertyName === 'undefined') { + throw Error('1 argument required, but only 0 present.'); + } + + this.hasStyle(); + + var properties = this.getProperties(); + this._handleParseError(); + + var oldValue = this.getPropertyValue(propertyName); + properties.delete(propertyName.trim()); + return oldValue; +}; + +/** + * Modify an existing CSS property or creates a new CSS property in the declaration block. + * + * @param {String} propertyName representing the CSS property name to be modified. + * @param {String} [value] containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter. + * @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string. + * @return {undefined} + */ +CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priority) { + if(typeof propertyName === 'undefined') { + throw Error('propertyName argument required, but only not present.'); + } + + this.hasStyle(); + + var properties = this.getProperties(); + this._handleParseError(); + + var property = { + value: value.trim(), + priority: priority.trim() + }; + properties.set(propertyName.trim(), property); + + return property; +}; + + +module.exports = CSSStyleDeclaration; diff --git a/vendor/svgclean/src/svgclean/css-tools.js b/vendor/svgclean/src/svgclean/css-tools.js new file mode 100644 index 000000000..6517892b8 --- /dev/null +++ b/vendor/svgclean/src/svgclean/css-tools.js @@ -0,0 +1,222 @@ +'use strict'; + +var csstree = require('css-tree'), + List = csstree.List, + stable = require('stable'), + specificity = require('csso/lib/restructure/prepare/specificity'); + + +/** + * Flatten a CSS AST to a selectors list. + * + * @param {Object} cssAst css-tree AST to flatten + * @return {Array} selectors + */ +function flattenToSelectors(cssAst) { + var selectors = []; + + csstree.walk(cssAst, {visit: 'Rule', enter: function(node) { + if (node.type !== 'Rule') { + return; + } + + var atrule = this.atrule; + var rule = node; + + node.prelude.children.each(function(selectorNode, selectorItem) { + var selector = { + item: selectorItem, + atrule: atrule, + rule: rule, + pseudos: [] + }; + + selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) { + if (selectorChildNode.type === 'PseudoClassSelector' || + selectorChildNode.type === 'PseudoElementSelector') { + selector.pseudos.push({ + item: selectorChildItem, + list: selectorChildList + }); + } + }); + + selectors.push(selector); + }); + }}); + + return selectors; +} + +/** + * Filter selectors by Media Query. + * + * @param {Array} selectors to filter + * @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>) + * @return {Array} Filtered selectors that match the passed media queries + */ +function filterByMqs(selectors, useMqs) { + return selectors.filter(function(selector) { + if (selector.atrule === null) { + return ~useMqs.indexOf(''); + } + + var mqName = selector.atrule.name; + var mqStr = mqName; + if (selector.atrule.expression && + selector.atrule.expression.children.first().type === 'MediaQueryList') { + var mqExpr = csstree.generate(selector.atrule.expression); + mqStr = [mqName, mqExpr].join(' '); + } + + return ~useMqs.indexOf(mqStr); + }); +} + +/** + * Filter selectors by the pseudo-elements and/or -classes they contain. + * + * @param {Array} selectors to filter + * @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass + * @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes + */ +function filterByPseudos(selectors, usePseudos) { + return selectors.filter(function(selector) { + var pseudoSelectorsStr = csstree.generate({ + type: 'Selector', + children: new List().fromArray(selector.pseudos.map(function(pseudo) { + return pseudo.item.data; + })) + }); + return ~usePseudos.indexOf(pseudoSelectorsStr); + }); +} + +/** + * Remove pseudo-elements and/or -classes from the selectors for proper matching. + * + * @param {Array} selectors to clean + * @return {Array} Selectors without pseudo-elements and/or -classes + */ +function cleanPseudos(selectors) { + selectors.forEach(function(selector) { + selector.pseudos.forEach(function(pseudo) { + pseudo.list.remove(pseudo.item); + }); + }); +} + + +/** + * Compares two selector specificities. + * extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211 + * + * @param {Array} aSpecificity Specificity of selector A + * @param {Array} bSpecificity Specificity of selector B + * @return {Number} Score of selector specificity A compared to selector specificity B + */ +function compareSpecificity(aSpecificity, bSpecificity) { + for (var i = 0; i < 4; i += 1) { + if (aSpecificity[i] < bSpecificity[i]) { + return -1; + } else if (aSpecificity[i] > bSpecificity[i]) { + return 1; + } + } + + return 0; +} + + +/** + * Compare two simple selectors. + * + * @param {Object} aSimpleSelectorNode Simple selector A + * @param {Object} bSimpleSelectorNode Simple selector B + * @return {Number} Score of selector A compared to selector B + */ +function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) { + var aSpecificity = specificity(aSimpleSelectorNode), + bSpecificity = specificity(bSimpleSelectorNode); + return compareSpecificity(aSpecificity, bSpecificity); +} + +function _bySelectorSpecificity(selectorA, selectorB) { + return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data); +} + + +/** + * Sort selectors stably by their specificity. + * + * @param {Array} selectors to be sorted + * @return {Array} Stable sorted selectors + */ +function sortSelectors(selectors) { + return stable(selectors, _bySelectorSpecificity); +} + + +/** + * Convert a css-tree AST style declaration to CSSStyleDeclaration property. + * + * @param {Object} declaration css-tree style declaration + * @return {Object} CSSStyleDeclaration property + */ +function csstreeToStyleDeclaration(declaration) { + var propertyName = declaration.property, + propertyValue = csstree.generate(declaration.value), + propertyPriority = (declaration.important ? 'important' : ''); + return { + name: propertyName, + value: propertyValue, + priority: propertyPriority + }; +} + + +/** + * Gets the CSS string of a style element + * + * @param {Object} element style element + * @return {String|Array} CSS string or empty array if no styles are set + */ +function getCssStr(elem) { + return elem.content[0].text || elem.content[0].cdata || []; +} + +/** + * Sets the CSS string of a style element + * + * @param {Object} element style element + * @param {String} CSS string to be set + * @return {Object} reference to field with CSS + */ +function setCssStr(elem, css) { + // in case of cdata field + if(elem.content[0].cdata) { + elem.content[0].cdata = css; + return elem.content[0].cdata; + } + + // in case of text field + if nothing was set yet + elem.content[0].text = css; + return elem.content[0].text; +} + + +module.exports.flattenToSelectors = flattenToSelectors; + +module.exports.filterByMqs = filterByMqs; +module.exports.filterByPseudos = filterByPseudos; +module.exports.cleanPseudos = cleanPseudos; + +module.exports.compareSpecificity = compareSpecificity; +module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode; + +module.exports.sortSelectors = sortSelectors; + +module.exports.csstreeToStyleDeclaration = csstreeToStyleDeclaration; + +module.exports.getCssStr = getCssStr; +module.exports.setCssStr = setCssStr; diff --git a/vendor/svgclean/src/svgclean/js2svg.js b/vendor/svgclean/src/svgclean/js2svg.js new file mode 100644 index 000000000..6ed123f9a --- /dev/null +++ b/vendor/svgclean/src/svgclean/js2svg.js @@ -0,0 +1,346 @@ +'use strict'; + +const EOL = "\n"; +const textElem = require('./plugins/_collections.js').elemsGroups.textContent.concat('title'); + +var defaults = { + doctypeStart: '<!DOCTYPE', + doctypeEnd: '>', + procInstStart: '<?', + procInstEnd: '?>', + tagOpenStart: '<', + tagOpenEnd: '>', + tagCloseStart: '</', + tagCloseEnd: '>', + tagShortStart: '<', + tagShortEnd: '/>', + attrStart: '="', + attrEnd: '"', + commentStart: '<!--', + commentEnd: '-->', + cdataStart: '<![CDATA[', + cdataEnd: ']]>', + textStart: '', + textEnd: '', + indent: 4, + regEntities: /[&'"<>]/g, + regValEntities: /[&"<>]/g, + encodeEntity: encodeEntity, + pretty: false, + useShortTags: true +}; + +var entities = { + '&': '&', + '\'': ''', + '"': '"', + '>': '>', + '<': '<', +}; + +/** + * Convert SVG-as-JS object to SVG (XML) string. + * + * @param {Object} data input data + * @param {Object} config config + * + * @return {Object} output data + */ +module.exports = function(data, config) { + return new JS2SVG(config).convert(data); + +}; + +function JS2SVG(config) { + if (config) { + this.config = Object.assign({}, defaults, config); + } else { + this.config = Object.assign({}, defaults); + } + + var indent = this.config.indent; + if (typeof indent == 'number' && !isNaN(indent)) { + this.config.indent = (indent < 0) ? '\t' : ' '.repeat(indent); + } else if (typeof indent != 'string') { + this.config.indent = ' '; + } + + if (this.config.pretty) { + this.config.doctypeEnd += EOL; + this.config.procInstEnd += EOL; + this.config.commentEnd += EOL; + this.config.cdataEnd += EOL; + this.config.tagShortEnd += EOL; + this.config.tagOpenEnd += EOL; + this.config.tagCloseEnd += EOL; + this.config.textEnd += EOL; + } + + this.indentLevel = 0; + this.textContext = null; + +} + +function encodeEntity(char) { + return entities[char]; +} + +/** + * Start conversion. + * + * @param {Object} data input data + * + * @return {String} + */ +JS2SVG.prototype.convert = function(data) { + + var svg = ''; + + if (data.content) { + + this.indentLevel++; + + data.content.forEach(function(item) { + + if (item.elem) { + svg += this.createElem(item); + } else if (item.text) { + svg += this.createText(item.text); + } else if (item.doctype) { + svg += this.createDoctype(item.doctype); + } else if (item.processinginstruction) { + svg += this.createProcInst(item.processinginstruction); + } else if (item.comment) { + svg += this.createComment(item.comment); + } else if (item.cdata) { + svg += this.createCDATA(item.cdata); + } + + }, this); + + } + + this.indentLevel--; + + return { + data: svg, + info: { + width: this.width, + height: this.height + } + }; + +}; + +/** + * Create indent string in accordance with the current node level. + * + * @return {String} + */ +JS2SVG.prototype.createIndent = function() { + + var indent = ''; + + if (this.config.pretty && !this.textContext) { + indent = this.config.indent.repeat(this.indentLevel - 1); + } + + return indent; + +}; + +/** + * Create doctype tag. + * + * @param {String} doctype doctype body string + * + * @return {String} + */ +JS2SVG.prototype.createDoctype = function(doctype) { + + return this.config.doctypeStart + + doctype + + this.config.doctypeEnd; + +}; + +/** + * Create XML Processing Instruction tag. + * + * @param {Object} instruction instruction object + * + * @return {String} + */ +JS2SVG.prototype.createProcInst = function(instruction) { + + return this.config.procInstStart + + instruction.name + + ' ' + + instruction.body + + this.config.procInstEnd; + +}; + +/** + * Create comment tag. + * + * @param {String} comment comment body + * + * @return {String} + */ +JS2SVG.prototype.createComment = function(comment) { + + return this.config.commentStart + + comment + + this.config.commentEnd; + +}; + +/** + * Create CDATA section. + * + * @param {String} cdata CDATA body + * + * @return {String} + */ +JS2SVG.prototype.createCDATA = function(cdata) { + + return this.createIndent() + + this.config.cdataStart + + cdata + + this.config.cdataEnd; + +}; + +/** + * Create element tag. + * + * @param {Object} data element object + * + * @return {String} + */ +JS2SVG.prototype.createElem = function(data) { + + // beautiful injection for obtaining SVG information :) + if ( + data.isElem('svg') && + data.hasAttr('width') && + data.hasAttr('height') + ) { + this.width = data.attr('width').value; + this.height = data.attr('height').value; + } + + // empty element and short tag + if (data.isEmpty()) { + if (this.config.useShortTags) { + return this.createIndent() + + this.config.tagShortStart + + data.elem + + this.createAttrs(data) + + this.config.tagShortEnd; + } else { + return this.createIndent() + + this.config.tagShortStart + + data.elem + + this.createAttrs(data) + + this.config.tagOpenEnd + + this.config.tagCloseStart + + data.elem + + this.config.tagCloseEnd; + } + // non-empty element + } else { + var tagOpenStart = this.config.tagOpenStart, + tagOpenEnd = this.config.tagOpenEnd, + tagCloseStart = this.config.tagCloseStart, + tagCloseEnd = this.config.tagCloseEnd, + openIndent = this.createIndent(), + textIndent = '', + processedData = '', + dataEnd = ''; + + if (this.textContext) { + tagOpenStart = defaults.tagOpenStart; + tagOpenEnd = defaults.tagOpenEnd; + tagCloseStart = defaults.tagCloseStart; + tagCloseEnd = defaults.tagCloseEnd; + openIndent = ''; + } else if (data.isElem(textElem)) { + if (this.config.pretty) { + textIndent += openIndent + this.config.indent; + } + this.textContext = data; + } + + processedData += this.convert(data).data; + + if (this.textContext == data) { + this.textContext = null; + if (this.config.pretty) dataEnd = EOL; + } + + return openIndent + + tagOpenStart + + data.elem + + this.createAttrs(data) + + tagOpenEnd + + textIndent + + processedData + + dataEnd + + this.createIndent() + + tagCloseStart + + data.elem + + tagCloseEnd; + + } + +}; + +/** + * Create element attributes. + * + * @param {Object} elem attributes object + * + * @return {String} + */ +JS2SVG.prototype.createAttrs = function(elem) { + + var attrs = ''; + + elem.eachAttr(function(attr) { + + if (attr.value !== undefined) { + attrs += ' ' + + attr.name + + this.config.attrStart + + String(attr.value).replace(this.config.regValEntities, this.config.encodeEntity) + + this.config.attrEnd; + } + else { + attrs += ' ' + + attr.name; + } + + + }, this); + + return attrs; + +}; + +/** + * Create text node. + * + * @param {String} text text + * + * @return {String} + */ +JS2SVG.prototype.createText = function(text) { + + return this.createIndent() + + this.config.textStart + + text.replace(this.config.regEntities, this.config.encodeEntity) + + (this.textContext ? '' : this.config.textEnd); + +}; diff --git a/vendor/svgclean/src/svgclean/jsAPI.js b/vendor/svgclean/src/svgclean/jsAPI.js new file mode 100644 index 000000000..354e4672e --- /dev/null +++ b/vendor/svgclean/src/svgclean/jsAPI.js @@ -0,0 +1,372 @@ +'use strict'; + +var cssSelect = require('css-select'); + +var svgoCssSelectAdapter = require('./css-select-adapter'); +var cssSelectOpts = { + xmlMode: true, + adapter: svgoCssSelectAdapter +}; + +var JSAPI = module.exports = function(data, parentNode) { + Object.assign(this, data); + if (parentNode) { + Object.defineProperty(this, 'parentNode', { + writable: true, + value: parentNode + }); + } +}; + +/** + * Perform a deep clone of this node. + * + * @return {Object} element + */ +JSAPI.prototype.clone = function() { + var node = this; + var nodeData = {}; + + Object.keys(node).forEach(function(key) { + if (key !== 'class' && key !== 'style' && key !== 'content') { + nodeData[key] = node[key]; + } + }); + + // Deep-clone node data. + nodeData = JSON.parse(JSON.stringify(nodeData)); + + // parentNode gets set to a proper object by the parent clone, + // but it needs to be true/false now to do the right thing + // in the constructor. + var clonedNode = new JSAPI(nodeData, !!node.parentNode); + + if (node.class) { + clonedNode.class = node.class.clone(clonedNode); + } + if (node.style) { + clonedNode.style = node.style.clone(clonedNode); + } + if (node.content) { + clonedNode.content = node.content.map(function(childNode) { + var clonedChild = childNode.clone(); + clonedChild.parentNode = clonedNode; + return clonedChild; + }); + } + + return clonedNode; +}; + +/** + * Determine if item is an element + * (any, with a specific name or in a names array). + * + * @param {String|Array} [param] element name or names arrays + * @return {Boolean} + */ +JSAPI.prototype.isElem = function(param) { + + if (!param) return !!this.elem; + + if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1); + + return !!this.elem && this.elem === param; + +}; + +/** + * Renames an element + * + * @param {String} name new element name + * @return {Object} element + */ +JSAPI.prototype.renameElem = function(name) { + + if (name && typeof name === 'string') + this.elem = this.local = name; + + return this; + +}; + +/** + * Determine if element is empty. + * + * @return {Boolean} + */ + JSAPI.prototype.isEmpty = function() { + + return !this.content || !this.content.length; + +}; + +/** + * Find the closest ancestor of the current element. + * @param elemName + * + * @return {?Object} + */ + JSAPI.prototype.closestElem = function(elemName) { + var elem = this; + + while ((elem = elem.parentNode) && !elem.isElem(elemName)); + + return elem; +}; + +/** + * Changes content by removing elements and/or adding new elements. + * + * @param {Number} start Index at which to start changing the content. + * @param {Number} n Number of elements to remove. + * @param {Array|Object} [insertion] Elements to add to the content. + * @return {Array} Removed elements. + */ + JSAPI.prototype.spliceContent = function(start, n, insertion) { + + if (arguments.length < 2) return []; + + if (!Array.isArray(insertion)) + insertion = Array.apply(null, arguments).slice(2); + + insertion.forEach(function(inner) { inner.parentNode = this }, this); + + return this.content.splice.apply(this.content, [start, n].concat(insertion)); + + +}; + +/** + * Determine if element has an attribute + * (any, or by name or by name + value). + * + * @param {String} [name] attribute name + * @param {String} [val] attribute value (will be toString()'ed) + * @return {Boolean} + */ + JSAPI.prototype.hasAttr = function(name, val) { + + if (!this.attrs || !Object.keys(this.attrs).length) return false; + + if (!arguments.length) return !!this.attrs; + + if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString(); + + return !!this.attrs[name]; + +}; + +/** + * Determine if element has an attribute by local name + * (any, or by name or by name + value). + * + * @param {String} [localName] local attribute name + * @param {Number|String|RegExp|Function} [val] attribute value (will be toString()'ed or executed, otherwise ignored) + * @return {Boolean} + */ + JSAPI.prototype.hasAttrLocal = function(localName, val) { + + if (!this.attrs || !Object.keys(this.attrs).length) return false; + + if (!arguments.length) return !!this.attrs; + + var callback; + + switch (val != null && val.constructor && val.constructor.name) { + case 'Number': // same as String + case 'String': callback = stringValueTest; break; + case 'RegExp': callback = regexpValueTest; break; + case 'Function': callback = funcValueTest; break; + default: callback = nameTest; + } + return this.someAttr(callback); + + function nameTest(attr) { + return attr.local === localName; + } + + function stringValueTest(attr) { + return attr.local === localName && val == attr.value; + } + + function regexpValueTest(attr) { + return attr.local === localName && val.test(attr.value); + } + + function funcValueTest(attr) { + return attr.local === localName && val(attr.value); + } + +}; + +/** + * Get a specific attribute from an element + * (by name or name + value). + * + * @param {String} name attribute name + * @param {String} [val] attribute value (will be toString()'ed) + * @return {Object|Undefined} + */ + JSAPI.prototype.attr = function(name, val) { + + if (!this.hasAttr() || !arguments.length) return undefined; + + if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined; + + return this.attrs[name]; + +}; + +/** + * Get computed attribute value from an element + * + * @param {String} name attribute name + * @return {Object|Undefined} + */ + JSAPI.prototype.computedAttr = function(name, val) { + /* jshint eqnull: true */ + if (!arguments.length) return; + + for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode); + + if (val != null) { + return elem ? elem.hasAttr(name, val) : false; + } else if (elem && elem.hasAttr(name)) { + return elem.attrs[name].value; + } + +}; + +/** + * Remove a specific attribute. + * + * @param {String|Array} name attribute name + * @param {String} [val] attribute value + * @return {Boolean} + */ + JSAPI.prototype.removeAttr = function(name, val, recursive) { + + if (!arguments.length) return false; + + if (Array.isArray(name)) { + name.forEach(this.removeAttr, this); + return false; + } + + if (!this.hasAttr(name)) return false; + + if (!recursive && val && this.attrs[name].value !== val) return false; + + delete this.attrs[name]; + + if (!Object.keys(this.attrs).length) delete this.attrs; + + return true; + +}; + +/** + * Add attribute. + * + * @param {Object} [attr={}] attribute object + * @return {Object|Boolean} created attribute or false if no attr was passed in + */ + JSAPI.prototype.addAttr = function(attr) { + attr = attr || {}; + + if (attr.name === undefined || + attr.prefix === undefined || + attr.local === undefined + ) return false; + + this.attrs = this.attrs || {}; + this.attrs[attr.name] = attr; + + if(attr.name === 'class') { // newly added class attribute + this.class.hasClass(); + } + + if(attr.name === 'style') { // newly added style attribute + this.style.hasStyle(); + } + + return this.attrs[attr.name]; + +}; + +/** + * Iterates over all attributes. + * + * @param {Function} callback callback + * @param {Object} [context] callback context + * @return {Boolean} false if there are no any attributes + */ + JSAPI.prototype.eachAttr = function(callback, context) { + + if (!this.hasAttr()) return false; + + for (var name in this.attrs) { + callback.call(context, this.attrs[name]); + } + + return true; + +}; + +/** + * Tests whether some attribute passes the test. + * + * @param {Function} callback callback + * @param {Object} [context] callback context + * @return {Boolean} false if there are no any attributes + */ + JSAPI.prototype.someAttr = function(callback, context) { + + if (!this.hasAttr()) return false; + + for (var name in this.attrs) { + if (callback.call(context, this.attrs[name])) return true; + } + + return false; + +}; + +/** + * Evaluate a string of CSS selectors against the element and returns matched elements. + * + * @param {String} selectors CSS selector(s) string + * @return {Array} null if no elements matched + */ + JSAPI.prototype.querySelectorAll = function(selectors) { + + var matchedEls = cssSelect.selectAll(selectors, this, cssSelectOpts); + + return matchedEls.length > 0 ? matchedEls : null; + +}; + +/** + * Evaluate a string of CSS selectors against the element and returns only the first matched element. + * + * @param {String} selectors CSS selector(s) string + * @return {Array} null if no element matched + */ + JSAPI.prototype.querySelector = function(selectors) { + + return cssSelect.selectOne(selectors, this, cssSelectOpts); + +}; + +/** + * Test if a selector matches a given element. + * + * @param {String} selector CSS selector string + * @return {Boolean} true if element would be selected by selector string, false if it does not + */ + JSAPI.prototype.matches = function(selector) { + + return cssSelect.is(this, selector, cssSelectOpts); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/_collections.js b/vendor/svgclean/src/svgclean/plugins/_collections.js new file mode 100644 index 000000000..8179f3050 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/_collections.js @@ -0,0 +1,2558 @@ +'use strict'; + +// http://www.w3.org/TR/SVG11/intro.html#Definitions +exports.elemsGroups = { + animation: ['animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'], + descriptive: ['desc', 'metadata', 'title'], + shape: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'], + structural: ['defs', 'g', 'svg', 'symbol', 'use'], + paintServer: ['solidColor', 'linearGradient', 'radialGradient', 'meshGradient', 'pattern', 'hatch'], + nonRendering: ['linearGradient', 'radialGradient', 'pattern', 'clipPath', 'mask', 'marker', 'symbol', 'filter', 'solidColor'], + container: ['a', 'defs', 'g', 'marker', 'mask', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol', 'foreignObject'], + textContent: ['altGlyph', 'altGlyphDef', 'altGlyphItem', 'glyph', 'glyphRef', 'textPath', 'text', 'tref', 'tspan'], + textContentChild: ['altGlyph', 'textPath', 'tref', 'tspan'], + lightSource: ['feDiffuseLighting', 'feSpecularLighting', 'feDistantLight', 'fePointLight', 'feSpotLight'], + filterPrimitive: ['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feFlood', 'feGaussianBlur', 'feImage', 'feMerge', 'feMorphology', 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence'] +}; + +exports.pathElems = ['path', 'glyph', 'missing-glyph']; + +// http://www.w3.org/TR/SVG11/intro.html#Definitions +exports.attrsGroups = { + animationAddition: ['additive', 'accumulate'], + animationAttributeTarget: ['attributeType', 'attributeName'], + animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'], + animationTiming: ['begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'], + animationValue: ['calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'], + conditionalProcessing: ['requiredFeatures', 'requiredExtensions', 'systemLanguage'], + core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'], + graphicalEvent: ['onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'], + presentation: [ + 'alignment-baseline', + 'baseline-shift', + 'clip', + 'clip-path', + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'display', + 'dominant-baseline', + 'enable-background', + 'fill', + 'fill-opacity', + 'fill-rule', + 'filter', + 'flood-color', + 'flood-opacity', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'letter-spacing', + 'lighting-color', + 'marker-end', + 'marker-mid', + 'marker-start', + 'mask', + 'opacity', + 'overflow', + 'paint-order', + 'pointer-events', + 'shape-rendering', + 'stop-color', + 'stop-opacity', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'text-anchor', + 'text-decoration', + 'text-overflow', + 'text-rendering', + 'transform', + 'unicode-bidi', + 'vector-effect', + 'visibility', + 'word-spacing', + 'writing-mode' + ], + xlink: ['xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title'], + documentEvent: ['onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom'], + filterPrimitive: ['x', 'y', 'width', 'height', 'result'], + transferFunction: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'] +}; + +exports.attrsGroupsDefaults = { + core: {'xml:space': 'preserve'}, + filterPrimitive: {x: '0', y: '0', width: '100%', height: '100%'}, + presentation: { + clip: 'auto', + 'clip-path': 'none', + 'clip-rule': 'nonzero', + mask: 'none', + opacity: '1', + 'stop-color': '#000', + 'stop-opacity': '1', + 'fill-opacity': '1', + 'fill-rule': 'nonzero', + fill: '#000', + stroke: 'none', + 'stroke-width': '1', + 'stroke-linecap': 'butt', + 'stroke-linejoin': 'miter', + 'stroke-miterlimit': '4', + 'stroke-dasharray': 'none', + 'stroke-dashoffset': '0', + 'stroke-opacity': '1', + 'paint-order': 'normal', + 'vector-effect': 'none', + display: 'inline', + visibility: 'visible', + 'marker-start': 'none', + 'marker-mid': 'none', + 'marker-end': 'none', + 'color-interpolation': 'sRGB', + 'color-interpolation-filters': 'linearRGB', + 'color-rendering': 'auto', + 'shape-rendering': 'auto', + 'text-rendering': 'auto', + 'image-rendering': 'auto', + 'font-style': 'normal', + 'font-variant': 'normal', + 'font-weight': 'normal', + 'font-stretch': 'normal', + 'font-size': 'medium', + 'font-size-adjust': 'none', + kerning: 'auto', + 'letter-spacing': 'normal', + 'word-spacing': 'normal', + 'text-decoration': 'none', + 'text-anchor': 'start', + 'text-overflow': 'clip', + 'writing-mode': 'lr-tb', + 'glyph-orientation-vertical': 'auto', + 'glyph-orientation-horizontal': '0deg', + direction: 'ltr', + 'unicode-bidi': 'normal', + 'dominant-baseline': 'auto', + 'alignment-baseline': 'baseline', + 'baseline-shift': 'baseline' + }, + transferFunction: {slope: '1', intercept: '0', amplitude: '1', exponent: '1', offset: '0'} +}; + +// http://www.w3.org/TR/SVG11/eltindex.html +exports.elems = { + a: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'target' + ], + defaults: { + target: '_self' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + altGlyph: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'glyphRef', + 'format', + 'rotate' + ] + }, + altGlyphDef: { + attrsGroups: [ + 'core' + ], + content: [ + 'glyphRef' + ] + }, + altGlyphItem: { + attrsGroups: [ + 'core' + ], + content: [ + 'glyphRef', + 'altGlyphItem' + ] + }, + animate: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationAddition', + 'animationAttributeTarget', + 'animationEvent', + 'animationTiming', + 'animationValue', + 'presentation', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired' + ], + contentGroups: [ + 'descriptive' + ] + }, + animateColor: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition', + 'presentation' + ], + attrs: [ + 'externalResourcesRequired' + ], + contentGroups: [ + 'descriptive' + ] + }, + animateMotion: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationTiming', + 'animationValue', + 'animationAddition' + ], + attrs: [ + 'externalResourcesRequired', + 'path', + 'keyPoints', + 'rotate', + 'origin' + ], + defaults: { + 'rotate': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'mpath' + ] + }, + animateTransform: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition' + ], + attrs: [ + 'externalResourcesRequired', + 'type' + ], + contentGroups: [ + 'descriptive' + ] + }, + circle: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'r' + ], + defaults: { + cx: '0', + cy: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + clipPath: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'clipPathUnits' + ], + defaults: { + clipPathUnits: 'userSpaceOnUse' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape' + ], + content: [ + 'text', + 'use' + ] + }, + 'color-profile': { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'local', + 'name', + 'rendering-intent' + ], + defaults: { + name: 'sRGB', + 'rendering-intent': 'auto' + }, + contentGroups: [ + 'descriptive' + ] + }, + cursor: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'x', + 'y' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'descriptive' + ] + }, + defs: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + desc: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'class', + 'style' + ] + }, + ellipse: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'rx', + 'ry' + ], + defaults: { + cx: '0', + cy: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + feBlend: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + // TODO: in - 'If no value is provided and this is the first filter primitive, + // then this filter primitive will use SourceGraphic as its input' + 'in', + 'in2', + 'mode' + ], + defaults: { + mode: 'normal' + }, + content: [ + 'animate', + 'set' + ] + }, + feColorMatrix: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'type', + 'values' + ], + defaults: { + type: 'matrix' + }, + content: [ + 'animate', + 'set' + ] + }, + feComponentTransfer: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in' + ], + content: [ + 'feFuncA', + 'feFuncB', + 'feFuncG', + 'feFuncR' + ] + }, + feComposite: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'in2', + 'operator', + 'k1', + 'k2', + 'k3', + 'k4' + ], + defaults: { + operator: 'over', + k1: '0', + k2: '0', + k3: '0', + k4: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feConvolveMatrix: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'order', + 'kernelMatrix', + // TODO: divisor - 'The default value is the sum of all values in kernelMatrix, + // with the exception that if the sum is zero, then the divisor is set to 1' + 'divisor', + 'bias', + // TODO: targetX - 'By default, the convolution matrix is centered in X over each + // pixel of the input image (i.e., targetX = floor ( orderX / 2 ))' + 'targetX', + 'targetY', + 'edgeMode', + // TODO: kernelUnitLength - 'The first number is the <dx> value. The second number + // is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>' + 'kernelUnitLength', + 'preserveAlpha' + ], + defaults: { + order: '3', + bias: '0', + edgeMode: 'duplicate', + preserveAlpha: 'false' + }, + content: [ + 'animate', + 'set' + ] + }, + feDiffuseLighting: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'diffuseConstant', + 'kernelUnitLength' + ], + defaults: { + surfaceScale: '1', + diffuseConstant: '1' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + // TODO: 'exactly one light source element, in any order' + 'feDistantLight', + 'fePointLight', + 'feSpotLight' + ] + }, + feDisplacementMap: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'in2', + 'scale', + 'xChannelSelector', + 'yChannelSelector' + ], + defaults: { + scale: '0', + xChannelSelector: 'A', + yChannelSelector: 'A' + }, + content: [ + 'animate', + 'set' + ] + }, + feDistantLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'azimuth', + 'elevation' + ], + defaults: { + azimuth: '0', + elevation: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feFlood: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + feFuncA: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncB: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncG: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feFuncR: { + attrsGroups: [ + 'core', + 'transferFunction' + ], + content: [ + 'set', + 'animate' + ] + }, + feGaussianBlur: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'stdDeviation' + ], + defaults: { + stdDeviation: '0' + }, + content: [ + 'set', + 'animate' + ] + }, + feImage: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'href', + 'xlink:href' + ], + defaults: { + preserveAspectRatio: 'xMidYMid meet' + }, + content: [ + 'animate', + 'animateTransform', + 'set' + ] + }, + feMerge: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style' + ], + content: [ + 'feMergeNode' + ] + }, + feMergeNode: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'in' + ], + content: [ + 'animate', + 'set' + ] + }, + feMorphology: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'operator', + 'radius' + ], + defaults: { + operator: 'erode', + radius: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feOffset: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'dx', + 'dy' + ], + defaults: { + dx: '0', + dy: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + fePointLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'x', + 'y', + 'z' + ], + defaults: { + x: '0', + y: '0', + z: '0' + }, + content: [ + 'animate', + 'set' + ] + }, + feSpecularLighting: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'specularConstant', + 'specularExponent', + 'kernelUnitLength' + ], + defaults: { + surfaceScale: '1', + specularConstant: '1', + specularExponent: '1' + }, + contentGroups: [ + 'descriptive', + // TODO: exactly one 'light source element' + 'lightSource' + ] + }, + feSpotLight: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'x', + 'y', + 'z', + 'pointsAtX', + 'pointsAtY', + 'pointsAtZ', + 'specularExponent', + 'limitingConeAngle' + ], + defaults: { + x: '0', + y: '0', + z: '0', + pointsAtX: '0', + pointsAtY: '0', + pointsAtZ: '0', + specularExponent: '1' + }, + content: [ + 'animate', + 'set' + ] + }, + feTile: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'in' + ], + content: [ + 'animate', + 'set' + ] + }, + feTurbulence: { + attrsGroups: [ + 'core', + 'presentation', + 'filterPrimitive' + ], + attrs: [ + 'class', + 'style', + 'baseFrequency', + 'numOctaves', + 'seed', + 'stitchTiles', + 'type' + ], + defaults: { + baseFrequency: '0', + numOctaves: '1', + seed: '0', + stitchTiles: 'noStitch', + type: 'turbulence' + }, + content: [ + 'animate', + 'set' + ] + }, + filter: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'filterRes', + 'filterUnits', + 'primitiveUnits', + 'href', + 'xlink:href' + ], + defaults: { + primitiveUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%' + }, + contentGroups: [ + 'descriptive', + 'filterPrimitive' + ], + content: [ + 'animate', + 'set' + ] + }, + font: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'horiz-origin-x', + 'horiz-origin-y', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + defaults: { + 'horiz-origin-x': '0', + 'horiz-origin-y': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'font-face', + 'glyph', + 'hkern', + 'missing-glyph', + 'vkern' + ] + }, + 'font-face': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'font-family', + 'font-style', + 'font-variant', + 'font-weight', + 'font-stretch', + 'font-size', + 'unicode-range', + 'units-per-em', + 'panose-1', + 'stemv', + 'stemh', + 'slope', + 'cap-height', + 'x-height', + 'accent-height', + 'ascent', + 'descent', + 'widths', + 'bbox', + 'ideographic', + 'alphabetic', + 'mathematical', + 'hanging', + 'v-ideographic', + 'v-alphabetic', + 'v-mathematical', + 'v-hanging', + 'underline-position', + 'underline-thickness', + 'strikethrough-position', + 'strikethrough-thickness', + 'overline-position', + 'overline-thickness' + ], + defaults: { + 'font-style': 'all', + 'font-variant': 'normal', + 'font-weight': 'all', + 'font-stretch': 'normal', + 'unicode-range': 'U+0-10FFFF', + 'units-per-em': '1000', + 'panose-1': '0 0 0 0 0 0 0 0 0 0', + 'slope': '0' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + // TODO: "at most one 'font-face-src' element" + 'font-face-src' + ] + }, + // TODO: empty content + 'font-face-format': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'string' + ] + }, + 'font-face-name': { + attrsGroups: [ + 'core' + ], + attrs: [ + 'name' + ] + }, + 'font-face-src': { + attrsGroups: [ + 'core' + ], + content: [ + 'font-face-name', + 'font-face-uri' + ] + }, + 'font-face-uri': { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'href', + 'xlink:href' + ], + content: [ + 'font-face-format' + ] + }, + foreignObject: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height' + ], + defaults: { + x: 0, + y: 0 + } + }, + g: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + glyph: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y', + 'unicode', + 'glyph-name', + 'orientation', + 'arabic-form', + 'lang' + ], + defaults: { + 'arabic-form': 'initial' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ], + }, + glyphRef: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + hatch: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'pitch', + 'rotate', + 'hatchUnits', + 'hatchContentUnits', + 'transform' + ], + defaults: { + hatchUnits: 'objectBoundingBox', + hatchContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + pitch: '0', + rotate: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ], + content: [ + 'hatchPath' + ] + }, + hatchPath: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'd', + 'offset' + ], + defaults: { + offset: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + hkern: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'u1', + 'g1', + 'u2', + 'g2', + 'k' + ] + }, + image: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'xlink', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'href', + 'xlink:href' + ], + defaults: { + x: '0', + y: '0', + preserveAspectRatio: 'xMidYMid meet' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + line: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x1', + 'y1', + 'x2', + 'y2' + ], + defaults: { + x1: '0', + y1: '0', + x2: '0', + y2: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + linearGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x1', + 'y1', + 'x2', + 'y2', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'href', + 'xlink:href' + ], + defaults: { + x1: '0', + y1: '0', + x2: '100%', + y2: '0', + spreadMethod: 'pad' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateTransform', + 'set', + 'stop' + ] + }, + marker: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'refX', + 'refY', + 'markerUnits', + 'markerWidth', + 'markerHeight', + 'orient' + ], + defaults: { + markerUnits: 'strokeWidth', + refX: '0', + refY: '0', + markerWidth: '3', + markerHeight: '3' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + mask: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'maskUnits', + 'maskContentUnits' + ], + defaults: { + maskUnits: 'objectBoundingBox', + maskContentUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + metadata: { + attrsGroups: [ + 'core' + ] + }, + 'missing-glyph': { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + mpath: { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'href', + 'xlink:href' + ], + contentGroups: [ + 'descriptive' + ] + }, + path: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'd', + 'pathLength' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + pattern: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'x', + 'y', + 'width', + 'height', + 'patternUnits', + 'patternContentUnits', + 'patternTransform', + 'href', + 'xlink:href' + ], + defaults: { + patternUnits: 'objectBoundingBox', + patternContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + width: '0', + height: '0', + preserveAspectRatio: 'xMidYMid meet' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'paintServer', + 'shape', + 'structural' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + polygon: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + polyline: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points' + ], + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + radialGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'cx', + 'cy', + 'r', + 'fx', + 'fy', + 'fr', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'href', + 'xlink:href' + ], + defaults: { + gradientUnits: 'objectBoundingBox', + cx: '50%', + cy: '50%', + r: '50%' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateTransform', + 'set', + 'stop' + ] + }, + meshGradient: { + attrsGroups: [ + 'core', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'gradientUnits', + 'transform' + ], + contentGroups: [ + 'descriptive', + 'paintServer', + 'animation', + ], + content: [ + 'meshRow' + ] + }, + meshRow: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'meshPatch' + ] + }, + meshPatch: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'stop' + ] + }, + rect: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'rx', + 'ry' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + script: { + attrsGroups: [ + 'core', + 'xlink' + ], + attrs: [ + 'externalResourcesRequired', + 'type', + 'href', + 'xlink:href' + ] + }, + set: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animation', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + ], + attrs: [ + 'externalResourcesRequired', + 'to' + ], + contentGroups: [ + 'descriptive' + ] + }, + solidColor: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style' + ], + contentGroups: [ + 'paintServer' + ] + }, + stop: { + attrsGroups: [ + 'core', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'offset', + 'path' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + style: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'type', + 'media', + 'title' + ], + defaults: { + type: 'text/css' + } + }, + svg: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'documentEvent', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'width', + 'height', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'version', + 'baseProfile', + 'contentScriptType', + 'contentStyleType' + ], + defaults: { + x: '0', + y: '0', + width: '100%', + height: '100%', + preserveAspectRatio: 'xMidYMid meet', + zoomAndPan: 'magnify', + version: '1.1', + baseProfile: 'none', + contentScriptType: 'application/ecmascript', + contentStyleType: 'text/css' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + switch: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform' + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape' + ], + content: [ + 'a', + 'foreignObject', + 'g', + 'image', + 'svg', + 'switch', + 'text', + 'use' + ] + }, + symbol: { + attrsGroups: [ + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'viewBox', + 'refX', + 'refY' + ], + defaults: { + refX: 0, + refY: 0 + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer' + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view' + ] + }, + text: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'lengthAdjust', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength' + ], + defaults: { + x: '0', + y: '0', + lengthAdjust: 'spacing' + }, + contentGroups: [ + 'animation', + 'descriptive', + 'textContentChild' + ], + content: [ + 'a' + ] + }, + textPath: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'href', + 'xlink:href', + 'startOffset', + 'method', + 'spacing', + 'd' + ], + defaults: { + startOffset: '0', + method: 'align', + spacing: 'exact' + }, + contentGroups: [ + 'descriptive' + ], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan' + ] + }, + title: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'class', + 'style' + ] + }, + tref: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'href', + 'xlink:href' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'animate', + 'animateColor', + 'set' + ] + }, + tspan: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength', + 'lengthAdjust' + ], + contentGroups: [ + 'descriptive' + ], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan' + ] + }, + use: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation', + 'xlink' + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'href', + 'xlink:href' + ], + defaults: { + x: '0', + y: '0' + }, + contentGroups: [ + 'animation', + 'descriptive' + ] + }, + view: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'viewTarget' + ], + contentGroups: [ + 'descriptive' + ] + }, + vkern: { + attrsGroups: [ + 'core' + ], + attrs: [ + 'u1', + 'g1', + 'u2', + 'g2', + 'k' + ] + } +}; + +// http://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes +exports.editorNamespaces = [ + 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd', + 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd', + 'http://www.inkscape.org/namespaces/inkscape', + 'http://www.bohemiancoding.com/sketch/ns', + 'http://ns.adobe.com/AdobeIllustrator/10.0/', + 'http://ns.adobe.com/Graphs/1.0/', + 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/', + 'http://ns.adobe.com/Variables/1.0/', + 'http://ns.adobe.com/SaveForWeb/1.0/', + 'http://ns.adobe.com/Extensibility/1.0/', + 'http://ns.adobe.com/Flows/1.0/', + 'http://ns.adobe.com/ImageReplacement/1.0/', + 'http://ns.adobe.com/GenericCustomNamespace/1.0/', + 'http://ns.adobe.com/XPath/1.0/', + 'http://schemas.microsoft.com/visio/2003/SVGExtensions/', + 'http://taptrix.com/vectorillustrator/svg_extensions', + 'http://www.figma.com/figma/ns', + 'http://purl.org/dc/elements/1.1/', + 'http://creativecommons.org/ns#', + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + 'http://www.serif.com/', + 'http://www.vector.evaxdesign.sk' +]; + +// http://www.w3.org/TR/SVG11/linking.html#processingIRI +exports.referencesProps = [ + 'clip-path', + 'color-profile', + 'fill', + 'filter', + 'marker-start', + 'marker-mid', + 'marker-end', + 'mask', + 'stroke', + 'style' +]; + +// http://www.w3.org/TR/SVG11/propidx.html +exports.inheritableAttrs = [ + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'dominant-baseline', + 'fill', + 'fill-opacity', + 'fill-rule', + 'font', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'letter-spacing', + 'marker', + 'marker-end', + 'marker-mid', + 'marker-start', + 'paint-order', + 'pointer-events', + 'shape-rendering', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'text-anchor', + 'text-rendering', + 'transform', + 'visibility', + 'word-spacing', + 'writing-mode' +]; + +exports.presentationNonInheritableGroupAttrs = [ + 'display', + 'clip-path', + 'filter', + 'mask', + 'opacity', + 'text-decoration', + 'transform', + 'unicode-bidi', + 'visibility' +]; + +// http://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords +exports.colorsNames = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#0ff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000', + 'blanchedalmond': '#ffebcd', + 'blue': '#00f', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#0ff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgreen': '#006400', + 'darkgrey': '#a9a9a9', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkslategrey': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#f0f', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'grey': '#808080', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgray': '#d3d3d3', + 'lightgreen': '#90ee90', + 'lightgrey': '#d3d3d3', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#789', + 'lightslategrey': '#789', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#0f0', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#f0f', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370db', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#db7093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'rebeccapurple': '#639', + 'red': '#f00', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#fff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ff0', + 'yellowgreen': '#9acd32' +}; + +exports.colorsShortNames = { + '#f0ffff': 'azure', + '#f5f5dc': 'beige', + '#ffe4c4': 'bisque', + '#a52a2a': 'brown', + '#ff7f50': 'coral', + '#ffd700': 'gold', + '#808080': 'gray', + '#008000': 'green', + '#4b0082': 'indigo', + '#fffff0': 'ivory', + '#f0e68c': 'khaki', + '#faf0e6': 'linen', + '#800000': 'maroon', + '#000080': 'navy', + '#808000': 'olive', + '#ffa500': 'orange', + '#da70d6': 'orchid', + '#cd853f': 'peru', + '#ffc0cb': 'pink', + '#dda0dd': 'plum', + '#800080': 'purple', + '#f00': 'red', + '#ff0000': 'red', + '#fa8072': 'salmon', + '#a0522d': 'sienna', + '#c0c0c0': 'silver', + '#fffafa': 'snow', + '#d2b48c': 'tan', + '#008080': 'teal', + '#ff6347': 'tomato', + '#ee82ee': 'violet', + '#f5deb3': 'wheat' +}; + +// http://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor +exports.colorsProps = [ + 'color', 'fill', 'stroke', 'stop-color', 'flood-color', 'lighting-color' +]; diff --git a/vendor/svgclean/src/svgclean/plugins/_path.js b/vendor/svgclean/src/svgclean/plugins/_path.js new file mode 100644 index 000000000..89244d83a --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/_path.js @@ -0,0 +1,988 @@ +/* global a2c */ +'use strict'; + +var rNumber = String.raw`[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?\s*`, + rCommaWsp = String.raw`(?:\s,?\s*|,\s*)`, + rNumberCommaWsp = `(${rNumber})` + rCommaWsp, + rFlagCommaWsp = `([01])${rCommaWsp}?`, + rCoordinatePair = String.raw`(${rNumber})${rCommaWsp}?(${rNumber})`, + rArcSeq = (rNumberCommaWsp + '?').repeat(2) + rNumberCommaWsp + rFlagCommaWsp.repeat(2) + rCoordinatePair; + +var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/, + regCoordinateSequence = new RegExp(rNumber, 'g'), + regArcArgumentSequence = new RegExp(rArcSeq, 'g'), + regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/, + transform2js = require('./_transforms').transform2js, + transformsMultiply = require('./_transforms').transformsMultiply, + transformArc = require('./_transforms').transformArc, + collections = require('./_collections.js'), + referencesProps = collections.referencesProps, + defaultStrokeWidth = collections.attrsGroupsDefaults.presentation['stroke-width'], + cleanupOutData = require('../tools').cleanupOutData, + removeLeadingZero = require('../tools').removeLeadingZero, + prevCtrlPoint; + +/** + * Convert path string to JS representation. + * + * @param {String} pathString input string + * @param {Object} params plugin params + * @return {Array} output array + */ +exports.path2js = function(path) { + if (path.pathJS) return path.pathJS; + + var paramsLength = { // Number of parameters of every path command + H: 1, V: 1, M: 2, L: 2, T: 2, Q: 4, S: 4, C: 6, A: 7, + h: 1, v: 1, m: 2, l: 2, t: 2, q: 4, s: 4, c: 6, a: 7 + }, + pathData = [], // JS representation of the path data + instruction, // current instruction context + startMoveto = false; + + // splitting path string into array like ['M', '10 50', 'L', '20 30'] + path.attr('d').value.split(regPathInstructions).forEach(function(data) { + if (!data) return; + if (!startMoveto) { + if (data == 'M' || data == 'm') { + startMoveto = true; + } else return; + } + + // instruction item + if (regPathInstructions.test(data)) { + instruction = data; + + // z - instruction w/o data + if (instruction == 'Z' || instruction == 'z') { + pathData.push({ + instruction: 'z' + }); + } + // data item + } else { + /* jshint boss: true */ + if (instruction == 'A' || instruction == 'a') { + var newData = []; + for (var args; (args = regArcArgumentSequence.exec(data));) { + for (var i = 1; i < args.length; i++) { + newData.push(args[i]); + } + } + data = newData; + } else { + data = data.match(regCoordinateSequence); + } + if (!data) return; + + data = data.map(Number); + // Subsequent moveto pairs of coordinates are threated as implicit lineto commands + // http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands + if (instruction == 'M' || instruction == 'm') { + pathData.push({ + instruction: pathData.length == 0 ? 'M' : instruction, + data: data.splice(0, 2) + }); + instruction = instruction == 'M' ? 'L' : 'l'; + } + + for (var pair = paramsLength[instruction]; data.length;) { + pathData.push({ + instruction: instruction, + data: data.splice(0, pair) + }); + } + } + }); + + // First moveto is actually absolute. Subsequent coordinates were separated above. + if (pathData.length && pathData[0].instruction == 'm') { + pathData[0].instruction = 'M'; + } + path.pathJS = pathData; + + return pathData; +}; + +/** + * Convert relative Path data to absolute. + * + * @param {Array} data input data + * @return {Array} output data + */ +var relative2absolute = exports.relative2absolute = function(data) { + var currentPoint = [0, 0], + subpathPoint = [0, 0], + i; + + return data.map(function(item) { + + var instruction = item.instruction, + itemData = item.data && item.data.slice(); + + if (instruction == 'M') { + + set(currentPoint, itemData); + set(subpathPoint, itemData); + + } else if ('mlcsqt'.indexOf(instruction) > -1) { + + for (i = 0; i < itemData.length; i++) { + itemData[i] += currentPoint[i % 2]; + } + set(currentPoint, itemData); + + if (instruction == 'm') { + set(subpathPoint, itemData); + } + + } else if (instruction == 'a') { + + itemData[5] += currentPoint[0]; + itemData[6] += currentPoint[1]; + set(currentPoint, itemData); + + } else if (instruction == 'h') { + + itemData[0] += currentPoint[0]; + currentPoint[0] = itemData[0]; + + } else if (instruction == 'v') { + + itemData[0] += currentPoint[1]; + currentPoint[1] = itemData[0]; + + } else if ('MZLCSQTA'.indexOf(instruction) > -1) { + + set(currentPoint, itemData); + + } else if (instruction == 'H') { + + currentPoint[0] = itemData[0]; + + } else if (instruction == 'V') { + + currentPoint[1] = itemData[0]; + + } else if (instruction == 'z') { + + set(currentPoint, subpathPoint); + + } + + return instruction == 'z' ? + { instruction: 'z' } : + { + instruction: instruction.toUpperCase(), + data: itemData + }; + + }); +}; + +/** + * Apply transformation(s) to the Path data. + * + * @param {Object} elem current element + * @param {Array} path input path data + * @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width) + * @return {Array} output path data + */ +exports.applyTransforms = function(elem, path, params) { + // if there are no 'stroke' attr and references to other objects such as + // gradiends or clip-path which are also subjects to transform. + if (!elem.hasAttr('transform') || !elem.attr('transform').value || + elem.someAttr(function(attr) { + return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url('); + })) + return path; + + var matrix = transformsMultiply(transform2js(elem.attr('transform').value)), + stroke = elem.computedAttr('stroke'), + id = elem.computedAttr('id'), + transformPrecision = params.transformPrecision, + newPoint, scale; + + if (stroke && stroke != 'none') { + if (!params.applyTransformsStroked || + (matrix.data[0] != matrix.data[3] || matrix.data[1] != -matrix.data[2]) && + (matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2])) + return path; + + // "stroke-width" should be inside the part with ID, otherwise it can be overrided in <use> + if (id) { + var idElem = elem, + hasStrokeWidth = false; + + do { + if (idElem.hasAttr('stroke-width')) hasStrokeWidth = true; + } while (!idElem.hasAttr('id', id) && !hasStrokeWidth && (idElem = idElem.parentNode)); + + if (!hasStrokeWidth) return path; + } + + scale = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(transformPrecision); + + if (scale !== 1) { + var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth; + + if (!elem.hasAttr('vector-effect') || elem.attr('vector-effect').value !== 'non-scaling-stroke') { + if (elem.hasAttr('stroke-width')) { + elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim() + .replace(regNumericValues, function(num) { + return removeLeadingZero(num * scale); + }); + } else { + elem.addAttr({ + name: 'stroke-width', + prefix: '', + local: 'stroke-width', + value: strokeWidth.replace(regNumericValues, function(num) { + return removeLeadingZero(num * scale); + }) + }); + } + } + } + } else if (id) { // Stroke and stroke-width can be redefined with <use> + return path; + } + + path.forEach(function(pathItem) { + + if (pathItem.data) { + + // h -> l + if (pathItem.instruction === 'h') { + + pathItem.instruction = 'l'; + pathItem.data[1] = 0; + + // v -> l + } else if (pathItem.instruction === 'v') { + + pathItem.instruction = 'l'; + pathItem.data[1] = pathItem.data[0]; + pathItem.data[0] = 0; + + } + + // if there is a translate() transform + if (pathItem.instruction === 'M' && + (matrix.data[4] !== 0 || + matrix.data[5] !== 0) + ) { + + // then apply it only to the first absoluted M + newPoint = transformPoint(matrix.data, pathItem.data[0], pathItem.data[1]); + set(pathItem.data, newPoint); + set(pathItem.coords, newPoint); + + // clear translate() data from transform matrix + matrix.data[4] = 0; + matrix.data[5] = 0; + + } else { + + if (pathItem.instruction == 'a') { + + transformArc(pathItem.data, matrix.data); + + // reduce number of digits in rotation angle + if (Math.abs(pathItem.data[2]) > 80) { + var a = pathItem.data[0], + rotation = pathItem.data[2]; + pathItem.data[0] = pathItem.data[1]; + pathItem.data[1] = a; + pathItem.data[2] = rotation + (rotation > 0 ? -90 : 90); + } + + newPoint = transformPoint(matrix.data, pathItem.data[5], pathItem.data[6]); + pathItem.data[5] = newPoint[0]; + pathItem.data[6] = newPoint[1]; + + } else { + + for (var i = 0; i < pathItem.data.length; i += 2) { + newPoint = transformPoint(matrix.data, pathItem.data[i], pathItem.data[i + 1]); + pathItem.data[i] = newPoint[0]; + pathItem.data[i + 1] = newPoint[1]; + } + } + + pathItem.coords[0] = pathItem.base[0] + pathItem.data[pathItem.data.length - 2]; + pathItem.coords[1] = pathItem.base[1] + pathItem.data[pathItem.data.length - 1]; + + } + + } + + }); + + // remove transform attr + elem.removeAttr('transform'); + + return path; +}; + +/** + * Apply transform 3x3 matrix to x-y point. + * + * @param {Array} matrix transform 3x3 matrix + * @param {Array} point x-y point + * @return {Array} point with new coordinates + */ +function transformPoint(matrix, x, y) { + + return [ + matrix[0] * x + matrix[2] * y + matrix[4], + matrix[1] * x + matrix[3] * y + matrix[5] + ]; + +} + +/** + * Compute Cubic Bézie bounding box. + * + * @see http://processingjs.nihongoresources.com/bezierinfo/ + * + * @param {Float} xa + * @param {Float} ya + * @param {Float} xb + * @param {Float} yb + * @param {Float} xc + * @param {Float} yc + * @param {Float} xd + * @param {Float} yd + * + * @return {Object} + */ +exports.computeCubicBoundingBox = function(xa, ya, xb, yb, xc, yc, xd, yd) { + + var minx = Number.POSITIVE_INFINITY, + miny = Number.POSITIVE_INFINITY, + maxx = Number.NEGATIVE_INFINITY, + maxy = Number.NEGATIVE_INFINITY, + ts, + t, + x, + y, + i; + + // X + if (xa < minx) { minx = xa; } + if (xa > maxx) { maxx = xa; } + if (xd < minx) { minx= xd; } + if (xd > maxx) { maxx = xd; } + + ts = computeCubicFirstDerivativeRoots(xa, xb, xc, xd); + + for (i = 0; i < ts.length; i++) { + + t = ts[i]; + + if (t >= 0 && t <= 1) { + x = computeCubicBaseValue(t, xa, xb, xc, xd); + // y = computeCubicBaseValue(t, ya, yb, yc, yd); + + if (x < minx) { minx = x; } + if (x > maxx) { maxx = x; } + } + + } + + // Y + if (ya < miny) { miny = ya; } + if (ya > maxy) { maxy = ya; } + if (yd < miny) { miny = yd; } + if (yd > maxy) { maxy = yd; } + + ts = computeCubicFirstDerivativeRoots(ya, yb, yc, yd); + + for (i = 0; i < ts.length; i++) { + + t = ts[i]; + + if (t >= 0 && t <= 1) { + // x = computeCubicBaseValue(t, xa, xb, xc, xd); + y = computeCubicBaseValue(t, ya, yb, yc, yd); + + if (y < miny) { miny = y; } + if (y > maxy) { maxy = y; } + } + + } + + return { + minx: minx, + miny: miny, + maxx: maxx, + maxy: maxy + }; + +}; + +// compute the value for the cubic bezier function at time=t +function computeCubicBaseValue(t, a, b, c, d) { + + var mt = 1 - t; + + return mt * mt * mt * a + 3 * mt * mt * t * b + 3 * mt * t * t * c + t * t * t * d; + +} + +// compute the value for the first derivative of the cubic bezier function at time=t +function computeCubicFirstDerivativeRoots(a, b, c, d) { + + var result = [-1, -1], + tl = -a + 2 * b - c, + tr = -Math.sqrt(-a * (c - d) + b * b - b * (c + d) + c * c), + dn = -a + 3 * b - 3 * c + d; + + if (dn !== 0) { + result[0] = (tl + tr) / dn; + result[1] = (tl - tr) / dn; + } + + return result; + +} + +/** + * Compute Quadratic Bézier bounding box. + * + * @see http://processingjs.nihongoresources.com/bezierinfo/ + * + * @param {Float} xa + * @param {Float} ya + * @param {Float} xb + * @param {Float} yb + * @param {Float} xc + * @param {Float} yc + * + * @return {Object} + */ +exports.computeQuadraticBoundingBox = function(xa, ya, xb, yb, xc, yc) { + + var minx = Number.POSITIVE_INFINITY, + miny = Number.POSITIVE_INFINITY, + maxx = Number.NEGATIVE_INFINITY, + maxy = Number.NEGATIVE_INFINITY, + t, + x, + y; + + // X + if (xa < minx) { minx = xa; } + if (xa > maxx) { maxx = xa; } + if (xc < minx) { minx = xc; } + if (xc > maxx) { maxx = xc; } + + t = computeQuadraticFirstDerivativeRoot(xa, xb, xc); + + if (t >= 0 && t <= 1) { + x = computeQuadraticBaseValue(t, xa, xb, xc); + // y = computeQuadraticBaseValue(t, ya, yb, yc); + + if (x < minx) { minx = x; } + if (x > maxx) { maxx = x; } + } + + // Y + if (ya < miny) { miny = ya; } + if (ya > maxy) { maxy = ya; } + if (yc < miny) { miny = yc; } + if (yc > maxy) { maxy = yc; } + + t = computeQuadraticFirstDerivativeRoot(ya, yb, yc); + + if (t >= 0 && t <=1 ) { + // x = computeQuadraticBaseValue(t, xa, xb, xc); + y = computeQuadraticBaseValue(t, ya, yb, yc); + + if (y < miny) { miny = y; } + if (y > maxy) { maxy = y ; } + + } + + return { + minx: minx, + miny: miny, + maxx: maxx, + maxy: maxy + }; + +}; + +// compute the value for the quadratic bezier function at time=t +function computeQuadraticBaseValue(t, a, b, c) { + + var mt = 1 - t; + + return mt * mt * a + 2 * mt * t * b + t * t * c; + +} + +// compute the value for the first derivative of the quadratic bezier function at time=t +function computeQuadraticFirstDerivativeRoot(a, b, c) { + + var t = -1, + denominator = a - 2 * b + c; + + if (denominator !== 0) { + t = (a - b) / denominator; + } + + return t; + +} + +/** + * Convert path array to string. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {String} output path string + */ +exports.js2path = function(path, data, params) { + + path.pathJS = data; + + if (params.collapseRepeated) { + data = collapseRepeated(data); + } + + path.attr('d').value = data.reduce(function(pathString, item) { + var strData = ''; + if (item.data) { + strData = cleanupOutData(item.data, params, item.instruction); + } + return pathString += item.instruction + strData; + }, ''); + +}; + +/** + * Collapse repeated instructions data + * + * @param {Array} path input path data + * @return {Array} output path data + */ +function collapseRepeated(data) { + + var prev, + prevIndex; + + // copy an array and modifieds item to keep original data untouched + data = data.reduce(function(newPath, item) { + if ( + prev && item.data && + item.instruction == prev.instruction + ) { + // concat previous data with current + if (item.instruction != 'M') { + prev = newPath[prevIndex] = { + instruction: prev.instruction, + data: prev.data.concat(item.data), + coords: item.coords, + base: prev.base + }; + } else { + prev.data = item.data; + prev.coords = item.coords; + } + } else { + newPath.push(item); + prev = item; + prevIndex = newPath.length - 1; + } + + return newPath; + }, []); + + return data; + +} + +function set(dest, source) { + dest[0] = source[source.length - 2]; + dest[1] = source[source.length - 1]; + return dest; +} + +/** + * Checks if two paths have an intersection by checking convex hulls + * collision using Gilbert-Johnson-Keerthi distance algorithm + * http://entropyinteractive.com/2011/04/gjk-algorithm/ + * + * @param {Array} path1 JS path representation + * @param {Array} path2 JS path representation + * @return {Boolean} + */ +exports.intersects = function(path1, path2) { + if (path1.length < 3 || path2.length < 3) return false; // nothing to fill + + // Collect points of every subpath. + var points1 = relative2absolute(path1).reduce(gatherPoints, []), + points2 = relative2absolute(path2).reduce(gatherPoints, []); + + // Axis-aligned bounding box check. + if (points1.maxX <= points2.minX || points2.maxX <= points1.minX || + points1.maxY <= points2.minY || points2.maxY <= points1.minY || + points1.every(function (set1) { + return points2.every(function (set2) { + return set1[set1.maxX][0] <= set2[set2.minX][0] || + set2[set2.maxX][0] <= set1[set1.minX][0] || + set1[set1.maxY][1] <= set2[set2.minY][1] || + set2[set2.maxY][1] <= set1[set1.minY][1]; + }); + }) + ) return false; + + // Get a convex hull from points of each subpath. Has the most complexity O(n·log n). + var hullNest1 = points1.map(convexHull), + hullNest2 = points2.map(convexHull); + + // Check intersection of every subpath of the first path with every subpath of the second. + return hullNest1.some(function(hull1) { + if (hull1.length < 3) return false; + + return hullNest2.some(function(hull2) { + if (hull2.length < 3) return false; + + var simplex = [getSupport(hull1, hull2, [1, 0])], // create the initial simplex + direction = minus(simplex[0]); // set the direction to point towards the origin + + var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough + while (true) { + if (iterations-- == 0) { + console.error('Error: infinite loop while processing mergePaths plugin.'); + return true; // true is the safe value that means “do nothing with paths” + } + // add a new point + simplex.push(getSupport(hull1, hull2, direction)); + // see if the new point was on the correct side of the origin + if (dot(direction, simplex[simplex.length - 1]) <= 0) return false; + // process the simplex + if (processSimplex(simplex, direction)) return true; + } + }); + }); + + function getSupport(a, b, direction) { + return sub(supportPoint(a, direction), supportPoint(b, minus(direction))); + } + + // Computes farthest polygon point in particular direction. + // Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in. + // Since we're working on convex hull, the dot product is increasing until we find the farthest point. + function supportPoint(polygon, direction) { + var index = direction[1] >= 0 ? + direction[0] < 0 ? polygon.maxY : polygon.maxX : + direction[0] < 0 ? polygon.minX : polygon.minY, + max = -Infinity, + value; + while ((value = dot(polygon[index], direction)) > max) { + max = value; + index = ++index % polygon.length; + } + return polygon[(index || polygon.length) - 1]; + } +}; + +function processSimplex(simplex, direction) { + /* jshint -W004 */ + + // we only need to handle to 1-simplex and 2-simplex + if (simplex.length == 2) { // 1-simplex + var a = simplex[1], + b = simplex[0], + AO = minus(simplex[1]), + AB = sub(b, a); + // AO is in the same direction as AB + if (dot(AO, AB) > 0) { + // get the vector perpendicular to AB facing O + set(direction, orth(AB, a)); + } else { + set(direction, AO); + // only A remains in the simplex + simplex.shift(); + } + } else { // 2-simplex + var a = simplex[2], // [a, b, c] = simplex + b = simplex[1], + c = simplex[0], + AB = sub(b, a), + AC = sub(c, a), + AO = minus(a), + ACB = orth(AB, AC), // the vector perpendicular to AB facing away from C + ABC = orth(AC, AB); // the vector perpendicular to AC facing away from B + + if (dot(ACB, AO) > 0) { + if (dot(AB, AO) > 0) { // region 4 + set(direction, ACB); + simplex.shift(); // simplex = [b, a] + } else { // region 5 + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } else if (dot(ABC, AO) > 0) { + if (dot(AC, AO) > 0) { // region 6 + set(direction, ABC); + simplex.splice(1, 1); // simplex = [c, a] + } else { // region 5 (again) + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } else // region 7 + return true; + } + return false; +} + +function minus(v) { + return [-v[0], -v[1]]; +} + +function sub(v1, v2) { + return [v1[0] - v2[0], v1[1] - v2[1]]; +} + +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +function orth(v, from) { + var o = [-v[1], v[0]]; + return dot(o, minus(from)) < 0 ? minus(o) : o; +} + +function gatherPoints(points, item, index, path) { + + var subPath = points.length && points[points.length - 1], + prev = index && path[index - 1], + basePoint = subPath.length && subPath[subPath.length - 1], + data = item.data, + ctrlPoint = basePoint; + + switch (item.instruction) { + case 'M': + points.push(subPath = []); + break; + case 'H': + addPoint(subPath, [data[0], basePoint[1]]); + break; + case 'V': + addPoint(subPath, [basePoint[0], data[0]]); + break; + case 'Q': + addPoint(subPath, data.slice(0, 2)); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; // Save control point for shorthand + break; + case 'T': + if (prev.instruction == 'Q' || prev.instruction == 'T') { + ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]]; + addPoint(subPath, ctrlPoint); + prevCtrlPoint = [data[0] - ctrlPoint[0], data[1] - ctrlPoint[1]]; + } + break; + case 'C': + // Approximate quibic Bezier curve with middle points between control points + addPoint(subPath, [.5 * (basePoint[0] + data[0]), .5 * (basePoint[1] + data[1])]); + addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]); + addPoint(subPath, [.5 * (data[2] + data[4]), .5 * (data[3] + data[5])]); + prevCtrlPoint = [data[4] - data[2], data[5] - data[3]]; // Save control point for shorthand + break; + case 'S': + if (prev.instruction == 'C' || prev.instruction == 'S') { + addPoint(subPath, [basePoint[0] + .5 * prevCtrlPoint[0], basePoint[1] + .5 * prevCtrlPoint[1]]); + ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]]; + } + addPoint(subPath, [.5 * (ctrlPoint[0] + data[0]), .5 * (ctrlPoint[1]+ data[1])]); + addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; + break; + case 'A': + // Convert the arc to bezier curves and use the same approximation + var curves = a2c.apply(0, basePoint.concat(data)); + for (var cData; (cData = curves.splice(0,6).map(toAbsolute)).length;) { + addPoint(subPath, [.5 * (basePoint[0] + cData[0]), .5 * (basePoint[1] + cData[1])]); + addPoint(subPath, [.5 * (cData[0] + cData[2]), .5 * (cData[1] + cData[3])]); + addPoint(subPath, [.5 * (cData[2] + cData[4]), .5 * (cData[3] + cData[5])]); + if (curves.length) addPoint(subPath, basePoint = cData.slice(-2)); + } + break; + } + // Save final command coordinates + if (data && data.length >= 2) addPoint(subPath, data.slice(-2)); + return points; + + function toAbsolute(n, i) { return n + basePoint[i % 2] } + + // Writes data about the extreme points on each axle + function addPoint(path, point) { + if (!path.length || point[1] > path[path.maxY][1]) { + path.maxY = path.length; + points.maxY = points.length ? Math.max(point[1], points.maxY) : point[1]; + } + if (!path.length || point[0] > path[path.maxX][0]) { + path.maxX = path.length; + points.maxX = points.length ? Math.max(point[0], points.maxX) : point[0]; + } + if (!path.length || point[1] < path[path.minY][1]) { + path.minY = path.length; + points.minY = points.length ? Math.min(point[1], points.minY) : point[1]; + } + if (!path.length || point[0] < path[path.minX][0]) { + path.minX = path.length; + points.minX = points.length ? Math.min(point[0], points.minX) : point[0]; + } + path.push(point); + } +} + +/** + * Forms a convex hull from set of points of every subpath using monotone chain convex hull algorithm. + * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain + * + * @param points An array of [X, Y] coordinates + */ +function convexHull(points) { + /* jshint -W004 */ + + points.sort(function(a, b) { + return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; + }); + + var lower = [], + minY = 0, + bottom = 0; + for (var i = 0; i < points.length; i++) { + while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) { + lower.pop(); + } + if (points[i][1] < points[minY][1]) { + minY = i; + bottom = lower.length; + } + lower.push(points[i]); + } + + var upper = [], + maxY = points.length - 1, + top = 0; + for (var i = points.length; i--;) { + while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) { + upper.pop(); + } + if (points[i][1] > points[maxY][1]) { + maxY = i; + top = upper.length; + } + upper.push(points[i]); + } + + // last points are equal to starting points of the other part + upper.pop(); + lower.pop(); + + var hull = lower.concat(upper); + + hull.minX = 0; // by sorting + hull.maxX = lower.length; + hull.minY = bottom; + hull.maxY = (lower.length + top) % hull.length; + + return hull; +} + +function cross(o, a, b) { + return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); +} + +/* Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/ + * Thanks to Dmitry Baranovskiy for his great work! + */ + +// jshint ignore: start +function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this Math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = Math.PI * 120 / 180, + rad = Math.PI / 180 * (+angle || 0), + res = [], + rotateX = function(x, y, rad) { return x * Math.cos(rad) - y * Math.sin(rad) }, + rotateY = function(x, y, rad) { return x * Math.sin(rad) + y * Math.cos(rad) }; + if (!recursive) { + x1 = rotateX(x1, y1, -rad); + y1 = rotateY(x1, y1, -rad); + x2 = rotateX(x2, y2, -rad); + y2 = rotateY(x2, y2, -rad); + var x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = Math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = Math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = Math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? Math.PI - f1 : f1; + f2 = x2 < cx ? Math.PI - f2 : f2; + f1 < 0 && (f1 = Math.PI * 2 + f1); + f2 < 0 && (f2 = Math.PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - Math.PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - Math.PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (Math.abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * Math.cos(f2); + y2 = cy + ry * Math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = Math.cos(f1), + s1 = Math.sin(f1), + c2 = Math.cos(f2), + s2 = Math.sin(f2), + t = Math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m = [ + - hx * s1, hy * c1, + x2 + hx * s2 - x1, y2 - hy * c2 - y1, + x2 - x1, y2 - y1 + ]; + if (recursive) { + return m.concat(res); + } else { + res = m.concat(res); + var newres = []; + for (var i = 0, n = res.length; i < n; i++) { + newres[i] = i % 2 ? rotateY(res[i - 1], res[i], rad) : rotateX(res[i], res[i + 1], rad); + } + return newres; + } +} +// jshint ignore: end diff --git a/vendor/svgclean/src/svgclean/plugins/_transforms.js b/vendor/svgclean/src/svgclean/plugins/_transforms.js new file mode 100644 index 000000000..a5160839a --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/_transforms.js @@ -0,0 +1,310 @@ +'use strict'; + +var regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/, + regTransformSplit = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/, + regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + +/** + * Convert transform string to JS representation. + * + * @param {String} transformString input string + * @param {Object} params plugin params + * @return {Array} output array + */ +exports.transform2js = function(transformString) { + + // JS representation of the transform data + var transforms = [], + // current transform context + current; + + // split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', ''] + transformString.split(regTransformSplit).forEach(function(item) { + /*jshint -W084 */ + var num; + + if (item) { + // if item is a translate function + if (regTransformTypes.test(item)) { + // then collect it and change current context + transforms.push(current = { name: item }); + // else if item is data + } else { + // then split it into [10, 50] and collect as context.data + while (num = regNumericValues.exec(item)) { + num = Number(num); + if (current.data) + current.data.push(num); + else + current.data = [num]; + } + } + } + }); + + // return empty array if broken transform (no data) + return current && current.data ? transforms : []; +}; + +/** + * Multiply transforms into one. + * + * @param {Array} input transforms array + * @return {Array} output matrix array + */ +exports.transformsMultiply = function(transforms) { + + // convert transforms objects to the matrices + transforms = transforms.map(function(transform) { + if (transform.name === 'matrix') { + return transform.data; + } + return transformToMatrix(transform); + }); + + // multiply all matrices into one + transforms = { + name: 'matrix', + data: transforms.length > 0 ? transforms.reduce(multiplyTransformMatrices) : [] + }; + + return transforms; + +}; + +/** + * Do math like a schoolgirl. + * + * @type {Object} + */ +var mth = exports.mth = { + + rad: function(deg) { + return deg * Math.PI / 180; + }, + + deg: function(rad) { + return rad * 180 / Math.PI; + }, + + cos: function(deg) { + return Math.cos(this.rad(deg)); + }, + + acos: function(val, floatPrecision) { + return +(this.deg(Math.acos(val)).toFixed(floatPrecision)); + }, + + sin: function(deg) { + return Math.sin(this.rad(deg)); + }, + + asin: function(val, floatPrecision) { + return +(this.deg(Math.asin(val)).toFixed(floatPrecision)); + }, + + tan: function(deg) { + return Math.tan(this.rad(deg)); + }, + + atan: function(val, floatPrecision) { + return +(this.deg(Math.atan(val)).toFixed(floatPrecision)); + } + +}; + +/** + * Decompose matrix into simple transforms. See + * http://frederic-wang.fr/decomposition-of-2d-transform-matrices.html + * + * @param {Object} data matrix transform object + * @return {Object|Array} transforms array or original transform object + */ +exports.matrixToTransform = function(transform, params) { + var floatPrecision = params.floatPrecision, + data = transform.data, + transforms = [], + sx = +Math.hypot(data[0], data[1]).toFixed(params.transformPrecision), + sy = +((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(params.transformPrecision), + colsSum = data[0] * data[2] + data[1] * data[3], + rowsSum = data[0] * data[1] + data[2] * data[3], + scaleBefore = rowsSum != 0 || sx == sy; + + // [..., ..., ..., ..., tx, ty] → translate(tx, ty) + if (data[4] || data[5]) { + transforms.push({ name: 'translate', data: data.slice(4, data[5] ? 6 : 5) }); + } + + // [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy) + if (!data[1] && data[2]) { + transforms.push({ name: 'skewX', data: [mth.atan(data[2] / sy, floatPrecision)] }); + + // [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy) + } else if (data[1] && !data[2]) { + transforms.push({ name: 'skewY', data: [mth.atan(data[1] / data[0], floatPrecision)] }); + sx = data[0]; + sy = data[3]; + + // [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or + // [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore) + } else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) { + if (!scaleBefore) { + sx = (data[0] < 0 ? -1 : 1) * Math.hypot(data[0], data[2]); + sy = (data[3] < 0 ? -1 : 1) * Math.hypot(data[1], data[3]); + transforms.push({ name: 'scale', data: [sx, sy] }); + } + var angle = Math.min(Math.max(-1, data[0] / sx), 1), + rotate = [mth.acos(angle, floatPrecision) * ((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1)]; + + if (rotate[0]) transforms.push({ name: 'rotate', data: rotate }); + + if (rowsSum && colsSum) transforms.push({ + name: 'skewX', + data: [mth.atan(colsSum / (sx * sx), floatPrecision)] + }); + + // rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point) + if (rotate[0] && (data[4] || data[5])) { + transforms.shift(); + var cos = data[0] / sx, + sin = data[1] / (scaleBefore ? sx : sy), + x = data[4] * (scaleBefore || sy), + y = data[5] * (scaleBefore || sx), + denom = (Math.pow(1 - cos, 2) + Math.pow(sin, 2)) * (scaleBefore || sx * sy); + rotate.push(((1 - cos) * x - sin * y) / denom); + rotate.push(((1 - cos) * y + sin * x) / denom); + } + + // Too many transformations, return original matrix if it isn't just a scale/translate + } else if (data[1] || data[2]) { + return transform; + } + + if (scaleBefore && (sx != 1 || sy != 1) || !transforms.length) transforms.push({ + name: 'scale', + data: sx == sy ? [sx] : [sx, sy] + }); + + return transforms; +}; + +/** + * Convert transform to the matrix data. + * + * @param {Object} transform transform object + * @return {Array} matrix data + */ +function transformToMatrix(transform) { + + if (transform.name === 'matrix') return transform.data; + + var matrix; + + switch (transform.name) { + case 'translate': + // [1, 0, 0, 1, tx, ty] + matrix = [1, 0, 0, 1, transform.data[0], transform.data[1] || 0]; + break; + case 'scale': + // [sx, 0, 0, sy, 0, 0] + matrix = [transform.data[0], 0, 0, transform.data[1] || transform.data[0], 0, 0]; + break; + case 'rotate': + // [cos(a), sin(a), -sin(a), cos(a), x, y] + var cos = mth.cos(transform.data[0]), + sin = mth.sin(transform.data[0]), + cx = transform.data[1] || 0, + cy = transform.data[2] || 0; + + matrix = [cos, sin, -sin, cos, (1 - cos) * cx + sin * cy, (1 - cos) * cy - sin * cx]; + break; + case 'skewX': + // [1, 0, tan(a), 1, 0, 0] + matrix = [1, 0, mth.tan(transform.data[0]), 1, 0, 0]; + break; + case 'skewY': + // [1, tan(a), 0, 1, 0, 0] + matrix = [1, mth.tan(transform.data[0]), 0, 1, 0, 0]; + break; + } + + return matrix; + +} + +/** + * Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it + * by the transformation matrix and use a singular value decomposition to represent in a form + * rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ. + * SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}}) + * + * @param {Array} arc [a, b, rotation in deg] + * @param {Array} transform transformation matrix + * @return {Array} arc transformed input arc + */ +exports.transformArc = function(arc, transform) { + + var a = arc[0], + b = arc[1], + rot = arc[2] * Math.PI / 180, + cos = Math.cos(rot), + sin = Math.sin(rot), + h = Math.pow(arc[5] * cos + arc[6] * sin, 2) / (4 * a * a) + + Math.pow(arc[6] * cos - arc[5] * sin, 2) / (4 * b * b); + if (h > 1) { + h = Math.sqrt(h); + a *= h; + b *= h; + } + var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0], + m = multiplyTransformMatrices(transform, ellipse), + // Decompose the new ellipse matrix + lastCol = m[2] * m[2] + m[3] * m[3], + squareSum = m[0] * m[0] + m[1] * m[1] + lastCol, + root = Math.hypot(m[0] - m[3], m[1] + m[2]) * Math.hypot(m[0] + m[3], m[1] - m[2]); + + if (!root) { // circle + arc[0] = arc[1] = Math.sqrt(squareSum / 2); + arc[2] = 0; + } else { + var majorAxisSqr = (squareSum + root) / 2, + minorAxisSqr = (squareSum - root) / 2, + major = Math.abs(majorAxisSqr - lastCol) > 1e-6, + sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol, + rowsSum = m[0] * m[2] + m[1] * m[3], + term1 = m[0] * sub + m[2] * rowsSum, + term2 = m[1] * sub + m[3] * rowsSum; + arc[0] = Math.sqrt(majorAxisSqr); + arc[1] = Math.sqrt(minorAxisSqr); + arc[2] = ((major ? term2 < 0 : term1 > 0) ? -1 : 1) * + Math.acos((major ? term1 : term2) / Math.hypot(term1, term2)) * 180 / Math.PI; + } + + if ((transform[0] < 0) !== (transform[3] < 0)) { + // Flip the sweep flag if coordinates are being flipped horizontally XOR vertically + arc[4] = 1 - arc[4]; + } + + return arc; + +}; + +/** + * Multiply transformation matrices. + * + * @param {Array} a matrix A data + * @param {Array} b matrix B data + * @return {Array} result + */ +function multiplyTransformMatrices(a, b) { + + return [ + a[0] * b[0] + a[2] * b[1], + a[1] * b[0] + a[3] * b[1], + a[0] * b[2] + a[2] * b[3], + a[1] * b[2] + a[3] * b[3], + a[0] * b[4] + a[2] * b[5] + a[4], + a[1] * b[4] + a[3] * b[5] + a[5] + ]; + +} diff --git a/vendor/svgclean/src/svgclean/plugins/addAttributesToSVGElement.js b/vendor/svgclean/src/svgclean/plugins/addAttributesToSVGElement.js new file mode 100644 index 000000000..da2448b1b --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/addAttributesToSVGElement.js @@ -0,0 +1,82 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'adds attributes to an outer <svg> element'; + +var ENOCLS = `Error in plugin "addAttributesToSVGElement": absent parameters. +It should have a list of "attributes" or one "attribute". +Config example: + +plugins: +- addAttributesToSVGElement: + attribute: "mySvg" + +plugins: +- addAttributesToSVGElement: + attributes: ["mySvg", "size-big"] + +plugins: +- addAttributesToSVGElement: + attributes: + - focusable: false + - data-image: icon`; + +/** + * Add attributes to an outer <svg> element. Example config: + * + * plugins: + * - addAttributesToSVGElement: + * attribute: 'data-icon' + * + * plugins: + * - addAttributesToSVGElement: + * attributes: ['data-icon', 'data-disabled'] + * + * plugins: + * - addAttributesToSVGElement: + * attributes: + * - focusable: false + * - data-image: icon + * + * @author April Arcus + */ +exports.fn = function(data, params) { + if (!params || !(Array.isArray(params.attributes) || params.attribute)) { + console.error(ENOCLS); + return data; + } + + var attributes = params.attributes || [ params.attribute ], + svg = data.content[0]; + + if (svg.isElem('svg')) { + attributes.forEach(function (attribute) { + if (typeof attribute === 'string') { + if (!svg.hasAttr(attribute)) { + svg.addAttr({ + name: attribute, + prefix: '', + local: attribute + }); + } + } else if (typeof attribute === 'object') { + Object.keys(attribute).forEach(function (key) { + if (!svg.hasAttr(key)) { + svg.addAttr({ + name: key, + value: attribute[key], + prefix: '', + local: key + }); + } + }); + } + }); + } + + return data; + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/addClassesToSVGElement.js b/vendor/svgclean/src/svgclean/plugins/addClassesToSVGElement.js new file mode 100644 index 000000000..ef215fc93 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/addClassesToSVGElement.js @@ -0,0 +1,50 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'adds classnames to an outer <svg> element'; + +var ENOCLS = `Error in plugin "addClassesToSVGElement": absent parameters. +It should have a list of classes in "classNames" or one "className". +Config example: + +plugins: +- addClassesToSVGElement: + className: "mySvg" + +plugins: +- addClassesToSVGElement: + classNames: ["mySvg", "size-big"] +`; + +/** + * Add classnames to an outer <svg> element. Example config: + * + * plugins: + * - addClassesToSVGElement: + * className: 'mySvg' + * + * plugins: + * - addClassesToSVGElement: + * classNames: ['mySvg', 'size-big'] + * + * @author April Arcus + */ +exports.fn = function(data, params) { + if (!params || !(Array.isArray(params.classNames) && params.classNames.some(String) || params.className)) { + console.error(ENOCLS); + return data; + } + + var classNames = params.classNames || [ params.className ], + svg = data.content[0]; + + if (svg.isElem('svg')) { + svg.class.add.apply(svg.class, classNames); + } + + return data; + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/cleanupAttrs.js b/vendor/svgclean/src/svgclean/plugins/cleanupAttrs.js new file mode 100644 index 000000000..47e77ac79 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/cleanupAttrs.js @@ -0,0 +1,56 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'cleanups attributes from newlines, trailing and repeating spaces'; + +exports.params = { + newlines: true, + trim: true, + spaces: true +}; + +var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g, + regNewlines = /\r?\n/g, + regSpaces = /\s{2,}/g; + +/** + * Cleanup attributes values from newlines, trailing and repeating spaces. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem()) { + + item.eachAttr(function(attr) { + + if (params.newlines) { + // new line which requires a space instead of themselve + attr.value = attr.value.replace(regNewlinesNeedSpace, function(match, p1, p2) { + return p1 + ' ' + p2; + }); + + // simple new line + attr.value = attr.value.replace(regNewlines, ''); + } + + if (params.trim) { + attr.value = attr.value.trim(); + } + + if (params.spaces) { + attr.value = attr.value.replace(regSpaces, ' '); + } + + }); + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/cleanupEnableBackground.js b/vendor/svgclean/src/svgclean/plugins/cleanupEnableBackground.js new file mode 100644 index 000000000..e6384ab50 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/cleanupEnableBackground.js @@ -0,0 +1,84 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'remove or cleanup enable-background attribute when possible'; + +/** + * Remove or cleanup enable-background attr which coincides with a width/height box. + * + * @see http://www.w3.org/TR/SVG/filters.html#EnableBackgroundProperty + * + * @example + * <svg width="100" height="50" enable-background="new 0 0 100 50"> + * ⬇ + * <svg width="100" height="50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(data) { + + var regEnableBackground = /^new\s0\s0\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)$/, + hasFilter = false, + elems = ['svg', 'mask', 'pattern']; + + function checkEnableBackground(item) { + if ( + item.isElem(elems) && + item.hasAttr('enable-background') && + item.hasAttr('width') && + item.hasAttr('height') + ) { + + var match = item.attr('enable-background').value.match(regEnableBackground); + + if (match) { + if ( + item.attr('width').value === match[1] && + item.attr('height').value === match[3] + ) { + if (item.isElem('svg')) { + item.removeAttr('enable-background'); + } else { + item.attr('enable-background').value = 'new'; + } + } + } + + } + } + + function checkForFilter(item) { + if (item.isElem('filter')) { + hasFilter = true; + } + } + + function monkeys(items, fn) { + items.content.forEach(function(item) { + fn(item); + + if (item.content) { + monkeys(item, fn); + } + }); + return items; + } + + var firstStep = monkeys(data, function(item) { + checkEnableBackground(item); + if (!hasFilter) { + checkForFilter(item); + } + }); + + return hasFilter ? firstStep : monkeys(firstStep, function(item) { + //we don't need 'enable-background' if we have no filters + item.removeAttr('enable-background'); + }); +}; diff --git a/vendor/svgclean/src/svgclean/plugins/cleanupIDs.js b/vendor/svgclean/src/svgclean/plugins/cleanupIDs.js new file mode 100644 index 000000000..71ffb5f93 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/cleanupIDs.js @@ -0,0 +1,212 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'removes unused IDs and minifies used'; + +exports.params = { + remove: true, + minify: true, + prefix: '', + preserve: [], + preservePrefixes: [], + force: false +}; + +var referencesProps = new Set(require('./_collections').referencesProps), + regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/, + regReferencesHref = /^#(.+?)$/, + regReferencesBegin = /(\w+)\./, + styleOrScript = ['style', 'script'], + generateIDchars = [ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' + ], + maxIDindex = generateIDchars.length - 1; + +/** + * Remove unused and minify used IDs + * (only if there are no any <style> or <script>). + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * + * @author Kir Belevich + */ +exports.fn = function(data, params) { + var currentID, + currentIDstring, + IDs = new Map(), + referencesIDs = new Map(), + hasStyleOrScript = false, + preserveIDs = new Set(Array.isArray(params.preserve) ? params.preserve : params.preserve ? [params.preserve] : []), + preserveIDPrefixes = new Set(Array.isArray(params.preservePrefixes) ? params.preservePrefixes : (params.preservePrefixes ? [params.preservePrefixes] : [])), + idValuePrefix = '#', + idValuePostfix = '.'; + + /** + * Bananas! + * + * @param {Array} items input items + * @return {Array} output items + */ + function monkeys(items) { + for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) { + var item = items.content[i]; + + // quit if <style> or <script> present ('force' param prevents quitting) + if (!params.force) { + var isNotEmpty = Boolean(item.content); + if (item.isElem(styleOrScript) && isNotEmpty) { + hasStyleOrScript = true; + continue; + } + + // Don't remove IDs if the whole SVG consists only of defs. + if (item.isElem('svg')) { + var hasDefsOnly = true; + + for (var j = 0; j < item.content.length; j++) { + if (!item.content[j].isElem('defs')) { + hasDefsOnly = false; + break; + } + } + if (hasDefsOnly) { + break; + } + } + } + // …and don't remove any ID if yes + if (item.isElem()) { + item.eachAttr(function(attr) { + var key, match; + + // save IDs + if (attr.name === 'id') { + key = attr.value; + if (IDs.has(key)) { + item.removeAttr('id'); // remove repeated id + } else { + IDs.set(key, item); + } + return; + } + // save references + if (referencesProps.has(attr.name) && (match = attr.value.match(regReferencesUrl))) { + key = match[2]; // url() reference + } else if ( + attr.local === 'href' && (match = attr.value.match(regReferencesHref)) || + attr.name === 'begin' && (match = attr.value.match(regReferencesBegin)) + ) { + key = match[1]; // href reference + } + if (key) { + var ref = referencesIDs.get(key) || []; + ref.push(attr); + referencesIDs.set(key, ref); + } + }); + } + // go deeper + if (item.content) { + monkeys(item); + } + } + return items; + } + + data = monkeys(data); + + if (hasStyleOrScript) { + return data; + } + + const idPreserved = id => preserveIDs.has(id) || idMatchesPrefix(preserveIDPrefixes, id); + + for (var ref of referencesIDs) { + var key = ref[0]; + + if (IDs.has(key)) { + // replace referenced IDs with the minified ones + if (params.minify && !idPreserved(key)) { + do { + currentIDstring = getIDstring(currentID = generateID(currentID), params); + } while (idPreserved(currentIDstring)); + + IDs.get(key).attr('id').value = currentIDstring; + + for (var attr of ref[1]) { + attr.value = attr.value.includes(idValuePrefix) ? + attr.value.replace(idValuePrefix + key, idValuePrefix + currentIDstring) : + attr.value.replace(key + idValuePostfix, currentIDstring + idValuePostfix); + } + } + // don't remove referenced IDs + IDs.delete(key); + } + } + // remove non-referenced IDs attributes from elements + if (params.remove) { + for(var keyElem of IDs) { + if (!idPreserved(keyElem[0])) { + keyElem[1].removeAttr('id'); + } + } + } + return data; +}; + +/** + * Check if an ID starts with any one of a list of strings. + * + * @param {Array} of prefix strings + * @param {String} current ID + * @return {Boolean} if currentID starts with one of the strings in prefixArray + */ +function idMatchesPrefix(prefixArray, currentID) { + if (!currentID) return false; + + for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true; + return false; +} + +/** + * Generate unique minimal ID. + * + * @param {Array} [currentID] current ID + * @return {Array} generated ID array + */ +function generateID(currentID) { + if (!currentID) return [0]; + + currentID[currentID.length - 1]++; + + for(var i = currentID.length - 1; i > 0; i--) { + if (currentID[i] > maxIDindex) { + currentID[i] = 0; + + if (currentID[i - 1] !== undefined) { + currentID[i - 1]++; + } + } + } + if (currentID[0] > maxIDindex) { + currentID[0] = 0; + currentID.unshift(0); + } + return currentID; +} + +/** + * Get string from generated ID array. + * + * @param {Array} arr input ID array + * @return {String} output ID string + */ +function getIDstring(arr, params) { + var str = params.prefix; + return str + arr.map(i => generateIDchars[i]).join(''); +} diff --git a/vendor/svgclean/src/svgclean/plugins/cleanupListOfValues.js b/vendor/svgclean/src/svgclean/plugins/cleanupListOfValues.js new file mode 100644 index 000000000..84aaef1e9 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/cleanupListOfValues.js @@ -0,0 +1,139 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'rounds list of values to the fixed precision'; + +exports.params = { + floatPrecision: 3, + leadingZero: true, + defaultPx: true, + convertToPx: true +}; + +var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/, + regSeparator = /\s+,?\s*|,\s*/, + removeLeadingZero = require('../tools').removeLeadingZero, + absoluteLengths = { // relative to px + cm: 96/2.54, + mm: 96/25.4, + in: 96, + pt: 4/3, + pc: 16 + }; + +/** + * Round list of values to the fixed precision. + * + * @example + * <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423"> + * ⬇ + * <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284"> + * + * + * <polygon points="208.250977 77.1308594 223.069336 ... "/> + * ⬇ + * <polygon points="208.251 77.131 223.069 ... "/> + * + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author kiyopikko + */ +exports.fn = function(item, params) { + + + if ( item.hasAttr('points') ) { + roundValues(item.attrs.points); + } + + if ( item.hasAttr('enable-background') ) { + roundValues(item.attrs['enable-background']); + } + + if ( item.hasAttr('viewBox') ) { + roundValues(item.attrs.viewBox); + } + + if ( item.hasAttr('stroke-dasharray') ) { + roundValues(item.attrs['stroke-dasharray']); + } + + if ( item.hasAttr('dx') ) { + roundValues(item.attrs.dx); + } + + if ( item.hasAttr('dy') ) { + roundValues(item.attrs.dy); + } + + if ( item.hasAttr('x') ) { + roundValues(item.attrs.x); + } + + if ( item.hasAttr('y') ) { + roundValues(item.attrs.y); + } + + + function roundValues($prop){ + + var num, units, + match, + matchNew, + lists = $prop.value, + listsArr = lists.split(regSeparator), + roundedListArr = [], + roundedList; + + listsArr.forEach(function(elem){ + + match = elem.match(regNumericValues); + matchNew = elem.match(/new/); + + // if attribute value matches regNumericValues + if (match) { + // round it to the fixed precision + num = +(+match[1]).toFixed(params.floatPrecision), + units = match[3] || ''; + + // convert absolute values to pixels + if (params.convertToPx && units && (units in absoluteLengths)) { + var pxNum = +(absoluteLengths[units] * match[1]).toFixed(params.floatPrecision); + + if (String(pxNum).length < match[0].length) + num = pxNum, + units = 'px'; + } + + // and remove leading zero + if (params.leadingZero) { + num = removeLeadingZero(num); + } + + // remove default 'px' units + if (params.defaultPx && units === 'px') { + units = ''; + } + + roundedListArr.push(num+units); + } + // if attribute value is "new"(only enable-background). + else if (matchNew) { + roundedListArr.push('new'); + } else if (elem) { + roundedListArr.push(elem); + } + + }); + + roundedList = roundedListArr.join(' '); + $prop.value = roundedList; + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/cleanupNumericValues.js b/vendor/svgclean/src/svgclean/plugins/cleanupNumericValues.js new file mode 100644 index 000000000..82c0f58e2 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/cleanupNumericValues.js @@ -0,0 +1,88 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'rounds numeric values to the fixed precision, removes default ‘px’ units'; + +exports.params = { + floatPrecision: 3, + leadingZero: true, + defaultPx: true, + convertToPx: true +}; + +var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/, + removeLeadingZero = require('../tools').removeLeadingZero, + absoluteLengths = { // relative to px + cm: 96/2.54, + mm: 96/25.4, + in: 96, + pt: 4/3, + pc: 16 + }; + +/** + * Round numeric values to the fixed precision, + * remove default 'px' units. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem()) { + + var floatPrecision = params.floatPrecision; + + if (item.hasAttr('viewBox')) { + var nums = item.attr('viewBox').value.split(/\s,?\s*|,\s*/g); + item.attr('viewBox').value = nums.map(function(value) { + var num = +value; + return isNaN(num) ? value : +num.toFixed(floatPrecision); + }).join(' '); + } + + item.eachAttr(function(attr) { + // The `version` attribute is a text string and cannot be rounded + if (attr.name === 'version') { return } + + var match = attr.value.match(regNumericValues); + + // if attribute value matches regNumericValues + if (match) { + // round it to the fixed precision + var num = +(+match[1]).toFixed(floatPrecision), + units = match[3] || ''; + + // convert absolute values to pixels + if (params.convertToPx && units && (units in absoluteLengths)) { + var pxNum = +(absoluteLengths[units] * match[1]).toFixed(floatPrecision); + + if (String(pxNum).length < match[0].length) { + num = pxNum; + units = 'px'; + } + } + + // and remove leading zero + if (params.leadingZero) { + num = removeLeadingZero(num); + } + + // remove default 'px' units + if (params.defaultPx && units === 'px') { + units = ''; + } + + attr.value = num + units; + } + }); + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/collapseGroups.js b/vendor/svgclean/src/svgclean/plugins/collapseGroups.js new file mode 100644 index 000000000..3daa5a889 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/collapseGroups.js @@ -0,0 +1,87 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'collapses useless groups'; + +var collections = require('./_collections'), + attrsInheritable = collections.inheritableAttrs, + animationElems = collections.elemsGroups.animation; + +function hasAnimatedAttr(item) { + /* jshint validthis:true */ + return item.isElem(animationElems) && item.hasAttr('attributeName', this) || + !item.isEmpty() && item.content.some(hasAnimatedAttr, this); +} + +/* + * Collapse useless groups. + * + * @example + * <g> + * <g attr1="val1"> + * <path d="..."/> + * </g> + * </g> + * ⬇ + * <g> + * <g> + * <path attr1="val1" d="..."/> + * </g> + * </g> + * ⬇ + * <path attr1="val1" d="..."/> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + // non-empty elements + if (item.isElem() && !item.isElem('switch') && !item.isEmpty()) { + item.content.forEach(function(g, i) { + // non-empty groups + if (g.isElem('g') && !g.isEmpty()) { + // move group attibutes to the single content element + if (g.hasAttr() && g.content.length === 1) { + var inner = g.content[0]; + + if (inner.isElem() && !inner.hasAttr('id') && !g.hasAttr('filter') && + !(g.hasAttr('class') && inner.hasAttr('class')) && ( + !g.hasAttr('clip-path') && !g.hasAttr('mask') || + inner.isElem('g') && !g.hasAttr('transform') && !inner.hasAttr('transform') + ) + ) { + g.eachAttr(function(attr) { + if (g.content.some(hasAnimatedAttr, attr.name)) return; + + if (!inner.hasAttr(attr.name)) { + inner.addAttr(attr); + } else if (attr.name == 'transform') { + inner.attr(attr.name).value = attr.value + ' ' + inner.attr(attr.name).value; + } else if (inner.hasAttr(attr.name, 'inherit')) { + inner.attr(attr.name).value = attr.value; + } else if ( + attrsInheritable.indexOf(attr.name) < 0 && + !inner.hasAttr(attr.name, attr.value) + ) { + return; + } + + g.removeAttr(attr.name); + }); + } + } + + // collapse groups without attributes + if (!g.hasAttr() && !g.content.some(function(item) { return item.isElem(animationElems) })) { + item.spliceContent(i, 1, g.content); + } + } + }); + } +}; diff --git a/vendor/svgclean/src/svgclean/plugins/convertColors.js b/vendor/svgclean/src/svgclean/plugins/convertColors.js new file mode 100644 index 000000000..77279e942 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertColors.js @@ -0,0 +1,130 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb'; + +exports.params = { + currentColor: false, + names2hex: true, + rgb2hex: true, + shorthex: true, + shortname: true +}; + +var collections = require('./_collections'), + rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)', + rComma = '\\s*,\\s*', + regRGB = new RegExp('^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'), + regHEX = /^\#(([a-fA-F0-9])\2){3}$/, + none = /\bnone\b/i; + +/** + * Convert different colors formats in element attributes to hex. + * + * @see http://www.w3.org/TR/SVG/types.html#DataTypeColor + * @see http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords + * + * @example + * Convert color name keyword to long hex: + * fuchsia ➡ #ff00ff + * + * Convert rgb() to long hex: + * rgb(255, 0, 255) ➡ #ff00ff + * rgb(50%, 100, 100%) ➡ #7f64ff + * + * Convert long hex to short hex: + * #aabbcc ➡ #abc + * + * Convert hex to short name + * #000080 ➡ navy + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.elem) { + + item.eachAttr(function(attr) { + + if (collections.colorsProps.indexOf(attr.name) > -1) { + + var val = attr.value, + match; + + // Convert colors to currentColor + if (params.currentColor) { + if (typeof params.currentColor === 'string') { + match = val === params.currentColor; + } else if (params.currentColor.exec) { + match = params.currentColor.exec(val); + } else { + match = !val.match(none); + } + if (match) { + val = 'currentColor'; + } + } + + // Convert color name keyword to long hex + if (params.names2hex && val.toLowerCase() in collections.colorsNames) { + val = collections.colorsNames[val.toLowerCase()]; + } + + // Convert rgb() to long hex + if (params.rgb2hex && (match = val.match(regRGB))) { + match = match.slice(1, 4).map(function(m) { + if (m.indexOf('%') > -1) + m = Math.round(parseFloat(m) * 2.55); + + return Math.max(0, Math.min(m, 255)); + }); + + val = rgb2hex(match); + } + + // Convert long hex to short hex + if (params.shorthex && (match = val.match(regHEX))) { + val = '#' + match[0][1] + match[0][3] + match[0][5]; + } + + // Convert hex to short name + if (params.shortname) { + var lowerVal = val.toLowerCase(); + if (lowerVal in collections.colorsShortNames) { + val = collections.colorsShortNames[lowerVal]; + } + } + + attr.value = val; + + } + + }); + + } + +}; + +/** + * Convert [r, g, b] to #rrggbb. + * + * @see https://gist.github.com/983535 + * + * @example + * rgb2hex([255, 255, 255]) // '#ffffff' + * + * @param {Array} rgb [r, g, b] + * @return {String} #rrggbb + * + * @author Jed Schmidt + */ +function rgb2hex(rgb) { + return '#' + ('00000' + (rgb[0] << 16 | rgb[1] << 8 | rgb[2]).toString(16)).slice(-6).toUpperCase(); +} diff --git a/vendor/svgclean/src/svgclean/plugins/convertEllipseToCircle.js b/vendor/svgclean/src/svgclean/plugins/convertEllipseToCircle.js new file mode 100644 index 000000000..f1af11a94 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertEllipseToCircle.js @@ -0,0 +1,39 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts non-eccentric <ellipse>s to <circle>s'; + +/** + * Converts non-eccentric <ellipse>s to <circle>s. + * + * @see http://www.w3.org/TR/SVG/shapes.html + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Taylor Hunt + */ +exports.fn = function(item) { + if (item.isElem('ellipse')) { + var rx = item.attr('rx').value || 0; + var ry = item.attr('ry').value || 0; + + if (rx === ry || + rx === 'auto' || ry === 'auto' // SVG2 + ) { + var radius = rx !== 'auto' ? rx : ry; + item.renameElem('circle'); + item.removeAttr(['rx', 'ry']); + item.addAttr({ + name: 'r', + value: radius, + prefix: '', + local: 'r', + }); + } + } + return; +}; diff --git a/vendor/svgclean/src/svgclean/plugins/convertPathData.js b/vendor/svgclean/src/svgclean/plugins/convertPathData.js new file mode 100644 index 000000000..954c2bfe1 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertPathData.js @@ -0,0 +1,971 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'optimizes path data: writes in shorter form, applies transformations'; + +exports.params = { + applyTransforms: true, + applyTransformsStroked: true, + makeArcs: { + threshold: 2.5, // coefficient of rounding error + tolerance: 0.5 // percentage of radius + }, + straightCurves: true, + lineShorthands: true, + curveSmoothShorthands: true, + floatPrecision: 3, + transformPrecision: 5, + removeUseless: true, + collapseRepeated: true, + utilizeAbsolute: true, + leadingZero: true, + negativeExtraSpace: true, + noSpaceAfterFlags: true, + forceAbsolutePath: false +}; + +var pathElems = require('./_collections.js').pathElems, + path2js = require('./_path.js').path2js, + js2path = require('./_path.js').js2path, + applyTransforms = require('./_path.js').applyTransforms, + cleanupOutData = require('../tools').cleanupOutData, + roundData, + precision, + error, + arcThreshold, + arcTolerance, + hasMarkerMid, + hasStrokeLinecap; + +/** + * Convert absolute Path to relative, + * collapse repeated instructions, + * detect and convert Lineto shorthands, + * remove useless instructions like "l0,0", + * trim useless delimiters and leading zeros, + * decrease accuracy of floating-point numbers. + * + * @see http://www.w3.org/TR/SVG/paths.html#PathData + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem(pathElems) && item.hasAttr('d')) { + + precision = params.floatPrecision; + error = precision !== false ? +Math.pow(.1, precision).toFixed(precision) : 1e-2; + roundData = precision > 0 && precision < 20 ? strongRound : round; + if (params.makeArcs) { + arcThreshold = params.makeArcs.threshold; + arcTolerance = params.makeArcs.tolerance; + } + hasMarkerMid = item.hasAttr('marker-mid'); + + var stroke = item.computedAttr('stroke'), + strokeLinecap = item.computedAttr('stroke'); + hasStrokeLinecap = stroke && stroke != 'none' && strokeLinecap && strokeLinecap != 'butt'; + + var data = path2js(item); + + // TODO: get rid of functions returns + if (data.length) { + convertToRelative(data); + + if (params.applyTransforms) { + data = applyTransforms(item, data, params); + } + + data = filters(data, params); + + if (params.utilizeAbsolute) { + data = convertToMixed(data, params); + } + + js2path(item, data, params); + } + + } + +}; + +/** + * Convert absolute path data coordinates to relative. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {Array} output path data + */ +function convertToRelative(path) { + + var point = [0, 0], + subpathPoint = [0, 0], + baseItem; + + path.forEach(function(item, index) { + + var instruction = item.instruction, + data = item.data; + + // data !== !z + if (data) { + + // already relative + // recalculate current point + if ('mcslqta'.indexOf(instruction) > -1) { + + point[0] += data[data.length - 2]; + point[1] += data[data.length - 1]; + + if (instruction === 'm') { + subpathPoint[0] = point[0]; + subpathPoint[1] = point[1]; + baseItem = item; + } + + } else if (instruction === 'h') { + + point[0] += data[0]; + + } else if (instruction === 'v') { + + point[1] += data[0]; + + } + + // convert absolute path data coordinates to relative + // if "M" was not transformed from "m" + // M → m + if (instruction === 'M') { + + if (index > 0) instruction = 'm'; + + data[0] -= point[0]; + data[1] -= point[1]; + + subpathPoint[0] = point[0] += data[0]; + subpathPoint[1] = point[1] += data[1]; + + baseItem = item; + + } + + // L → l + // T → t + else if ('LT'.indexOf(instruction) > -1) { + + instruction = instruction.toLowerCase(); + + // x y + // 0 1 + data[0] -= point[0]; + data[1] -= point[1]; + + point[0] += data[0]; + point[1] += data[1]; + + // C → c + } else if (instruction === 'C') { + + instruction = 'c'; + + // x1 y1 x2 y2 x y + // 0 1 2 3 4 5 + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + data[4] -= point[0]; + data[5] -= point[1]; + + point[0] += data[4]; + point[1] += data[5]; + + // S → s + // Q → q + } else if ('SQ'.indexOf(instruction) > -1) { + + instruction = instruction.toLowerCase(); + + // x1 y1 x y + // 0 1 2 3 + data[0] -= point[0]; + data[1] -= point[1]; + data[2] -= point[0]; + data[3] -= point[1]; + + point[0] += data[2]; + point[1] += data[3]; + + // A → a + } else if (instruction === 'A') { + + instruction = 'a'; + + // rx ry x-axis-rotation large-arc-flag sweep-flag x y + // 0 1 2 3 4 5 6 + data[5] -= point[0]; + data[6] -= point[1]; + + point[0] += data[5]; + point[1] += data[6]; + + // H → h + } else if (instruction === 'H') { + + instruction = 'h'; + + data[0] -= point[0]; + + point[0] += data[0]; + + // V → v + } else if (instruction === 'V') { + + instruction = 'v'; + + data[0] -= point[1]; + + point[1] += data[0]; + + } + + item.instruction = instruction; + item.data = data; + + // store absolute coordinates for later use + item.coords = point.slice(-2); + + } + + // !data === z, reset current point + else if (instruction == 'z') { + if (baseItem) { + item.coords = baseItem.coords; + } + point[0] = subpathPoint[0]; + point[1] = subpathPoint[1]; + } + + item.base = index > 0 ? path[index - 1].coords : [0, 0]; + + }); + + return path; + +} + +/** + * Main filters loop. + * + * @param {Array} path input path data + * @param {Object} params plugin params + * @return {Array} output path data + */ +function filters(path, params) { + + var stringify = data2Path.bind(null, params), + relSubpoint = [0, 0], + pathBase = [0, 0], + prev = {}; + + path = path.filter(function(item, index, path) { + + var instruction = item.instruction, + data = item.data, + next = path[index + 1]; + + if (data) { + + var sdata = data, + circle; + + if (instruction === 's') { + sdata = [0, 0].concat(data); + + if ('cs'.indexOf(prev.instruction) > -1) { + var pdata = prev.data, + n = pdata.length; + + // (-x, -y) of the prev tangent point relative to the current point + sdata[0] = pdata[n - 2] - pdata[n - 4]; + sdata[1] = pdata[n - 1] - pdata[n - 3]; + } + + } + + // convert curves to arcs if possible + if ( + params.makeArcs && + (instruction == 'c' || instruction == 's') && + isConvex(sdata) && + (circle = findCircle(sdata)) + ) { + var r = roundData([circle.radius])[0], + angle = findArcAngle(sdata, circle), + sweep = sdata[5] * sdata[0] - sdata[4] * sdata[1] > 0 ? 1 : 0, + arc = { + instruction: 'a', + data: [r, r, 0, 0, sweep, sdata[4], sdata[5]], + coords: item.coords.slice(), + base: item.base + }, + output = [arc], + // relative coordinates to adjust the found circle + relCenter = [circle.center[0] - sdata[4], circle.center[1] - sdata[5]], + relCircle = { center: relCenter, radius: circle.radius }, + arcCurves = [item], + hasPrev = 0, + suffix = '', + nextLonghand; + + if ( + prev.instruction == 'c' && isConvex(prev.data) && isArcPrev(prev.data, circle) || + prev.instruction == 'a' && prev.sdata && isArcPrev(prev.sdata, circle) + ) { + arcCurves.unshift(prev); + arc.base = prev.base; + arc.data[5] = arc.coords[0] - arc.base[0]; + arc.data[6] = arc.coords[1] - arc.base[1]; + var prevData = prev.instruction == 'a' ? prev.sdata : prev.data; + var prevAngle = findArcAngle(prevData, + { + center: [prevData[4] + circle.center[0], prevData[5] + circle.center[1]], + radius: circle.radius + } + ); + angle += prevAngle; + if (angle > Math.PI) arc.data[3] = 1; + hasPrev = 1; + } + + // check if next curves are fitting the arc + for (var j = index; (next = path[++j]) && ~'cs'.indexOf(next.instruction);) { + var nextData = next.data; + if (next.instruction == 's') { + nextLonghand = makeLonghand({instruction: 's', data: next.data.slice() }, + path[j - 1].data); + nextData = nextLonghand.data; + nextLonghand.data = nextData.slice(0, 2); + suffix = stringify([nextLonghand]); + } + if (isConvex(nextData) && isArc(nextData, relCircle)) { + angle += findArcAngle(nextData, relCircle); + if (angle - 2 * Math.PI > 1e-3) break; // more than 360° + if (angle > Math.PI) arc.data[3] = 1; + arcCurves.push(next); + if (2 * Math.PI - angle > 1e-3) { // less than 360° + arc.coords = next.coords; + arc.data[5] = arc.coords[0] - arc.base[0]; + arc.data[6] = arc.coords[1] - arc.base[1]; + } else { + // full circle, make a half-circle arc and add a second one + arc.data[5] = 2 * (relCircle.center[0] - nextData[4]); + arc.data[6] = 2 * (relCircle.center[1] - nextData[5]); + arc.coords = [arc.base[0] + arc.data[5], arc.base[1] + arc.data[6]]; + arc = { + instruction: 'a', + data: [r, r, 0, 0, sweep, + next.coords[0] - arc.coords[0], next.coords[1] - arc.coords[1]], + coords: next.coords, + base: arc.coords + }; + output.push(arc); + j++; + break; + } + relCenter[0] -= nextData[4]; + relCenter[1] -= nextData[5]; + } else break; + } + + if ((stringify(output) + suffix).length < stringify(arcCurves).length) { + if (path[j] && path[j].instruction == 's') { + makeLonghand(path[j], path[j - 1].data); + } + if (hasPrev) { + var prevArc = output.shift(); + roundData(prevArc.data); + relSubpoint[0] += prevArc.data[5] - prev.data[prev.data.length - 2]; + relSubpoint[1] += prevArc.data[6] - prev.data[prev.data.length - 1]; + prev.instruction = 'a'; + prev.data = prevArc.data; + item.base = prev.coords = prevArc.coords; + } + arc = output.shift(); + if (arcCurves.length == 1) { + item.sdata = sdata.slice(); // preserve curve data for future checks + } else if (arcCurves.length - 1 - hasPrev > 0) { + // filter out consumed next items + path.splice.apply(path, [index + 1, arcCurves.length - 1 - hasPrev].concat(output)); + } + if (!arc) return false; + instruction = 'a'; + data = arc.data; + item.coords = arc.coords; + } + } + + // Rounding relative coordinates, taking in account accummulating error + // to get closer to absolute coordinates. Sum of rounded value remains same: + // l .25 3 .25 2 .25 3 .25 2 -> l .3 3 .2 2 .3 3 .2 2 + if (precision !== false) { + if ('mltqsc'.indexOf(instruction) > -1) { + for (var i = data.length; i--;) { + data[i] += item.base[i % 2] - relSubpoint[i % 2]; + } + } else if (instruction == 'h') { + data[0] += item.base[0] - relSubpoint[0]; + } else if (instruction == 'v') { + data[0] += item.base[1] - relSubpoint[1]; + } else if (instruction == 'a') { + data[5] += item.base[0] - relSubpoint[0]; + data[6] += item.base[1] - relSubpoint[1]; + } + roundData(data); + + if (instruction == 'h') relSubpoint[0] += data[0]; + else if (instruction == 'v') relSubpoint[1] += data[0]; + else { + relSubpoint[0] += data[data.length - 2]; + relSubpoint[1] += data[data.length - 1]; + } + roundData(relSubpoint); + + if (instruction.toLowerCase() == 'm') { + pathBase[0] = relSubpoint[0]; + pathBase[1] = relSubpoint[1]; + } + } + + // convert straight curves into lines segments + if (params.straightCurves) { + + if ( + instruction === 'c' && + isCurveStraightLine(data) || + instruction === 's' && + isCurveStraightLine(sdata) + ) { + if (next && next.instruction == 's') + makeLonghand(next, data); // fix up next curve + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 'q' && + isCurveStraightLine(data) + ) { + if (next && next.instruction == 't') + makeLonghand(next, data); // fix up next curve + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 't' && + prev.instruction !== 'q' && + prev.instruction !== 't' + ) { + instruction = 'l'; + data = data.slice(-2); + } + + else if ( + instruction === 'a' && + (data[0] === 0 || data[1] === 0) + ) { + instruction = 'l'; + data = data.slice(-2); + } + } + + // horizontal and vertical line shorthands + // l 50 0 → h 50 + // l 0 50 → v 50 + if ( + params.lineShorthands && + instruction === 'l' + ) { + if (data[1] === 0) { + instruction = 'h'; + data.pop(); + } else if (data[0] === 0) { + instruction = 'v'; + data.shift(); + } + } + + // collapse repeated commands + // h 20 h 30 -> h 50 + if ( + params.collapseRepeated && + !hasMarkerMid && + ('mhv'.indexOf(instruction) > -1) && + prev.instruction && + instruction == prev.instruction.toLowerCase() && + ( + (instruction != 'h' && instruction != 'v') || + (prev.data[0] >= 0) == (data[0] >= 0) + )) { + prev.data[0] += data[0]; + if (instruction != 'h' && instruction != 'v') { + prev.data[1] += data[1]; + } + prev.coords = item.coords; + path[index] = prev; + return false; + } + + // convert curves into smooth shorthands + if (params.curveSmoothShorthands && prev.instruction) { + + // curveto + if (instruction === 'c') { + + // c + c → c + s + if ( + prev.instruction === 'c' && + data[0] === -(prev.data[2] - prev.data[4]) && + data[1] === -(prev.data[3] - prev.data[5]) + ) { + instruction = 's'; + data = data.slice(2); + } + + // s + c → s + s + else if ( + prev.instruction === 's' && + data[0] === -(prev.data[0] - prev.data[2]) && + data[1] === -(prev.data[1] - prev.data[3]) + ) { + instruction = 's'; + data = data.slice(2); + } + + // [^cs] + c → [^cs] + s + else if ( + 'cs'.indexOf(prev.instruction) === -1 && + data[0] === 0 && + data[1] === 0 + ) { + instruction = 's'; + data = data.slice(2); + } + + } + + // quadratic Bézier curveto + else if (instruction === 'q') { + + // q + q → q + t + if ( + prev.instruction === 'q' && + data[0] === (prev.data[2] - prev.data[0]) && + data[1] === (prev.data[3] - prev.data[1]) + ) { + instruction = 't'; + data = data.slice(2); + } + + // t + q → t + t + else if ( + prev.instruction === 't' && + data[2] === prev.data[0] && + data[3] === prev.data[1] + ) { + instruction = 't'; + data = data.slice(2); + } + + } + + } + + // remove useless non-first path segments + if (params.removeUseless && !hasStrokeLinecap) { + + // l 0,0 / h 0 / v 0 / q 0,0 0,0 / t 0,0 / c 0,0 0,0 0,0 / s 0,0 0,0 + if ( + ( + 'lhvqtcs'.indexOf(instruction) > -1 + ) && + data.every(function(i) { return i === 0; }) + ) { + path[index] = prev; + return false; + } + + // a 25,25 -30 0,1 0,0 + if ( + instruction === 'a' && + data[5] === 0 && + data[6] === 0 + ) { + path[index] = prev; + return false; + } + + } + + item.instruction = instruction; + item.data = data; + + prev = item; + + } else { + + // z resets coordinates + relSubpoint[0] = pathBase[0]; + relSubpoint[1] = pathBase[1]; + if (prev.instruction == 'z') return false; + prev = item; + + } + + return true; + + }); + + return path; + +} + +/** + * Writes data in shortest form using absolute or relative coordinates. + * + * @param {Array} data input path data + * @return {Boolean} output + */ +function convertToMixed(path, params) { + + var prev = path[0]; + + path = path.filter(function(item, index) { + + if (index == 0) return true; + if (!item.data) { + prev = item; + return true; + } + + var instruction = item.instruction, + data = item.data, + adata = data && data.slice(0); + + if ('mltqsc'.indexOf(instruction) > -1) { + for (var i = adata.length; i--;) { + adata[i] += item.base[i % 2]; + } + } else if (instruction == 'h') { + adata[0] += item.base[0]; + } else if (instruction == 'v') { + adata[0] += item.base[1]; + } else if (instruction == 'a') { + adata[5] += item.base[0]; + adata[6] += item.base[1]; + } + + roundData(adata); + + var absoluteDataStr = cleanupOutData(adata, params), + relativeDataStr = cleanupOutData(data, params); + + // Convert to absolute coordinates if it's shorter or forceAbsolutePath is true. + // v-20 -> V0 + // Don't convert if it fits following previous instruction. + // l20 30-10-50 instead of l20 30L20 30 + if ( + params.forceAbsolutePath || ( + absoluteDataStr.length < relativeDataStr.length && + !( + params.negativeExtraSpace && + instruction == prev.instruction && + prev.instruction.charCodeAt(0) > 96 && + absoluteDataStr.length == relativeDataStr.length - 1 && + (data[0] < 0 || /^0\./.test(data[0]) && prev.data[prev.data.length - 1] % 1) + )) + ) { + item.instruction = instruction.toUpperCase(); + item.data = adata; + } + + prev = item; + + return true; + + }); + + return path; + +} + +/** + * Checks if curve is convex. Control points of such a curve must form + * a convex quadrilateral with diagonals crosspoint inside of it. + * + * @param {Array} data input path data + * @return {Boolean} output + */ +function isConvex(data) { + + var center = getIntersection([0, 0, data[2], data[3], data[0], data[1], data[4], data[5]]); + + return center && + (data[2] < center[0] == center[0] < 0) && + (data[3] < center[1] == center[1] < 0) && + (data[4] < center[0] == center[0] < data[0]) && + (data[5] < center[1] == center[1] < data[1]); + +} + +/** + * Computes lines equations by two points and returns their intersection point. + * + * @param {Array} coords 8 numbers for 4 pairs of coordinates (x,y) + * @return {Array|undefined} output coordinate of lines' crosspoint + */ +function getIntersection(coords) { + + // Prev line equation parameters. + var a1 = coords[1] - coords[3], // y1 - y2 + b1 = coords[2] - coords[0], // x2 - x1 + c1 = coords[0] * coords[3] - coords[2] * coords[1], // x1 * y2 - x2 * y1 + + // Next line equation parameters + a2 = coords[5] - coords[7], // y1 - y2 + b2 = coords[6] - coords[4], // x2 - x1 + c2 = coords[4] * coords[7] - coords[5] * coords[6], // x1 * y2 - x2 * y1 + denom = (a1 * b2 - a2 * b1); + + if (!denom) return; // parallel lines havn't an intersection + + var cross = [ + (b1 * c2 - b2 * c1) / denom, + (a1 * c2 - a2 * c1) / -denom + ]; + if ( + !isNaN(cross[0]) && !isNaN(cross[1]) && + isFinite(cross[0]) && isFinite(cross[1]) + ) { + return cross; + } + +} + +/** + * Decrease accuracy of floating-point numbers + * in path data keeping a specified number of decimals. + * Smart rounds values like 2.3491 to 2.35 instead of 2.349. + * Doesn't apply "smartness" if the number precision fits already. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function strongRound(data) { + for (var i = data.length; i-- > 0;) { + if (data[i].toFixed(precision) != data[i]) { + var rounded = +data[i].toFixed(precision - 1); + data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= error ? + +data[i].toFixed(precision) : + rounded; + } + } + return data; +} + +/** + * Simple rounding function if precision is 0. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function round(data) { + for (var i = data.length; i-- > 0;) { + data[i] = Math.round(data[i]); + } + return data; +} + +/** + * Checks if a curve is a straight line by measuring distance + * from middle points to the line formed by end points. + * + * @param {Array} xs array of curve points x-coordinates + * @param {Array} ys array of curve points y-coordinates + * @return {Boolean} + */ + +function isCurveStraightLine(data) { + + // Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points. + var i = data.length - 2, + a = -data[i + 1], // y1 − y2 (y1 = 0) + b = data[i], // x2 − x1 (x1 = 0) + d = 1 / (a * a + b * b); // same part for all points + + if (i <= 1 || !isFinite(d)) return false; // curve that ends at start point isn't the case + + // Distance from point (x0, y0) to the line is sqrt((c − a·x0 − b·y0)² / (a² + b²)) + while ((i -= 2) >= 0) { + if (Math.sqrt(Math.pow(a * data[i] + b * data[i + 1], 2) * d) > error) + return false; + } + + return true; + +} + +/** + * Converts next curve from shorthand to full form using the current curve data. + * + * @param {Object} item curve to convert + * @param {Array} data current curve data + */ + +function makeLonghand(item, data) { + switch (item.instruction) { + case 's': item.instruction = 'c'; break; + case 't': item.instruction = 'q'; break; + } + item.data.unshift(data[data.length - 2] - data[data.length - 4], data[data.length - 1] - data[data.length - 3]); + return item; +} + +/** + * Returns distance between two points + * + * @param {Array} point1 first point coordinates + * @param {Array} point2 second point coordinates + * @return {Number} distance + */ + +function getDistance(point1, point2) { + return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]); +} + +/** + * Returns coordinates of the curve point corresponding to the certain t + * a·(1 - t)³·p1 + b·(1 - t)²·t·p2 + c·(1 - t)·t²·p3 + d·t³·p4, + * where pN are control points and p1 is zero due to relative coordinates. + * + * @param {Array} curve array of curve points coordinates + * @param {Number} t parametric position from 0 to 1 + * @return {Array} Point coordinates + */ + +function getCubicBezierPoint(curve, t) { + var sqrT = t * t, + cubT = sqrT * t, + mt = 1 - t, + sqrMt = mt * mt; + + return [ + 3 * sqrMt * t * curve[0] + 3 * mt * sqrT * curve[2] + cubT * curve[4], + 3 * sqrMt * t * curve[1] + 3 * mt * sqrT * curve[3] + cubT * curve[5] + ]; +} + +/** + * Finds circle by 3 points of the curve and checks if the curve fits the found circle. + * + * @param {Array} curve + * @return {Object|undefined} circle + */ + +function findCircle(curve) { + var midPoint = getCubicBezierPoint(curve, 1/2), + m1 = [midPoint[0] / 2, midPoint[1] / 2], + m2 = [(midPoint[0] + curve[4]) / 2, (midPoint[1] + curve[5]) / 2], + center = getIntersection([ + m1[0], m1[1], + m1[0] + m1[1], m1[1] - m1[0], + m2[0], m2[1], + m2[0] + (m2[1] - midPoint[1]), m2[1] - (m2[0] - midPoint[0]) + ]), + radius = center && getDistance([0, 0], center), + tolerance = Math.min(arcThreshold * error, arcTolerance * radius / 100); + + if (center && radius < 1e15 && + [1/4, 3/4].every(function(point) { + return Math.abs(getDistance(getCubicBezierPoint(curve, point), center) - radius) <= tolerance; + })) + return { center: center, radius: radius}; +} + +/** + * Checks if a curve fits the given circle. + * + * @param {Object} circle + * @param {Array} curve + * @return {Boolean} + */ + +function isArc(curve, circle) { + var tolerance = Math.min(arcThreshold * error, arcTolerance * circle.radius / 100); + + return [0, 1/4, 1/2, 3/4, 1].every(function(point) { + return Math.abs(getDistance(getCubicBezierPoint(curve, point), circle.center) - circle.radius) <= tolerance; + }); +} + +/** + * Checks if a previous curve fits the given circle. + * + * @param {Object} circle + * @param {Array} curve + * @return {Boolean} + */ + +function isArcPrev(curve, circle) { + return isArc(curve, { + center: [circle.center[0] + curve[4], circle.center[1] + curve[5]], + radius: circle.radius + }); +} + +/** + * Finds angle of a curve fitting the given arc. + + * @param {Array} curve + * @param {Object} relCircle + * @return {Number} angle + */ + +function findArcAngle(curve, relCircle) { + var x1 = -relCircle.center[0], + y1 = -relCircle.center[1], + x2 = curve[4] - relCircle.center[0], + y2 = curve[5] - relCircle.center[1]; + + return Math.acos( + (x1 * x2 + y1 * y2) / + Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) + ); +} + +/** + * Converts given path data to string. + * + * @param {Object} params + * @param {Array} pathData + * @return {String} + */ + +function data2Path(params, pathData) { + return pathData.reduce(function(pathString, item) { + var strData = ''; + if (item.data) { + strData = cleanupOutData(roundData(item.data.slice()), params); + } + return pathString + item.instruction + strData; + }, ''); +} diff --git a/vendor/svgclean/src/svgclean/plugins/convertShapeToPath.js b/vendor/svgclean/src/svgclean/plugins/convertShapeToPath.js new file mode 100644 index 000000000..907246145 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertShapeToPath.js @@ -0,0 +1,149 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts basic shapes to more compact path form'; + +exports.params = { + convertArcs: false +}; + +var none = { value: 0 }, + regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + +/** + * Converts basic shape to more compact path. + * It also allows further optimizations like + * combining paths with similar attributes. + * + * @see http://www.w3.org/TR/SVG/shapes.html + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Lev Solntsev + */ +exports.fn = function(item, params) { + var convertArcs = params && params.convertArcs; + + if ( + item.isElem('rect') && + item.hasAttr('width') && + item.hasAttr('height') && + !item.hasAttr('rx') && + !item.hasAttr('ry') + ) { + + var x = +(item.attr('x') || none).value, + y = +(item.attr('y') || none).value, + width = +item.attr('width').value, + height = +item.attr('height').value; + + // Values like '100%' compute to NaN, thus running after + // cleanupNumericValues when 'px' units has already been removed. + // TODO: Calculate sizes from % and non-px units if possible. + if (isNaN(x - y + width - height)) return; + + var pathData = + 'M' + x + ' ' + y + + 'H' + (x + width) + + 'V' + (y + height) + + 'H' + x + + 'z'; + + item.addAttr({ + name: 'd', + value: pathData, + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr(['x', 'y', 'width', 'height']); + + } else if (item.isElem('line')) { + + var x1 = +(item.attr('x1') || none).value, + y1 = +(item.attr('y1') || none).value, + x2 = +(item.attr('x2') || none).value, + y2 = +(item.attr('y2') || none).value; + if (isNaN(x1 - y1 + x2 - y2)) return; + + item.addAttr({ + name: 'd', + value: 'M' + x1 + ' ' + y1 + 'L' + x2 + ' ' + y2, + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr(['x1', 'y1', 'x2', 'y2']); + + } else if (( + item.isElem('polyline') || + item.isElem('polygon') + ) && + item.hasAttr('points') + ) { + + var coords = (item.attr('points').value.match(regNumber) || []).map(Number); + if (coords.length < 4) return false; + + item.addAttr({ + name: 'd', + value: 'M' + coords.slice(0,2).join(' ') + + 'L' + coords.slice(2).join(' ') + + (item.isElem('polygon') ? 'z' : ''), + prefix: '', + local: 'd' + }); + + item.renameElem('path') + .removeAttr('points'); + } else if (item.isElem('circle') && convertArcs) { + + var cx = +(item.attr('cx') || none).value; + var cy = +(item.attr('cy') || none).value; + var r = +(item.attr('r') || none).value; + if (isNaN(cx - cy + r)) { + return; + } + var cPathData = + 'M' + cx + ' ' + (cy - r) + + 'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy + r) + + 'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy - r) + + 'Z'; + item.addAttr({ + name: 'd', + value: cPathData, + prefix: '', + local: 'd', + }); + item.renameElem('path').removeAttr(['cx', 'cy', 'r']); + + } else if (item.isElem('ellipse') && convertArcs) { + + var ecx = +(item.attr('cx') || none).value; + var ecy = +(item.attr('cy') || none).value; + var rx = +(item.attr('rx') || none).value; + var ry = +(item.attr('ry') || none).value; + if (isNaN(ecx - ecy + rx - ry)) { + return; + } + var ePathData = + 'M' + ecx + ' ' + (ecy - ry) + + 'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy + ry) + + 'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy - ry) + + 'Z'; + item.addAttr({ + name: 'd', + value: ePathData, + prefix: '', + local: 'd', + }); + item.renameElem('path').removeAttr(['cx', 'cy', 'rx', 'ry']); + } +}; diff --git a/vendor/svgclean/src/svgclean/plugins/convertStyleToAttrs.js b/vendor/svgclean/src/svgclean/plugins/convertStyleToAttrs.js new file mode 100644 index 000000000..29d69a777 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertStyleToAttrs.js @@ -0,0 +1,125 @@ +/* jshint quotmark: false */ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'converts style to attributes'; + +exports.params = { + keepImportant: false +}; + +var stylingProps = require('./_collections').attrsGroups.presentation, + rEscape = '\\\\(?:[0-9a-f]{1,6}\\s?|\\r\\n|.)', // Like \" or \2051. Code points consume one space. + rAttr = '\\s*(' + g('[^:;\\\\]', rEscape) + '*?)\\s*', // attribute name like ‘fill’ + rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth' + rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth" + rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'), + + // Parentheses, E.g.: url(data:image/png;base64,iVBO...). + // ':' and ';' inside of it should be threated as is. (Just like in strings.) + rParenthesis = '\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)', + + // The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input. + rValue = '\\s*(' + g('[^!\'"();\\\\]+?', rEscape, rSingleQuotes, rQuotes, rParenthesis, '[^;]*?') + '*?' + ')', + + // End of declaration. Spaces outside of capturing groups help to do natural trimming. + rDeclEnd = '\\s*(?:;\\s*|$)', + + // Important rule + rImportant = '(\\s*!important(?![-(\w]))?', + + // Final RegExp to parse CSS declarations. + regDeclarationBlock = new RegExp(rAttr + ':' + rValue + rImportant + rDeclEnd, 'ig'), + + // Comments expression. Honors escape sequences and strings. + regStripComments = new RegExp(g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'), 'ig'); + +/** + * Convert style in attributes. Cleanups comments and illegal declarations (without colon) as a side effect. + * + * @example + * <g style="fill:#000; color: #fff;"> + * ⬇ + * <g fill="#000" color="#fff"> + * + * @example + * <g style="fill:#000; color: #fff; -webkit-blah: blah"> + * ⬇ + * <g fill="#000" color="#fff" style="-webkit-blah: blah"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + /* jshint boss: true */ + + if (item.elem && item.hasAttr('style')) { + // ['opacity: 1', 'color: #000'] + var styleValue = item.attr('style').value, + styles = [], + attrs = {}; + + // Strip CSS comments preserving escape sequences and strings. + styleValue = styleValue.replace(regStripComments, function(match) { + return match[0] == '/' ? '' : + match[0] == '\\' && /[-g-z]/i.test(match[1]) ? match[1] : match; + }); + + regDeclarationBlock.lastIndex = 0; + for (var rule; rule = regDeclarationBlock.exec(styleValue);) { + if (!params.keepImportant || !rule[3]) { + styles.push([rule[1], rule[2]]); + } + } + + if (styles.length) { + + styles = styles.filter(function(style) { + if (style[0]) { + var prop = style[0].toLowerCase(), + val = style[1]; + + if (rQuotedString.test(val)) { + val = val.slice(1, -1); + } + + if (stylingProps.indexOf(prop) > -1) { + + attrs[prop] = { + name: prop, + value: val, + local: prop, + prefix: '' + }; + + return false; + } + } + + return true; + }); + + Object.assign(item.attrs, attrs); + + if (styles.length) { + item.attr('style').value = styles + .map(function(declaration) { return declaration.join(':') }) + .join(';'); + } else { + item.removeAttr('style'); + } + + } + + } + +}; + +function g() { + return '(?:' + Array.prototype.join.call(arguments, '|') + ')'; +} diff --git a/vendor/svgclean/src/svgclean/plugins/convertTransform.js b/vendor/svgclean/src/svgclean/plugins/convertTransform.js new file mode 100644 index 000000000..5ed576ff0 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/convertTransform.js @@ -0,0 +1,363 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'collapses multiple transformations and optimizes it'; + +exports.params = { + convertToShorts: true, + // degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default + floatPrecision: 3, + transformPrecision: 5, + matrixToTransform: true, + shortTranslate: true, + shortScale: true, + shortRotate: true, + removeUseless: true, + collapseIntoOne: true, + leadingZero: true, + negativeExtraSpace: false +}; + +var cleanupOutData = require('../tools').cleanupOutData, + transform2js = require('./_transforms.js').transform2js, + transformsMultiply = require('./_transforms.js').transformsMultiply, + matrixToTransform = require('./_transforms.js').matrixToTransform, + degRound, + floatRound, + transformRound; + +/** + * Convert matrices to the short aliases, + * convert long translate, scale or rotate transform notations to the shorts ones, + * convert transforms to the matrices and multiply them all into one, + * remove useless transforms. + * + * @see http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.elem) { + + // transform + if (item.hasAttr('transform')) { + convertTransform(item, 'transform', params); + } + + // gradientTransform + if (item.hasAttr('gradientTransform')) { + convertTransform(item, 'gradientTransform', params); + } + + // patternTransform + if (item.hasAttr('patternTransform')) { + convertTransform(item, 'patternTransform', params); + } + + } + +}; + +/** + * Main function. + * + * @param {Object} item input item + * @param {String} attrName attribute name + * @param {Object} params plugin params + */ +function convertTransform(item, attrName, params) { + var data = transform2js(item.attr(attrName).value); + params = definePrecision(data, params); + + if (params.collapseIntoOne && data.length > 1) { + data = [transformsMultiply(data)]; + } + + if (params.convertToShorts) { + data = convertToShorts(data, params); + } else { + data.forEach(roundTransform); + } + + if (params.removeUseless) { + data = removeUseless(data); + } + + if (data.length) { + item.attr(attrName).value = js2transform(data, params); + } else { + item.removeAttr(attrName); + } +} + +/** + * Defines precision to work with certain parts. + * transformPrecision - for scale and four first matrix parameters (needs a better precision due to multiplying), + * floatPrecision - for translate including two last matrix and rotate parameters, + * degPrecision - for rotate and skew. By default it's equal to (rougly) + * transformPrecision - 2 or floatPrecision whichever is lower. Can be set in params. + * + * @param {Array} transforms input array + * @param {Object} params plugin params + * @return {Array} output array + */ +function definePrecision(data, params) { + /* jshint validthis: true */ + var matrixData = data.reduce(getMatrixData, []), + significantDigits = params.transformPrecision; + + // Clone params so it don't affect other elements transformations. + params = Object.assign({}, params); + + // Limit transform precision with matrix one. Calculating with larger precision doesn't add any value. + if (matrixData.length) { + params.transformPrecision = Math.min(params.transformPrecision, + Math.max.apply(Math, matrixData.map(floatDigits)) || params.transformPrecision); + + significantDigits = Math.max.apply(Math, matrixData.map(function(n) { + return String(n).replace(/\D+/g, '').length; // Number of digits in a number. 123.45 → 5 + })); + } + // No sense in angle precision more then number of significant digits in matrix. + if (!('degPrecision' in params)) { + params.degPrecision = Math.max(0, Math.min(params.floatPrecision, significantDigits - 2)); + } + + floatRound = params.floatPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.floatPrecision) : + round; + degRound = params.degPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.degPrecision) : + round; + transformRound = params.transformPrecision >= 1 && params.floatPrecision < 20 ? + smartRound.bind(this, params.transformPrecision) : + round; + + return params; +} + +/** + * Gathers four first matrix parameters. + * + * @param {Array} a array of data + * @param {Object} transform + * @return {Array} output array + */ +function getMatrixData(a, b) { + return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a; +} + +/** + * Returns number of digits after the point. 0.125 → 3 + */ +function floatDigits(n) { + return (n = String(n)).slice(n.indexOf('.')).length - 1; +} + +/** + * Convert transforms to the shorthand alternatives. + * + * @param {Array} transforms input array + * @param {Object} params plugin params + * @return {Array} output array + */ +function convertToShorts(transforms, params) { + + for(var i = 0; i < transforms.length; i++) { + + var transform = transforms[i]; + + // convert matrix to the short aliases + if ( + params.matrixToTransform && + transform.name === 'matrix' + ) { + var decomposed = matrixToTransform(transform, params); + if (decomposed != transform && + js2transform(decomposed, params).length <= js2transform([transform], params).length) { + + transforms.splice.apply(transforms, [i, 1].concat(decomposed)); + } + transform = transforms[i]; + } + + // fixed-point numbers + // 12.754997 → 12.755 + roundTransform(transform); + + // convert long translate transform notation to the shorts one + // translate(10 0) → translate(10) + if ( + params.shortTranslate && + transform.name === 'translate' && + transform.data.length === 2 && + !transform.data[1] + ) { + transform.data.pop(); + } + + // convert long scale transform notation to the shorts one + // scale(2 2) → scale(2) + if ( + params.shortScale && + transform.name === 'scale' && + transform.data.length === 2 && + transform.data[0] === transform.data[1] + ) { + transform.data.pop(); + } + + // convert long rotate transform notation to the short one + // translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy) + if ( + params.shortRotate && + transforms[i - 2] && + transforms[i - 2].name === 'translate' && + transforms[i - 1].name === 'rotate' && + transforms[i].name === 'translate' && + transforms[i - 2].data[0] === -transforms[i].data[0] && + transforms[i - 2].data[1] === -transforms[i].data[1] + ) { + transforms.splice(i - 2, 3, { + name: 'rotate', + data: [ + transforms[i - 1].data[0], + transforms[i - 2].data[0], + transforms[i - 2].data[1] + ] + }); + + // splice compensation + i -= 2; + + transform = transforms[i]; + } + + } + + return transforms; + +} + +/** + * Remove useless transforms. + * + * @param {Array} transforms input array + * @return {Array} output array + */ +function removeUseless(transforms) { + + return transforms.filter(function(transform) { + + // translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0) + if ( + ['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 && + (transform.data.length == 1 || transform.name == 'rotate') && + !transform.data[0] || + + // translate(0, 0) + transform.name == 'translate' && + !transform.data[0] && + !transform.data[1] || + + // scale(1) + transform.name == 'scale' && + transform.data[0] == 1 && + (transform.data.length < 2 || transform.data[1] == 1) || + + // matrix(1 0 0 1 0 0) + transform.name == 'matrix' && + transform.data[0] == 1 && + transform.data[3] == 1 && + !(transform.data[1] || transform.data[2] || transform.data[4] || transform.data[5]) + ) { + return false; + } + + return true; + + }); + +} + +/** + * Convert transforms JS representation to string. + * + * @param {Array} transformJS JS representation array + * @param {Object} params plugin params + * @return {String} output string + */ +function js2transform(transformJS, params) { + + var transformString = ''; + + // collect output value string + transformJS.forEach(function(transform) { + roundTransform(transform); + transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')'; + }); + + return transformString; + +} + +function roundTransform(transform) { + switch (transform.name) { + case 'translate': + transform.data = floatRound(transform.data); + break; + case 'rotate': + transform.data = degRound(transform.data.slice(0, 1)).concat(floatRound(transform.data.slice(1))); + break; + case 'skewX': + case 'skewY': + transform.data = degRound(transform.data); + break; + case 'scale': + transform.data = transformRound(transform.data); + break; + case 'matrix': + transform.data = transformRound(transform.data.slice(0, 4)).concat(floatRound(transform.data.slice(4))); + break; + } + return transform; +} + +/** + * Rounds numbers in array. + * + * @param {Array} data input data array + * @return {Array} output data array + */ +function round(data) { + return data.map(Math.round); +} + +/** + * Decrease accuracy of floating-point numbers + * in transforms keeping a specified number of decimals. + * Smart rounds values like 2.349 to 2.35. + * + * @param {Number} fixed number of decimals + * @param {Array} data input data array + * @return {Array} output data array + */ +function smartRound(precision, data) { + for (var i = data.length, tolerance = +Math.pow(.1, precision).toFixed(precision); i--;) { + if (data[i].toFixed(precision) != data[i]) { + var rounded = +data[i].toFixed(precision - 1); + data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance ? + +data[i].toFixed(precision) : + rounded; + } + } + return data; +} diff --git a/vendor/svgclean/src/svgclean/plugins/inlineStyles.js b/vendor/svgclean/src/svgclean/plugins/inlineStyles.js new file mode 100644 index 000000000..009c532ef --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/inlineStyles.js @@ -0,0 +1,245 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.params = { + onlyMatchedOnce: true, + removeMatchedSelectors: true, + useMqs: ['', 'screen'], + usePseudos: [''] +}; + +exports.description = 'inline styles (additional options)'; + + +var csstree = require('css-tree'), + cssTools = require('../css-tools'); + +/** + * Moves + merges styles from style elements to element styles + * + * Options + * onlyMatchedOnce (default: true) + * inline only selectors that match once + * + * removeMatchedSelectors (default: true) + * clean up matched selectors, + * leave selectors that hadn't matched + * + * useMqs (default: ['', 'screen']) + * what media queries to be used + * empty string element for styles outside media queries + * + * usePseudos (default: ['']) + * what pseudo-classes/-elements to be used + * empty string element for all non-pseudo-classes and/or -elements + * + * @param {Object} document document element + * @param {Object} opts plugin params + * + * @author strarsis <strarsis@gmail.com> + */ +exports.fn = function(document, opts) { + + // collect <style/>s + var styleEls = document.querySelectorAll('style'); + + //no <styles/>s, nothing to do + if (styleEls === null) { + return document; + } + + var styles = [], + selectors = []; + + for (var styleEl of styleEls) { + if (styleEl.isEmpty() || styleEl.closestElem('foreignObject')) { + // skip empty <style/>s or <foreignObject> content. + continue; + } + + var cssStr = cssTools.getCssStr(styleEl); + + // collect <style/>s and their css ast + var cssAst = {}; + try { + cssAst = csstree.parse(cssStr, { + parseValue: false, + parseCustomProperty: false + }); + } catch (parseError) { + // console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError); + continue; + } + + styles.push({ + styleEl: styleEl, + cssAst: cssAst + }); + + selectors = selectors.concat(cssTools.flattenToSelectors(cssAst)); + } + + + // filter for mediaqueries to be used or without any mediaquery + var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs); + + + // filter for pseudo elements to be used + var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos); + + // remove PseudoClass from its SimpleSelector for proper matching + cssTools.cleanPseudos(selectorsPseudo); + + + // stable sort selectors + var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse(); + + + var selector, + selectedEl; + + // match selectors + for (selector of sortedSelectors) { + var selectorStr = csstree.generate(selector.item.data), + selectedEls = null; + + try { + selectedEls = document.querySelectorAll(selectorStr); + } catch (selectError) { + if (selectError.constructor === SyntaxError) { + // console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError); + continue; + } + throw selectError; + } + + if (selectedEls === null) { + // nothing selected + continue; + } + + selector.selectedEls = selectedEls; + } + + + // apply <style/> styles to matched elements + for (selector of sortedSelectors) { + if(!selector.selectedEls) { + continue; + } + + if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) { + // skip selectors that match more than once if option onlyMatchedOnce is enabled + continue; + } + + // apply <style/> to matched elements + for (selectedEl of selector.selectedEls) { + if (selector.rule === null) { + continue; + } + + // merge declarations + csstree.walk(selector.rule, {visit: 'Declaration', enter: function(styleCsstreeDeclaration) { + + // existing inline styles have higher priority + // no inline styles, external styles, external styles used + // inline styles, external styles same priority as inline styles, inline styles used + // inline styles, external styles higher priority than inline styles, external styles used + var styleDeclaration = cssTools.csstreeToStyleDeclaration(styleCsstreeDeclaration); + if (selectedEl.style.getPropertyValue(styleDeclaration.name) !== null && + selectedEl.style.getPropertyPriority(styleDeclaration.name) >= styleDeclaration.priority) { + return; + } + selectedEl.style.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); + }}); + } + + if (opts.removeMatchedSelectors && selector.selectedEls !== null && selector.selectedEls.length > 0) { + // clean up matching simple selectors if option removeMatchedSelectors is enabled + selector.rule.prelude.children.remove(selector.item); + } + } + + + if (!opts.removeMatchedSelectors) { + return document; // no further processing required + } + + + // clean up matched class + ID attribute values + for (selector of sortedSelectors) { + if(!selector.selectedEls) { + continue; + } + + if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) { + // skip selectors that match more than once if option onlyMatchedOnce is enabled + continue; + } + + for (selectedEl of selector.selectedEls) { + // class + var firstSubSelector = selector.item.data.children.first(); + if(firstSubSelector.type === 'ClassSelector') { + selectedEl.class.remove(firstSubSelector.name); + } + // clean up now empty class attributes + if(typeof selectedEl.class.item(0) === 'undefined') { + selectedEl.removeAttr('class'); + } + + // ID + if(firstSubSelector.type === 'IdSelector') { + selectedEl.removeAttr('id', firstSubSelector.name); + } + } + } + + + // clean up now empty elements + for (var style of styles) { + csstree.walk(style.cssAst, {visit: 'Rule', enter: function(node, item, list) { + // clean up <style/> atrules without any rulesets left + if (node.type === 'Atrule' && + // only Atrules containing rulesets + node.block !== null && + node.block.children.isEmpty()) { + list.remove(item); + return; + } + + // clean up <style/> rulesets without any css selectors left + if (node.type === 'Rule' && + node.prelude.children.isEmpty()) { + list.remove(item); + } + }}); + + + if (style.cssAst.children.isEmpty()) { + // clean up now emtpy <style/>s + var styleParentEl = style.styleEl.parentNode; + styleParentEl.spliceContent(styleParentEl.content.indexOf(style.styleEl), 1); + + if (styleParentEl.elem === 'defs' && + styleParentEl.content.length === 0) { + // also clean up now empty <def/>s + var defsParentEl = styleParentEl.parentNode; + defsParentEl.spliceContent(defsParentEl.content.indexOf(styleParentEl), 1); + } + + continue; + } + + + // update existing, left over <style>s + cssTools.setCssStr(style.styleEl, csstree.generate(style.cssAst)); + } + + + return document; +}; diff --git a/vendor/svgclean/src/svgclean/plugins/mergePaths.js b/vendor/svgclean/src/svgclean/plugins/mergePaths.js new file mode 100644 index 000000000..6a18996bf --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/mergePaths.js @@ -0,0 +1,73 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'merges multiple paths in one if possible'; + +exports.params = { + collapseRepeated: true, + force: false, + leadingZero: true, + negativeExtraSpace: true, + noSpaceAfterFlags: true +}; + +var path2js = require('./_path.js').path2js, + js2path = require('./_path.js').js2path, + intersects = require('./_path.js').intersects; + +/** + * Merge multiple Paths into one. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich, Lev Solntsev + */ +exports.fn = function(item, params) { + + if (!item.isElem() || item.isEmpty()) return; + + var prevContentItem = null, + prevContentItemKeys = null; + + item.content = item.content.filter(function(contentItem) { + + if (prevContentItem && + prevContentItem.isElem('path') && + prevContentItem.isEmpty() && + prevContentItem.hasAttr('d') && + contentItem.isElem('path') && + contentItem.isEmpty() && + contentItem.hasAttr('d') + ) { + + if (!prevContentItemKeys) { + prevContentItemKeys = Object.keys(prevContentItem.attrs); + } + + var contentItemAttrs = Object.keys(contentItem.attrs), + equalData = prevContentItemKeys.length == contentItemAttrs.length && + contentItemAttrs.every(function(key) { + return key == 'd' || + prevContentItem.hasAttr(key) && + prevContentItem.attr(key).value == contentItem.attr(key).value; + }), + prevPathJS = path2js(prevContentItem), + curPathJS = path2js(contentItem); + + if (equalData && (params.force || !intersects(prevPathJS, curPathJS))) { + js2path(prevContentItem, prevPathJS.concat(curPathJS), params); + return false; + } + } + + prevContentItem = contentItem; + prevContentItemKeys = null; + return true; + + }); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/minifyStyles.js b/vendor/svgclean/src/svgclean/plugins/minifyStyles.js new file mode 100755 index 000000000..d240900ed --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/minifyStyles.js @@ -0,0 +1,160 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'minifies styles and removes unused styles based on usage data'; + +exports.params = { + // ... CSSO options goes here + + // additional + usage: { + force: false, // force to use usage data even if it unsafe (document contains <script> or on* attributes) + ids: true, + classes: true, + tags: true + } +}; + +var csso = require('csso'); + +/** + * Minifies styles (<style> element + style attribute) using CSSO + * + * @author strarsis <strarsis@gmail.com> + */ +exports.fn = function(ast, options) { + options = options || {}; + + var minifyOptionsForStylesheet = cloneObject(options); + var minifyOptionsForAttribute = cloneObject(options); + var elems = findStyleElems(ast); + + minifyOptionsForStylesheet.usage = collectUsageData(ast, options); + minifyOptionsForAttribute.usage = null; + + elems.forEach(function(elem) { + if (elem.isElem('style')) { + // <style> element + var styleCss = elem.content[0].text || elem.content[0].cdata || []; + var DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text'; + + elem.content[0][DATA] = csso.minify(styleCss, minifyOptionsForStylesheet).css; + } else { + // style attribute + var elemStyle = elem.attr('style').value; + + elem.attr('style').value = csso.minifyBlock(elemStyle, minifyOptionsForAttribute).css; + } + }); + + return ast; +}; + +function cloneObject(obj) { + var result = {}; + + for (var key in obj) { + result[key] = obj[key]; + } + + return result; +} + +function findStyleElems(ast) { + + function walk(items, styles) { + for (var i = 0; i < items.content.length; i++) { + var item = items.content[i]; + + // go deeper + if (item.content) { + walk(item, styles); + } + + if (item.isElem('style') && !item.isEmpty()) { + styles.push(item); + } else if (item.isElem() && item.hasAttr('style')) { + styles.push(item); + } + } + + return styles; + } + + return walk(ast, []); +} + +function shouldFilter(options, name) { + if ('usage' in options === false) { + return true; + } + + if (options.usage && name in options.usage === false) { + return true; + } + + return Boolean(options.usage && options.usage[name]); +} + +function collectUsageData(ast, options) { + + function walk(items, usageData) { + for (var i = 0; i < items.content.length; i++) { + var item = items.content[i]; + + // go deeper + if (item.content) { + walk(item, usageData); + } + + if (item.isElem('script')) { + safe = false; + } + + if (item.isElem()) { + usageData.tags[item.elem] = true; + + if (item.hasAttr('id')) { + usageData.ids[item.attr('id').value] = true; + } + + if (item.hasAttr('class')) { + item.attr('class').value.replace(/^\s+|\s+$/g, '').split(/\s+/).forEach(function(className) { + usageData.classes[className] = true; + }); + } + + if (item.attrs && Object.keys(item.attrs).some(function(name) { return /^on/i.test(name); })) { + safe = false; + } + } + } + + return usageData; + } + + var safe = true; + var usageData = {}; + var hasData = false; + var rawData = walk(ast, { + ids: Object.create(null), + classes: Object.create(null), + tags: Object.create(null) + }); + + if (!safe && options.usage && options.usage.force) { + safe = true; + } + + for (var key in rawData) { + if (shouldFilter(options, key)) { + usageData[key] = Object.keys(rawData[key]); + hasData = true; + } + } + + return safe && hasData ? usageData : null; +} diff --git a/vendor/svgclean/src/svgclean/plugins/moveElemsAttrsToGroup.js b/vendor/svgclean/src/svgclean/plugins/moveElemsAttrsToGroup.js new file mode 100644 index 000000000..0f3b65c70 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/moveElemsAttrsToGroup.js @@ -0,0 +1,126 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'moves elements attributes to the existing group wrapper'; + +var inheritableAttrs = require('./_collections').inheritableAttrs, + pathElems = require('./_collections.js').pathElems; + +/** + * Collapse content's intersected and inheritable + * attributes to the existing group wrapper. + * + * @example + * <g attr1="val1"> + * <g attr2="val2"> + * text + * </g> + * <circle attr2="val2" attr3="val3"/> + * </g> + * ⬇ + * <g attr1="val1" attr2="val2"> + * <g> + * text + * </g> + * <circle attr3="val3"/> + * </g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) { + + var intersection = {}, + hasTransform = false, + hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'), + intersected = item.content.every(function(inner) { + if (inner.isElem() && inner.hasAttr()) { + // don't mess with possible styles (hack until CSS parsing is implemented) + if (inner.hasAttr('class')) return false; + if (!Object.keys(intersection).length) { + intersection = inner.attrs; + } else { + intersection = intersectInheritableAttrs(intersection, inner.attrs); + + if (!intersection) return false; + } + + return true; + } + }), + allPath = item.content.every(function(inner) { + return inner.isElem(pathElems); + }); + + if (intersected) { + + item.content.forEach(function(g) { + + for (var name in intersection) { + + if (!allPath && !hasClip || name !== 'transform') { + + g.removeAttr(name); + + if (name === 'transform') { + if (!hasTransform) { + if (item.hasAttr('transform')) { + item.attr('transform').value += ' ' + intersection[name].value; + } else { + item.addAttr(intersection[name]); + } + + hasTransform = true; + } + } else { + item.addAttr(intersection[name]); + } + + } + } + + }); + + } + + } + +}; + +/** + * Intersect inheritable attributes. + * + * @param {Object} a first attrs object + * @param {Object} b second attrs object + * + * @return {Object} intersected attrs object + */ +function intersectInheritableAttrs(a, b) { + + var c = {}; + + for (var n in a) { + if ( + b.hasOwnProperty(n) && + inheritableAttrs.indexOf(n) > -1 && + a[n].name === b[n].name && + a[n].value === b[n].value && + a[n].prefix === b[n].prefix && + a[n].local === b[n].local + ) { + c[n] = a[n]; + } + } + + if (!Object.keys(c).length) return false; + + return c; + +} diff --git a/vendor/svgclean/src/svgclean/plugins/moveGroupAttrsToElems.js b/vendor/svgclean/src/svgclean/plugins/moveGroupAttrsToElems.js new file mode 100644 index 000000000..a966f882e --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/moveGroupAttrsToElems.js @@ -0,0 +1,63 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'moves some group attributes to the content elements'; + +var collections = require('./_collections.js'), + pathElems = collections.pathElems.concat(['g', 'text']), + referencesProps = collections.referencesProps; + +/** + * Move group attrs to the content elements. + * + * @example + * <g transform="scale(2)"> + * <path transform="rotate(45)" d="M0,0 L10,20"/> + * <path transform="translate(10, 20)" d="M0,10 L20,30"/> + * </g> + * ⬇ + * <g> + * <path transform="scale(2) rotate(45)" d="M0,0 L10,20"/> + * <path transform="scale(2) translate(10, 20)" d="M0,10 L20,30"/> + * </g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + // move group transform attr to content's pathElems + if ( + item.isElem('g') && + item.hasAttr('transform') && + !item.isEmpty() && + !item.someAttr(function(attr) { + return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url('); + }) && + item.content.every(function(inner) { + return inner.isElem(pathElems) && !inner.hasAttr('id'); + }) + ) { + item.content.forEach(function(inner) { + var attr = item.attr('transform'); + if (inner.hasAttr('transform')) { + inner.attr('transform').value = attr.value + ' ' + inner.attr('transform').value; + } else { + inner.addAttr({ + 'name': attr.name, + 'local': attr.local, + 'prefix': attr.prefix, + 'value': attr.value + }); + } + }); + + item.removeAttr('transform'); + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/prefixIds.js b/vendor/svgclean/src/svgclean/plugins/prefixIds.js new file mode 100755 index 000000000..9aff8bf90 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/prefixIds.js @@ -0,0 +1,274 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.params = { + delim: '__', + prefixIds: true, + prefixClassNames: true, +}; + +exports.description = 'prefix IDs'; + + +var path = require('path'), + csstree = require('css-tree'), + unquote = require('unquote'), + collections = require('./_collections.js'), + referencesProps = collections.referencesProps, + rxId = /^#(.*)$/, // regular expression for matching an ID + extracing its name + addPrefix = null; + + +// Escapes a string for being used as ID +var escapeIdentifierName = function(str) { + return str.replace(/[\. ]/g, '_'); +}; + +// Matches an #ID value, captures the ID name +var matchId = function(urlVal) { + var idUrlMatches = urlVal.match(rxId); + if (idUrlMatches === null) { + return false; + } + return idUrlMatches[1]; +}; + +// Matches an url(...) value, captures the URL +var matchUrl = function(val) { + var urlMatches = /url\((.*?)\)/gi.exec(val); + if (urlMatches === null) { + return false; + } + return urlMatches[1]; +}; + +// Checks if attribute is empty +var attrNotEmpty = function(attr) { + return (attr && attr.value && attr.value.length > 0); +}; + +// prefixes an #ID +var prefixId = function(val) { + var idName = matchId(val); + if (!idName) { + return false; + } + return '#' + addPrefix(idName); +}; + + +// attr.value helper methods + +// prefixes a class attribute value +var addPrefixToClassAttr = function(attr) { + if (!attrNotEmpty(attr)) { + return; + } + + attr.value = attr.value.split(/\s+/).map(addPrefix).join(' '); +}; + +// prefixes an ID attribute value +var addPrefixToIdAttr = function(attr) { + if (!attrNotEmpty(attr)) { + return; + } + + attr.value = addPrefix(attr.value); +}; + +// prefixes a href attribute value +var addPrefixToHrefAttr = function(attr) { + if (!attrNotEmpty(attr)) { + return; + } + + var idPrefixed = prefixId(attr.value); + if (!idPrefixed) { + return; + } + attr.value = idPrefixed; +}; + +// prefixes an URL attribute value +var addPrefixToUrlAttr = function(attr) { + if (!attrNotEmpty(attr)) { + return; + } + + // url(...) in value + var urlVal = matchUrl(attr.value); + if (!urlVal) { + return; + } + + var idPrefixed = prefixId(urlVal); + if (!idPrefixed) { + return; + } + + attr.value = 'url(' + idPrefixed + ')'; +}; + +// prefixes begin/end attribute value +var addPrefixToBeginEndAttr = function(attr) { + if (!attrNotEmpty(attr)) { + return; + } + + var parts = attr.value.split('; ').map(function(val) { + val = val.trim(); + + if (val.endsWith('.end') || val.endsWith('.start')) { + var idPostfix = val.split('.'), + id = idPostfix[0], + postfix = idPostfix[1]; + + var idPrefixed = prefixId(`#${id}`); + + if (!idPrefixed) { + return val; + } + + idPrefixed = idPrefixed.slice(1); + return `${idPrefixed}.${postfix}`; + } else { + return val; + } + }); + + attr.value = parts.join('; '); +}; + +/** + * Prefixes identifiers + * + * @param {Object} node node + * @param {Object} opts plugin params + * @param {Object} extra plugin extra information + * + * @author strarsis <strarsis@gmail.com> + */ +exports.fn = function(node, opts, extra) { + + // skip subsequent passes when multipass is used + if(extra.multipassCount && extra.multipassCount > 0) { + return node; + } + + // prefix, from file name or option + var prefix = 'prefix'; + if (opts.prefix) { + if (typeof opts.prefix === 'function') { + prefix = opts.prefix(node, extra); + } else { + prefix = opts.prefix; + } + } else if (opts.prefix === false) { + prefix = false; + } else if (extra && extra.path && extra.path.length > 0) { + var filename = path.basename(extra.path); + prefix = filename; + } + + + // prefixes a normal value + addPrefix = function(name) { + if(prefix === false){ + return escapeIdentifierName(name); + } + return escapeIdentifierName(prefix + opts.delim + name); + }; + + + // <style/> property values + + if (node.elem === 'style') { + if (node.isEmpty()) { + // skip empty <style/>s + return node; + } + + var cssStr = node.content[0].text || node.content[0].cdata || []; + + var cssAst = {}; + try { + cssAst = csstree.parse(cssStr, { + parseValue: true, + parseCustomProperty: false + }); + } catch (parseError) { + console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError); + return node; + } + + var idPrefixed = ''; + csstree.walk(cssAst, function(node) { + + // #ID, .class + if (((opts.prefixIds && node.type === 'IdSelector') || + (opts.prefixClassNames && node.type === 'ClassSelector')) && + node.name) { + node.name = addPrefix(node.name); + return; + } + + // url(...) in value + if (node.type === 'Url' && + node.value.value && node.value.value.length > 0) { + idPrefixed = prefixId(unquote(node.value.value)); + if (!idPrefixed) { + return; + } + node.value.value = idPrefixed; + } + + }); + + // update <style>s + node.content[0].text = csstree.generate(cssAst); + return node; + } + + + // element attributes + + if (!node.attrs) { + return node; + } + + + // Nodes + + if(opts.prefixIds) { + // ID + addPrefixToIdAttr(node.attrs.id); + } + + if(opts.prefixClassNames) { + // Class + addPrefixToClassAttr(node.attrs.class); + } + + + // References + + // href + addPrefixToHrefAttr(node.attrs.href); + + // (xlink:)href (deprecated, must be still supported) + addPrefixToHrefAttr(node.attrs['xlink:href']); + + // (referenceable) properties + for (var referencesProp of referencesProps) { + addPrefixToUrlAttr(node.attrs[referencesProp]); + } + + addPrefixToBeginEndAttr(node.attrs.begin); + addPrefixToBeginEndAttr(node.attrs.end); + + return node; +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeAttributesBySelector.js b/vendor/svgclean/src/svgclean/plugins/removeAttributesBySelector.js new file mode 100644 index 000000000..3ae7463da --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeAttributesBySelector.js @@ -0,0 +1,70 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes attributes of elements that match a css selector'; + + +/** + * Removes attributes of elements that match a css selector. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @example + * <caption>A selector removing a single attribute</caption> + * plugins: + * - removeAttributesBySelector: + * selector: "[fill='#00ff00']" + * attributes: "fill" + * + * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/> + * ↓ + * <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/> + * + * <caption>A selector removing multiple attributes</caption> + * plugins: + * - removeAttributesBySelector: + * selector: "[fill='#00ff00']" + * attributes: + * - fill + * - stroke + * + * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/> + * ↓ + * <rect x="0" y="0" width="100" height="100"/> + * + * <caption>Multiple selectors removing attributes</caption> + * plugins: + * - removeAttributesBySelector: + * selectors: + * - selector: "[fill='#00ff00']" + * attributes: "fill" + * + * - selector: "#remove" + * attributes: + * - stroke + * - id + * + * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/> + * ↓ + * <rect x="0" y="0" width="100" height="100"/> + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors} + * + * @author Bradley Mease + */ +exports.fn = function(item, params) { + + var selectors = Array.isArray(params.selectors) ? params.selectors : [params]; + + selectors.map(function(i) { + if (item.matches(i.selector)) { + item.removeAttr(i.attributes); + } + }); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeAttrs.js b/vendor/svgclean/src/svgclean/plugins/removeAttrs.js new file mode 100644 index 000000000..491e0dc42 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeAttrs.js @@ -0,0 +1,150 @@ +'use strict'; + +var DEFAULT_SEPARATOR = ':'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes specified attributes'; + +exports.params = { + elemSeparator: DEFAULT_SEPARATOR, + preserveCurrentColor: false, + attrs: [] +}; + +/** + * Remove attributes + * + * @param elemSeparator + * format: string + * + * @param preserveCurrentColor + * format: boolean + * + * @param attrs: + * + * format: [ element* : attribute* : value* ] + * + * element : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used) + * attribute : regexp (wrapped into ^...$) + * value : regexp (wrapped into ^...$), single * or omitted > all values + * + * examples: + * + * > basic: remove fill attribute + * --- + * removeAttrs: + * attrs: 'fill' + * + * > remove fill attribute on path element + * --- + * attrs: 'path:fill' + * + * > remove fill attribute on path element where value is none + * --- + * attrs: 'path:fill:none' + * + * + * > remove all fill and stroke attribute + * --- + * attrs: + * - 'fill' + * - 'stroke' + * + * [is same as] + * + * attrs: '(fill|stroke)' + * + * [is same as] + * + * attrs: '*:(fill|stroke)' + * + * [is same as] + * + * attrs: '.*:(fill|stroke)' + * + * [is same as] + * + * attrs: '.*:(fill|stroke):.*' + * + * + * > remove all stroke related attributes + * ---- + * attrs: 'stroke.*' + * + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Benny Schudel + */ +exports.fn = function(item, params) { + // wrap into an array if params is not + if (!Array.isArray(params.attrs)) { + params.attrs = [params.attrs]; + } + + if (item.isElem()) { + var elemSeparator = typeof params.elemSeparator == 'string' ? params.elemSeparator : DEFAULT_SEPARATOR; + var preserveCurrentColor = typeof params.preserveCurrentColor == 'boolean' ? params.preserveCurrentColor : false; + + // prepare patterns + var patterns = params.attrs.map(function(pattern) { + + // if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value* + if (pattern.indexOf(elemSeparator) === -1) { + pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join(''); + + // if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value + } else if (pattern.split(elemSeparator).length < 3) { + pattern = [pattern, elemSeparator, '.*'].join(''); + } + + // create regexps for element, attribute name, and attribute value + return pattern.split(elemSeparator) + .map(function(value) { + + // adjust single * to match anything + if (value === '*') { value = '.*'; } + + return new RegExp(['^', value, '$'].join(''), 'i'); + }); + + }); + + // loop patterns + patterns.forEach(function(pattern) { + + // matches element + if (pattern[0].test(item.elem)) { + + // loop attributes + item.eachAttr(function(attr) { + var name = attr.name; + var value = attr.value; + var isFillCurrentColor = preserveCurrentColor && name == 'fill' && value == 'currentColor'; + var isStrokeCurrentColor = preserveCurrentColor && name == 'stroke' && value == 'currentColor'; + + if (!(isFillCurrentColor || isStrokeCurrentColor)) { + // matches attribute name + if (pattern[1].test(name)) { + + // matches attribute value + if (pattern[2].test(attr.value)) { + item.removeAttr(name); + } + } + } + + }); + + } + + }); + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeComments.js b/vendor/svgclean/src/svgclean/plugins/removeComments.js new file mode 100644 index 000000000..8bfd21b09 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeComments.js @@ -0,0 +1,27 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes comments'; + +/** + * Remove comments. + * + * @example + * <!-- Generator: Adobe Illustrator 15.0.0, SVG Export + * Plug-In . SVG Version: 6.00 Build 0) --> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.comment && item.comment.charAt(0) !== '!') { + return false; + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeDesc.js b/vendor/svgclean/src/svgclean/plugins/removeDesc.js new file mode 100644 index 000000000..76e695933 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeDesc.js @@ -0,0 +1,32 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.params = { + removeAny: true +}; + +exports.description = 'removes <desc>'; + +var standardDescs = /^(Created with|Created using)/; + +/** + * Removes <desc>. + * Removes only standard editors content or empty elements 'cause it can be used for accessibility. + * Enable parameter 'removeAny' to remove any description. + * + * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Daniel Wabyick + */ +exports.fn = function(item, params) { + + return !item.isElem('desc') || !(params.removeAny || item.isEmpty() || + standardDescs.test(item.content[0].text)); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeDimensions.js b/vendor/svgclean/src/svgclean/plugins/removeDimensions.js new file mode 100644 index 000000000..7cbd65c72 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeDimensions.js @@ -0,0 +1,49 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)'; + +/** + * Remove width/height attributes and add the viewBox attribute if it's missing + * + * @example + * <svg width="100" height="50" /> + * ↓ + * <svg viewBox="0 0 100 50" /> + * + * @param {Object} item current iteration item + * @return {Boolean} if true, with and height will be filtered out + * + * @author Benny Schudel + */ +exports.fn = function(item) { + + if (item.isElem('svg')) { + if (item.hasAttr('viewBox')) { + item.removeAttr('width'); + item.removeAttr('height'); + } else if ( + item.hasAttr('width') && + item.hasAttr('height') && + !isNaN(Number(item.attr('width').value)) && + !isNaN(Number(item.attr('height').value)) + ) { + item.addAttr({ + name: 'viewBox', + value: + '0 0 ' + + Number(item.attr('width').value) + + ' ' + + Number(item.attr('height').value), + prefix: '', + local: 'viewBox' + }); + item.removeAttr('width'); + item.removeAttr('height'); + } + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeDoctype.js b/vendor/svgclean/src/svgclean/plugins/removeDoctype.js new file mode 100644 index 000000000..32ee4f461 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeDoctype.js @@ -0,0 +1,40 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes doctype declaration'; + +/** + * Remove DOCTYPE declaration. + * + * "Unfortunately the SVG DTDs are a source of so many + * issues that the SVG WG has decided not to write one + * for the upcoming SVG 1.2 standard. In fact SVG WG + * members are even telling people not to use a DOCTYPE + * declaration in SVG 1.0 and 1.1 documents" + * https://jwatt.org/svg/authoring/#doctype-declaration + * + * @example + * <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + * q"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> + * + * @example + * <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [ + * <!-- an internal subset can be embedded here --> + * ]> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.doctype) { + return false; + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeEditorsNSData.js b/vendor/svgclean/src/svgclean/plugins/removeEditorsNSData.js new file mode 100644 index 000000000..9e5c8cd8f --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeEditorsNSData.js @@ -0,0 +1,65 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes editors namespaces, elements and attributes'; + +var editorNamespaces = require('./_collections').editorNamespaces, + prefixes = []; + +exports.params = { + additionalNamespaces: [] +}; + +/** + * Remove editors namespaces, elements and attributes. + * + * @example + * <svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"> + * <sodipodi:namedview/> + * <path sodipodi:nodetypes="cccc"/> + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (Array.isArray(params.additionalNamespaces)) { + editorNamespaces = editorNamespaces.concat(params.additionalNamespaces); + } + + if (item.elem) { + + if (item.isElem('svg')) { + + item.eachAttr(function(attr) { + if (attr.prefix === 'xmlns' && editorNamespaces.indexOf(attr.value) > -1) { + prefixes.push(attr.local); + + // <svg xmlns:sodipodi=""> + item.removeAttr(attr.name); + } + }); + + } + + // <* sodipodi:*=""> + item.eachAttr(function(attr) { + if (prefixes.indexOf(attr.prefix) > -1) { + item.removeAttr(attr.name); + } + }); + + // <sodipodi:*> + if (prefixes.indexOf(item.prefix) > -1) { + return false; + } + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeElementsByAttr.js b/vendor/svgclean/src/svgclean/plugins/removeElementsByAttr.js new file mode 100644 index 000000000..c726f7084 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeElementsByAttr.js @@ -0,0 +1,80 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes arbitrary elements by ID or className (disabled by default)'; + +exports.params = { + id: [], + class: [] +}; + +/** + * Remove arbitrary SVG elements by ID or className. + * + * @param id + * examples: + * + * > single: remove element with ID of `elementID` + * --- + * removeElementsByAttr: + * id: 'elementID' + * + * > list: remove multiple elements by ID + * --- + * removeElementsByAttr: + * id: + * - 'elementID' + * - 'anotherID' + * + * @param class + * examples: + * + * > single: remove all elements with class of `elementClass` + * --- + * removeElementsByAttr: + * class: 'elementClass' + * + * > list: remove all elements with class of `elementClass` or `anotherClass` + * --- + * removeElementsByAttr: + * class: + * - 'elementClass' + * - 'anotherClass' + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Eli Dupuis (@elidupuis) + */ +exports.fn = function(item, params) { + var elemId, elemClass; + + // wrap params in an array if not already + ['id', 'class'].forEach(function(key) { + if (!Array.isArray(params[key])) { + params[key] = [ params[key] ]; + } + }); + + // abort if current item is no an element + if (!item.isElem()) { + return; + } + + // remove element if it's `id` matches configured `id` params + elemId = item.attr('id'); + if (elemId) { + return params.id.indexOf(elemId.value) === -1; + } + + // remove element if it's `class` contains any of the configured `class` params + elemClass = item.attr('class'); + if (elemClass) { + var hasClassRegex = new RegExp(params.class.join('|')); + return !hasClassRegex.test(elemClass.value); + } +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeEmptyAttrs.js b/vendor/svgclean/src/svgclean/plugins/removeEmptyAttrs.js new file mode 100644 index 000000000..ae73e6c96 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeEmptyAttrs.js @@ -0,0 +1,29 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes empty attributes'; + +/** + * Remove attributes with empty values. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.elem) { + + item.eachAttr(function(attr) { + if (attr.value === '') { + item.removeAttr(attr.name); + } + }); + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeEmptyContainers.js b/vendor/svgclean/src/svgclean/plugins/removeEmptyContainers.js new file mode 100644 index 000000000..356a5835b --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeEmptyContainers.js @@ -0,0 +1,32 @@ +'use strict'; + +exports.type = 'perItemReverse'; + +exports.active = true; + +exports.description = 'removes empty container elements'; + +var container = require('./_collections').elemsGroups.container; + +/** + * Remove empty containers. + * + * @see http://www.w3.org/TR/SVG/intro.html#TermContainerElement + * + * @example + * <defs/> + * + * @example + * <g><marker><a/></marker></g> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty() && + (!item.isElem('pattern') || !item.hasAttrLocal('href'))); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeEmptyText.js b/vendor/svgclean/src/svgclean/plugins/removeEmptyText.js new file mode 100644 index 000000000..049b18196 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeEmptyText.js @@ -0,0 +1,59 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes empty <text> elements'; + +exports.params = { + text: true, + tspan: true, + tref: true +}; + +/** + * Remove empty Text elements. + * + * @see http://www.w3.org/TR/SVG/text.html + * + * @example + * Remove empty text element: + * <text/> + * + * Remove empty tspan element: + * <tspan/> + * + * Remove tref with empty xlink:href attribute: + * <tref xlink:href=""/> + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + // Remove empty text element + if ( + params.text && + item.isElem('text') && + item.isEmpty() + ) return false; + + // Remove empty tspan element + if ( + params.tspan && + item.isElem('tspan') && + item.isEmpty() + ) return false; + + // Remove tref with empty xlink:href attribute + if ( + params.tref && + item.isElem('tref') && + !item.hasAttrLocal('href') + ) return false; + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeHiddenElems.js b/vendor/svgclean/src/svgclean/plugins/removeHiddenElems.js new file mode 100644 index 000000000..7379125e7 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeHiddenElems.js @@ -0,0 +1,225 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes hidden elements (zero sized, with absent attributes)'; + +exports.params = { + isHidden: true, + displayNone: true, + opacity0: true, + circleR0: true, + ellipseRX0: true, + ellipseRY0: true, + rectWidth0: true, + rectHeight0: true, + patternWidth0: true, + patternHeight0: true, + imageWidth0: true, + imageHeight0: true, + pathEmptyD: true, + polylineEmptyPoints: true, + polygonEmptyPoints: true +}; + +var regValidPath = /M\s*(?:[-+]?(?:\d*\.\d+|\d+(?:\.|(?!\.)))([eE][-+]?\d+)?(?!\d)\s*,?\s*){2}\D*\d/i; + +/** + * Remove hidden elements with disabled rendering: + * - display="none" + * - opacity="0" + * - circle with zero radius + * - ellipse with zero x-axis or y-axis radius + * - rectangle with zero width or height + * - pattern with zero width or height + * - image with zero width or height + * - path with empty data + * - polyline with empty points + * - polygon with empty points + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function (item, params) { + + if (item.elem) { + // Removes hidden elements + // https://www.w3schools.com/cssref/pr_class_visibility.asp + if ( + params.isHidden && + item.hasAttr('visibility', 'hidden') + ) return false; + + // display="none" + // + // http://www.w3.org/TR/SVG/painting.html#DisplayProperty + // "A value of display: none indicates that the given element + // and its children shall not be rendered directly" + if ( + params.displayNone && + item.hasAttr('display', 'none') + ) return false; + + // opacity="0" + // + // http://www.w3.org/TR/SVG/masking.html#ObjectAndGroupOpacityProperties + if ( + params.opacity0 && + item.hasAttr('opacity', '0') + ) return false; + + // Circles with zero radius + // + // http://www.w3.org/TR/SVG/shapes.html#CircleElementRAttribute + // "A value of zero disables rendering of the element" + // + // <circle r="0"> + if ( + params.circleR0 && + item.isElem('circle') && + item.isEmpty() && + item.hasAttr('r', '0') + ) return false; + + // Ellipse with zero x-axis radius + // + // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRXAttribute + // "A value of zero disables rendering of the element" + // + // <ellipse rx="0"> + if ( + params.ellipseRX0 && + item.isElem('ellipse') && + item.isEmpty() && + item.hasAttr('rx', '0') + ) return false; + + // Ellipse with zero y-axis radius + // + // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRYAttribute + // "A value of zero disables rendering of the element" + // + // <ellipse ry="0"> + if ( + params.ellipseRY0 && + item.isElem('ellipse') && + item.isEmpty() && + item.hasAttr('ry', '0') + ) return false; + + // Rectangle with zero width + // + // http://www.w3.org/TR/SVG/shapes.html#RectElementWidthAttribute + // "A value of zero disables rendering of the element" + // + // <rect width="0"> + if ( + params.rectWidth0 && + item.isElem('rect') && + item.isEmpty() && + item.hasAttr('width', '0') + ) return false; + + // Rectangle with zero height + // + // http://www.w3.org/TR/SVG/shapes.html#RectElementHeightAttribute + // "A value of zero disables rendering of the element" + // + // <rect height="0"> + if ( + params.rectHeight0 && + params.rectWidth0 && + item.isElem('rect') && + item.isEmpty() && + item.hasAttr('height', '0') + ) return false; + + // Pattern with zero width + // + // http://www.w3.org/TR/SVG/pservers.html#PatternElementWidthAttribute + // "A value of zero disables rendering of the element (i.e., no paint is applied)" + // + // <pattern width="0"> + if ( + params.patternWidth0 && + item.isElem('pattern') && + item.hasAttr('width', '0') + ) return false; + + // Pattern with zero height + // + // http://www.w3.org/TR/SVG/pservers.html#PatternElementHeightAttribute + // "A value of zero disables rendering of the element (i.e., no paint is applied)" + // + // <pattern height="0"> + if ( + params.patternHeight0 && + item.isElem('pattern') && + item.hasAttr('height', '0') + ) return false; + + // Image with zero width + // + // http://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute + // "A value of zero disables rendering of the element" + // + // <image width="0"> + if ( + params.imageWidth0 && + item.isElem('image') && + item.hasAttr('width', '0') + ) return false; + + // Image with zero height + // + // http://www.w3.org/TR/SVG/struct.html#ImageElementHeightAttribute + // "A value of zero disables rendering of the element" + // + // <image height="0"> + if ( + params.imageHeight0 && + item.isElem('image') && + item.hasAttr('height', '0') + ) return false; + + // Path with empty data + // + // http://www.w3.org/TR/SVG/paths.html#DAttribute + // + // <path d=""/> + if ( + params.pathEmptyD && + item.isElem('path') && + (!item.hasAttr('d') || !regValidPath.test(item.attr('d').value)) + ) return false; + + // Polyline with empty points + // + // http://www.w3.org/TR/SVG/shapes.html#PolylineElementPointsAttribute + // + // <polyline points=""> + if ( + params.polylineEmptyPoints && + item.isElem('polyline') && + !item.hasAttr('points') + ) return false; + + // Polygon with empty points + // + // http://www.w3.org/TR/SVG/shapes.html#PolygonElementPointsAttribute + // + // <polygon points=""> + if ( + params.polygonEmptyPoints && + item.isElem('polygon') && + !item.hasAttr('points') + ) return false; + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeMetadata.js b/vendor/svgclean/src/svgclean/plugins/removeMetadata.js new file mode 100644 index 000000000..fa7a57951 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeMetadata.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes <metadata>'; + +/** + * Remove <metadata>. + * + * http://www.w3.org/TR/SVG/metadata.html + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !item.isElem('metadata'); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeNonInheritableGroupAttrs.js b/vendor/svgclean/src/svgclean/plugins/removeNonInheritableGroupAttrs.js new file mode 100644 index 000000000..85e3b9796 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeNonInheritableGroupAttrs.js @@ -0,0 +1,37 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes non-inheritable group’s presentational attributes'; + +var inheritableAttrs = require('./_collections').inheritableAttrs, + attrsGroups = require('./_collections').attrsGroups, + applyGroups = require('./_collections').presentationNonInheritableGroupAttrs; + +/** + * Remove non-inheritable group's "presentation" attributes. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if (item.isElem('g')) { + + item.eachAttr(function(attr) { + if ( + ~attrsGroups.presentation.indexOf(attr.name) && + !~inheritableAttrs.indexOf(attr.name) && + !~applyGroups.indexOf(attr.name) + ) { + item.removeAttr(attr.name); + } + }); + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeOffCanvasPaths.js b/vendor/svgclean/src/svgclean/plugins/removeOffCanvasPaths.js new file mode 100644 index 000000000..717bb0e75 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeOffCanvasPaths.js @@ -0,0 +1,134 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes elements that are drawn outside of the viewbox (disabled by default)'; + +var tools = require("../tools"), + _path = require('./_path.js'), + intersects = _path.intersects, + path2js = _path.path2js, + viewBox, + viewBoxJS; + +/** + * Remove elements that are drawn outside of the viewbox. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author JoshyPHP + */ +exports.fn = function(item) { + + if (item.isElem('path') && item.hasAttr('d') && typeof viewBox !== 'undefined') + { + // Consider that any item with a transform attribute or a M instruction + // within the viewBox is visible + if (hasTransform(item) || pathMovesWithinViewBox(item.attr('d').value)) + { + return true; + } + + var pathJS = path2js(item); + if (pathJS.length === 2) + { + // Use a closed clone of the path if it's too short for intersects() + pathJS = JSON.parse(JSON.stringify(pathJS)); + pathJS.push({ instruction: 'z' }); + } + + return intersects(viewBoxJS, pathJS); + } + if (item.isElem('svg')) + { + parseViewBox(item); + } + + return true; +}; + +/** + * Test whether given item or any of its ancestors has a transform attribute. + * + * @param {String} path + * @return {Boolean} + */ +function hasTransform(item) +{ + return item.hasAttr('transform') || (item.parentNode && hasTransform(item.parentNode)); +} + +/** + * Parse the viewBox coordinates and compute the JS representation of its path. + * + * @param {Object} svg svg element item + */ +function parseViewBox(svg) +{ + var viewBoxData = ''; + if (svg.hasAttr('viewBox')) + { + // Remove commas and plus signs, normalize and trim whitespace + viewBoxData = svg.attr('viewBox').value; + } + else if (svg.hasAttr('height') && svg.hasAttr('width')) + { + viewBoxData = '0 0 ' + svg.attr('width').value + ' ' + svg.attr('height').value; + } + + // Remove commas and plus signs, normalize and trim whitespace + viewBoxData = viewBoxData.replace(/[,+]|px/g, ' ').replace(/\s+/g, ' ').replace(/^\s*|\s*$/g, ''); + + // Ensure that the dimensions are 4 values separated by space + var m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(viewBoxData); + if (!m) + { + return; + } + + // Store the viewBox boundaries + viewBox = { + left: parseFloat(m[1]), + top: parseFloat(m[2]), + right: parseFloat(m[1]) + parseFloat(m[3]), + bottom: parseFloat(m[2]) + parseFloat(m[4]) + }; + + var path = tools.createContentItem({ + elem: 'path', + prefix: '', + local: 'path' + }); + + path.addAttr({ + name: 'd', + prefix: '', + local: 'd', + value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z' + }); + + viewBoxJS = path2js(path); +} + +/** + * Test whether given path has a M instruction with coordinates within the viewBox. + * + * @param {String} path + * @return {Boolean} + */ +function pathMovesWithinViewBox(path) +{ + var regexp = /M\s*(-?\d*\.?\d+)(?!\d)\s*(-?\d*\.?\d+)/g, m; + while (null !== (m = regexp.exec(path))) + { + if (m[1] >= viewBox.left && m[1] <= viewBox.right && m[2] >= viewBox.top && m[2] <= viewBox.bottom) + { + return true; + } + } + + return false; +} diff --git a/vendor/svgclean/src/svgclean/plugins/removeRasterImages.js b/vendor/svgclean/src/svgclean/plugins/removeRasterImages.js new file mode 100644 index 000000000..cbddebe3d --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeRasterImages.js @@ -0,0 +1,28 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes raster images (disabled by default)'; + +/** + * Remove raster images references in <image>. + * + * @see https://bugs.webkit.org/show_bug.cgi?id=63548 + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if ( + item.isElem('image') && + item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/) + ) { + return false; + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeScriptElement.js b/vendor/svgclean/src/svgclean/plugins/removeScriptElement.js new file mode 100644 index 000000000..f80410bd4 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeScriptElement.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes <script> elements (disabled by default)'; + +/** + * Remove <script>. + * + * https://www.w3.org/TR/SVG/script.html + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Patrick Klingemann + */ +exports.fn = function(item) { + + return !item.isElem('script'); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeStyleElement.js b/vendor/svgclean/src/svgclean/plugins/removeStyleElement.js new file mode 100644 index 000000000..964ce45c8 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeStyleElement.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes <style> element (disabled by default)'; + +/** + * Remove <style>. + * + * http://www.w3.org/TR/SVG/styling.html#StyleElement + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Betsy Dupuis + */ +exports.fn = function(item) { + + return !item.isElem('style'); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeTitle.js b/vendor/svgclean/src/svgclean/plugins/removeTitle.js new file mode 100644 index 000000000..841d178b0 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeTitle.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes <title>'; + +/** + * Remove <title>. + * + * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Igor Kalashnikov + */ +exports.fn = function(item) { + + return !item.isElem('title'); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeUnknownsAndDefaults.js b/vendor/svgclean/src/svgclean/plugins/removeUnknownsAndDefaults.js new file mode 100644 index 000000000..31970a4f0 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeUnknownsAndDefaults.js @@ -0,0 +1,150 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes unknown elements content and attributes, removes attrs with default values'; + +exports.params = { + unknownContent: true, + unknownAttrs: true, + defaultAttrs: true, + uselessOverrides: true, + keepDataAttrs: true, + keepAriaAttrs: true, + keepRoleAttr: false +}; + +var collections = require('./_collections'), + elems = collections.elems, + attrsGroups = collections.attrsGroups, + elemsGroups = collections.elemsGroups, + attrsGroupsDefaults = collections.attrsGroupsDefaults, + attrsInheritable = collections.inheritableAttrs, + applyGroups = collections.presentationNonInheritableGroupAttrs; + +// collect and extend all references +for (var elem in elems) { + elem = elems[elem]; + + if (elem.attrsGroups) { + elem.attrs = elem.attrs || []; + + elem.attrsGroups.forEach(function(attrsGroupName) { + elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]); + + var groupDefaults = attrsGroupsDefaults[attrsGroupName]; + + if (groupDefaults) { + elem.defaults = elem.defaults || {}; + + for (var attrName in groupDefaults) { + elem.defaults[attrName] = groupDefaults[attrName]; + } + } + }); + + } + + if (elem.contentGroups) { + elem.content = elem.content || []; + + elem.contentGroups.forEach(function(contentGroupName) { + elem.content = elem.content.concat(elemsGroups[contentGroupName]); + }); + } +} + +/** + * Remove unknown elements content and attributes, + * remove attributes with default values. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + // elems w/o namespace prefix + if (item.isElem() && !item.prefix) { + + var elem = item.elem; + + // remove unknown element's content + if ( + params.unknownContent && + !item.isEmpty() && + elems[elem] && // make sure we know of this element before checking its children + elem !== 'foreignObject' // Don't check foreignObject + ) { + item.content.forEach(function(content, i) { + if ( + content.isElem() && + !content.prefix && + ( + ( + elems[elem].content && // Do we have a record of its permitted content? + elems[elem].content.indexOf(content.elem) === -1 + ) || + ( + !elems[elem].content && // we dont know about its permitted content + !elems[content.elem] // check that we know about the element at all + ) + ) + ) { + item.content.splice(i, 1); + } + }); + } + + // remove element's unknown attrs and attrs with default values + if (elems[elem] && elems[elem].attrs) { + + item.eachAttr(function(attr) { + + if ( + attr.name !== 'xmlns' && + (attr.prefix === 'xml' || !attr.prefix) && + (!params.keepDataAttrs || attr.name.indexOf('data-') != 0) && + (!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) && + (!params.keepRoleAttr || attr.name != 'role') + ) { + if ( + // unknown attrs + ( + params.unknownAttrs && + elems[elem].attrs.indexOf(attr.name) === -1 + ) || + // attrs with default values + ( + params.defaultAttrs && + !item.hasAttr('id') && + elems[elem].defaults && + elems[elem].defaults[attr.name] === attr.value && ( + attrsInheritable.indexOf(attr.name) < 0 || + !item.parentNode.computedAttr(attr.name) + ) + ) || + // useless overrides + ( + params.uselessOverrides && + !item.hasAttr('id') && + applyGroups.indexOf(attr.name) < 0 && + attrsInheritable.indexOf(attr.name) > -1 && + item.parentNode.computedAttr(attr.name, attr.value) + ) + ) { + item.removeAttr(attr.name); + } + } + + }); + + } + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeUnusedNS.js b/vendor/svgclean/src/svgclean/plugins/removeUnusedNS.js new file mode 100644 index 000000000..db0df7605 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeUnusedNS.js @@ -0,0 +1,109 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.description = 'removes unused namespaces declaration'; + +/** + * Remove unused namespaces declaration. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(data) { + + var svgElem, + xmlnsCollection = []; + + /** + * Remove namespace from collection. + * + * @param {String} ns namescape name + */ + function removeNSfromCollection(ns) { + + var pos = xmlnsCollection.indexOf(ns); + + // if found - remove ns from the namespaces collection + if (pos > -1) { + xmlnsCollection.splice(pos, 1); + } + + } + + /** + * Bananas! + * + * @param {Array} items input items + * + * @return {Array} output items + */ + function monkeys(items) { + + var i = 0, + length = items.content.length; + + while(i < length) { + + var item = items.content[i]; + + if (item.isElem('svg')) { + + item.eachAttr(function(attr) { + // collect namespaces + if (attr.prefix === 'xmlns' && attr.local) { + xmlnsCollection.push(attr.local); + } + }); + + // if svg element has ns-attr + if (xmlnsCollection.length) { + // save svg element + svgElem = item; + } + + } + + if (xmlnsCollection.length) { + + // check item for the ns-attrs + if (item.prefix) { + removeNSfromCollection(item.prefix); + } + + // check each attr for the ns-attrs + item.eachAttr(function(attr) { + removeNSfromCollection(attr.prefix); + }); + + } + + // if nothing is found - go deeper + if (xmlnsCollection.length && item.content) { + monkeys(item); + } + + i++; + + } + + return items; + + } + + data = monkeys(data); + + // remove svg element ns-attributes if they are not used even once + if (xmlnsCollection.length) { + xmlnsCollection.forEach(function(name) { + svgElem.removeAttr('xmlns:' + name); + }); + } + + return data; + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeUselessDefs.js b/vendor/svgclean/src/svgclean/plugins/removeUselessDefs.js new file mode 100644 index 000000000..87badd938 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeUselessDefs.js @@ -0,0 +1,53 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes elements in <defs> without id'; + +var nonRendering = require('./_collections').elemsGroups.nonRendering; + +/** + * Removes content of defs and properties that aren't rendered directly without ids. + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Lev Solntsev + */ +exports.fn = function(item) { + + if (item.isElem('defs')) { + + if (item.content) { + item.content = getUsefulItems(item, []); + } + + if (item.isEmpty()) return false; + + } else if (item.isElem(nonRendering) && !item.hasAttr('id')) { + + return false; + + } + +}; + +function getUsefulItems(item, usefulItems) { + + item.content.forEach(function(child) { + if (child.hasAttr('id') || child.isElem('style')) { + + usefulItems.push(child); + child.parentNode = item; + + } else if (!child.isEmpty()) { + + child.content = getUsefulItems(child, usefulItems); + + } + }); + + return usefulItems; +} diff --git a/vendor/svgclean/src/svgclean/plugins/removeUselessStrokeAndFill.js b/vendor/svgclean/src/svgclean/plugins/removeUselessStrokeAndFill.js new file mode 100644 index 000000000..e6b8eea71 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeUselessStrokeAndFill.js @@ -0,0 +1,100 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes useless stroke and fill attributes'; + +exports.params = { + stroke: true, + fill: true, + removeNone: false, + hasStyleOrScript: false +}; + +var shape = require('./_collections').elemsGroups.shape, + regStrokeProps = /^stroke/, + regFillProps = /^fill-/, + styleOrScript = ['style', 'script']; + +/** + * Remove useless stroke and fill attrs. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item, params) { + + if (item.isElem(styleOrScript)) { + params.hasStyleOrScript = true; + } + + if (!params.hasStyleOrScript && item.isElem(shape) && !item.computedAttr('id')) { + + var stroke = params.stroke && item.computedAttr('stroke'), + fill = params.fill && !item.computedAttr('fill', 'none'); + + // remove stroke* + if ( + params.stroke && + (!stroke || + stroke == 'none' || + item.computedAttr('stroke-opacity', '0') || + item.computedAttr('stroke-width', '0') + ) + ) { + var parentStroke = item.parentNode.computedAttr('stroke'), + declineStroke = parentStroke && parentStroke != 'none'; + + item.eachAttr(function(attr) { + if (regStrokeProps.test(attr.name)) { + item.removeAttr(attr.name); + } + }); + + if (declineStroke) item.addAttr({ + name: 'stroke', + value: 'none', + prefix: '', + local: 'stroke' + }); + } + + // remove fill* + if ( + params.fill && + (!fill || item.computedAttr('fill-opacity', '0')) + ) { + item.eachAttr(function(attr) { + if (regFillProps.test(attr.name)) { + item.removeAttr(attr.name); + } + }); + + if (fill) { + if (item.hasAttr('fill')) + item.attr('fill').value = 'none'; + else + item.addAttr({ + name: 'fill', + value: 'none', + prefix: '', + local: 'fill' + }); + } + } + + if (params.removeNone && + (!stroke || item.hasAttr('stroke') && item.attr('stroke').value=='none') && + (!fill || item.hasAttr('fill') && item.attr('fill').value=='none')) { + + return false; + } + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeViewBox.js b/vendor/svgclean/src/svgclean/plugins/removeViewBox.js new file mode 100644 index 000000000..2fbcba4f4 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeViewBox.js @@ -0,0 +1,48 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes viewBox attribute when possible'; + +var viewBoxElems = ['svg', 'pattern', 'symbol']; + +/** + * Remove viewBox attr which coincides with a width/height box. + * + * @see http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute + * + * @example + * <svg width="100" height="50" viewBox="0 0 100 50"> + * ⬇ + * <svg width="100" height="50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + if ( + item.isElem(viewBoxElems) && + item.hasAttr('viewBox') && + item.hasAttr('width') && + item.hasAttr('height') + ) { + + var nums = item.attr('viewBox').value.split(/[ ,]+/g); + + if ( + nums[0] === '0' && + nums[1] === '0' && + item.attr('width').value.replace(/px$/, '') === nums[2] && // could use parseFloat too + item.attr('height').value.replace(/px$/, '') === nums[3] + ) { + item.removeAttr('viewBox'); + } + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/removeXMLNS.js b/vendor/svgclean/src/svgclean/plugins/removeXMLNS.js new file mode 100644 index 000000000..afda99d36 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeXMLNS.js @@ -0,0 +1,28 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'removes xmlns attribute (for inline svg, disabled by default)'; + +/** + * Remove the xmlns attribute when present. + * + * @example + * <svg viewBox="0 0 100 50" xmlns="http://www.w3.org/2000/svg"> + * ↓ + * <svg viewBox="0 0 100 50"> + * + * @param {Object} item current iteration item + * @return {Boolean} if true, xmlns will be filtered out + * + * @author Ricardo Tomasi + */ +exports.fn = function(item) { + + if (item.isElem('svg') && item.hasAttr('xmlns')) { + item.removeAttr('xmlns'); + } + +}; \ No newline at end of file diff --git a/vendor/svgclean/src/svgclean/plugins/removeXMLProcInst.js b/vendor/svgclean/src/svgclean/plugins/removeXMLProcInst.js new file mode 100644 index 000000000..afd425d57 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/removeXMLProcInst.js @@ -0,0 +1,24 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'removes XML processing instructions'; + +/** + * Remove XML Processing Instruction. + * + * @example + * <?xml version="1.0" encoding="utf-8"?> + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author Kir Belevich + */ +exports.fn = function(item) { + + return !(item.processinginstruction && item.processinginstruction.name === 'xml'); + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/reusePaths.js b/vendor/svgclean/src/svgclean/plugins/reusePaths.js new file mode 100644 index 000000000..dc1f92ed7 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/reusePaths.js @@ -0,0 +1,169 @@ +/** + * @license + * The MIT License + * + * Copyright © 2012–2016 Kir Belevich + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * Лицензия MIT + * + * Copyright © 2012–2016 Кир Белевич + * + * Данная лицензия разрешает лицам, получившим копию + * данного + * программного обеспечения и сопутствующей + * документации + * (в дальнейшем именуемыми «Программное Обеспечение»), + * безвозмездно + * использовать Программное Обеспечение без + * ограничений, включая + * неограниченное право на использование, копирование, + * изменение, + * добавление, публикацию, распространение, + * сублицензирование + * и/или продажу копий Программного Обеспечения, также + * как и лицам, + * которым предоставляется данное Программное + * Обеспечение, + * при соблюдении следующих условий: + * + * Указанное выше уведомление об авторском праве и + * данные условия + * должны быть включены во все копии или значимые части + * данного + * Программного Обеспечения. + * + * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК + * ЕСТЬ», + * БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ + * ПОДРАЗУМЕВАЕМЫХ, + * ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ + * ПРИГОДНОСТИ, + * СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И + * ОТСУТСТВИЯ НАРУШЕНИЙ + * ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ + * НЕСУТ + * ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ + * ИЛИ ДРУГИХ + * ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ + * ИНОМУ, + * ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С + * ПРОГРАММНЫМ + * ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО + * ОБЕСПЕЧЕНИЯ + * ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. + */ + +'use strict'; + +const tools = require("../tools"); + +exports.type = 'full'; + +exports.active = false; + +exports.description = 'Finds <path> elements with the same d, fill, and ' + + 'stroke, and converts them to <use> elements ' + + 'referencing a single <path> def.'; + +/** + * Finds <path> elements with the same d, fill, and stroke, and converts them to + * <use> elements referencing a single <path> def. + * + * @author Jacob Howcroft + */ +exports.fn = function(data) { + const seen = new Map(); + let count = 0; + const defs = []; + traverse(data, item => { + if (!item.isElem('path') || !item.hasAttr('d')) { + return; + } + const d = item.attr('d').value; + const fill = (item.hasAttr('fill') && item.attr('fill').value) || ''; + const stroke = (item.hasAttr('stroke') && item.attr('stroke').value) || ''; + const key = d + ';s:' + stroke + ';f:' + fill; + const hasSeen = seen.get(key); + if (!hasSeen) { + seen.set(key, {elem: item, reused: false}); + return; + } + if (!hasSeen.reused) { + hasSeen.reused = true; + if (!hasSeen.elem.hasAttr('id')) { + hasSeen.elem.addAttr({name: 'id', local: 'id', + prefix: '', value: 'reuse-' + (count++)}); + } + defs.push(hasSeen.elem); + } + item = convertToUse(item, hasSeen.elem.attr('id').value); + }); + const defsTag = tools.createContentItem({ + elem: 'defs', prefix: '', local: 'defs', content: [], attrs: []}, data); + + data.content[0].spliceContent(0, 0, defsTag); + for (let def of defs) { + // Remove class and style before copying to avoid circular refs in + // JSON.stringify. This is fine because we don't actually want class or + // style information to be copied. + const style = def.style; + const defClass = def.class; + delete def.style; + delete def.class; + const defClone = def.clone(); + def.style = style; + def.class = defClass; + defClone.removeAttr('transform'); + defsTag.spliceContent(0, 0, defClone); + // Convert the original def to a use so the first usage isn't duplicated. + def = convertToUse(def, defClone.attr('id').value); + def.removeAttr('id'); + } + return data; +}; + +/** */ +function convertToUse(item, href) { + item.renameElem('use'); + item.removeAttr('d'); + item.removeAttr('stroke'); + item.removeAttr('fill'); + item.addAttr({name: 'xlink:href', local: 'xlink:href', + prefix: 'none', value: '#' + href}); + delete item.pathJS; + return item; +} + +/** */ +function traverse(parent, callback) { + if (parent.isEmpty()) { + return; + } + for (let child of parent.content) { + callback(child); + traverse(child, callback); + } +} diff --git a/vendor/svgclean/src/svgclean/plugins/sortAttrs.js b/vendor/svgclean/src/svgclean/plugins/sortAttrs.js new file mode 100644 index 000000000..cba5c1de6 --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/sortAttrs.js @@ -0,0 +1,84 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.description = 'sorts element attributes (disabled by default)'; + +exports.params = { + order: [ + 'id', + 'width', 'height', + 'x', 'x1', 'x2', + 'y', 'y1', 'y2', + 'cx', 'cy', 'r', + 'fill', 'stroke', 'marker', + 'd', 'points' + ] +}; + +/** + * Sort element attributes for epic readability. + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * + * @author Nikolay Frantsev + */ +exports.fn = function(item, params) { + + var attrs = [], + sorted = {}, + orderlen = params.order.length + 1, + xmlnsOrder = params.xmlnsOrder || 'front'; + + if (item.elem) { + + item.eachAttr(function(attr) { + attrs.push(attr); + }); + + attrs.sort(function(a, b) { + if (a.prefix != b.prefix) { + // xmlns attributes implicitly have the prefix xmlns + if (xmlnsOrder == 'front') { + if (a.prefix == 'xmlns') + return -1; + if (b.prefix == 'xmlns') + return 1; + } + return a.prefix < b.prefix ? -1 : 1; + } + + var aindex = orderlen; + var bindex = orderlen; + + for (var i = 0; i < params.order.length; i++) { + if (a.name == params.order[i]) { + aindex = i; + } else if (a.name.indexOf(params.order[i] + '-') === 0) { + aindex = i + .5; + } + if (b.name == params.order[i]) { + bindex = i; + } else if (b.name.indexOf(params.order[i] + '-') === 0) { + bindex = i + .5; + } + } + + if (aindex != bindex) { + return aindex - bindex; + } + return a.name < b.name ? -1 : 1; + }); + + attrs.forEach(function (attr) { + sorted[attr.name] = attr; + }); + + item.attrs = sorted; + + } + +}; diff --git a/vendor/svgclean/src/svgclean/plugins/sortDefsChildren.js b/vendor/svgclean/src/svgclean/plugins/sortDefsChildren.js new file mode 100644 index 000000000..bf1d1c43f --- /dev/null +++ b/vendor/svgclean/src/svgclean/plugins/sortDefsChildren.js @@ -0,0 +1,47 @@ +'use strict'; + +exports.type = 'perItem'; + +exports.active = true; + +exports.description = 'Sorts children of <defs> to improve compression'; + +/** + * Sorts children of defs in order to improve compression. + * Sorted first by frequency then by element name length then by element name (to ensure grouping). + * + * @param {Object} item current iteration item + * @return {Boolean} if false, item will be filtered out + * + * @author David Leston + */ +exports.fn = function(item) { + + if (item.isElem('defs')) { + + if (item.content) { + var frequency = item.content.reduce(function (frequency, child) { + if (child.elem in frequency) { + frequency[child.elem]++; + } else { + frequency[child.elem] = 1; + } + return frequency; + }, {}); + item.content.sort(function (a, b) { + var frequencyComparison = frequency[b.elem] - frequency[a.elem]; + if (frequencyComparison !== 0 ) { + return frequencyComparison; + } + var lengthComparison = b.elem.length - a.elem.length; + if (lengthComparison !== 0) { + return lengthComparison; + } + return a.elem != b.elem ? a.elem > b.elem ? -1 : 1 : 0; + }); + } + + return true; + } + +}; diff --git a/vendor/svgclean/src/svgclean/svg2js.js b/vendor/svgclean/src/svgclean/svg2js.js new file mode 100644 index 000000000..892d3dbd5 --- /dev/null +++ b/vendor/svgclean/src/svgclean/svg2js.js @@ -0,0 +1,190 @@ +"use strict"; + +const SAX = require("sax"); +const JSAPI = require("./jsAPI.js"); +const CSSClassList = require("./css-class-list"); +const CSSStyleDeclaration = require("./css-style-declaration"); +const entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g; + +const config = { + strict: true, + trim: false, + normalize: true, + lowercase: true, + xmlns: true, + position: true +}; + +/** + * Convert SVG (XML) string to SVG-as-JS object. + * + * @param {String} data input data + * @param {Function} callback + */ +module.exports = function(data, callback) { + return new Promise(function(resolve, reject) { + let sax = SAX.parser(config.strict, config); + let root = new JSAPI({ elem: "#document", content: [] }); + let current = root; + let stack = [root]; + let textContext = null; + let parsingError = false; + + function pushToContent(content) { + content = new JSAPI(content, current); + (current.content = current.content || []).push(content); + return content; + } + + sax.ondoctype = function(doctype) { + pushToContent({ + doctype: doctype + }); + + let subsetStart = doctype.indexOf("["); + let entityMatch; + + if (subsetStart >= 0) { + entityDeclaration.lastIndex = subsetStart; + + while ((entityMatch = entityDeclaration.exec(data)) != null) { + sax.ENTITIES[entityMatch[1]] = entityMatch[2] || entityMatch[3]; + } + } + }; + + sax.onprocessinginstruction = function(data) { + pushToContent({ + processinginstruction: data + }); + }; + + sax.oncomment = function(comment) { + pushToContent({ + comment: comment.trim() + }); + }; + + sax.oncdata = function(cdata) { + pushToContent({ + cdata: cdata + }); + }; + + sax.onopentag = function(data) { + let elem = { + elem: data.name, + prefix: data.prefix, + local: data.local, + attrs: {} + }; + + elem.class = new CSSClassList(elem); + elem.style = new CSSStyleDeclaration(elem); + + if (Object.keys(data.attributes).length) { + for (var name in data.attributes) { + + if (name === "class") { // has class attribute + elem.class.hasClass(); + } + + if (name === "style") { // has style attribute + elem.style.hasStyle(); + } + + elem.attrs[name] = { + name: name, + value: data.attributes[name].value, + prefix: data.attributes[name].prefix, + local: data.attributes[name].local + }; + } + } + + elem = pushToContent(elem); + current = elem; + + // Save info about <text> tag to prevent trimming of meaningful whitespace + if (data.name == "text" && !data.prefix) { + textContext = current; + } + + stack.push(elem); + + }; + + sax.ontext = function(text) { + if (/\S/.test(text) || textContext) { + if (!textContext) text = text.trim(); + + pushToContent({ + text: text + }); + + } + }; + + sax.onclosetag = function() { + var last = stack.pop(); + + // Trim text inside <text> tag. + if (last == textContext) { + trim(textContext); + textContext = null; + } + current = stack[stack.length - 1]; + }; + + sax.onerror = function(e) { + e.message = "Error in parsing SVG: " + e.message; + if (e.message.indexOf("Unexpected end") < 0) { + reject(e); + } + }; + + sax.onend = function() { + if (!this.error) { + resolve(root); + } else { + reject(this.error); + } + + }; + + try { + sax.write(data); + } catch (e) { + reject(e) + parsingError = true; + } + if (!parsingError) { + sax.close(); + } + + function trim(elem) { + if (!elem.content) return elem; + + let start = elem.content[0]; + let end = elem.content[elem.content.length - 1]; + + while (start && start.content && !start.text) { + start = start.content[0]; + } + + if (start && start.text) { + start.text = start.text.replace(/^\s+/, ""); + } + + while (end && end.content && !end.text) { + end = end.content[end.content.length - 1]; + } + + if (end && end.text) { + end.text = end.text.replace(/\s+$/, ""); + } + + return elem; + } + }); +}; diff --git a/vendor/svgclean/src/svgclean/tools.js b/vendor/svgclean/src/svgclean/tools.js new file mode 100644 index 000000000..75c78eb79 --- /dev/null +++ b/vendor/svgclean/src/svgclean/tools.js @@ -0,0 +1,152 @@ +'use strict'; + +const JSAPI = require("./jsAPI"); + +/** + * The factory that creates a content item with the helper methods. + * + * @param {Object} data which is passed to jsAPI constructor + * @returns {JSAPI} content item + */ +exports.createContentItem = function(data) { + return new JSAPI(data); +}; + +/** + * Encode plain SVG data string into Data URI string. + * + * @param {String} str input string + * @param {String} type Data URI type + * @return {String} output string + */ +exports.encodeSVGDatauri = function(str, type) { + var prefix = 'data:image/svg+xml'; + if (!type || type === 'base64') { + // base64 + prefix += ';base64,'; + if (Buffer.from) { + str = prefix + Buffer.from(str).toString('base64'); + } else { + str = prefix + new Buffer(str).toString('base64'); + } + } else if (type === 'enc') { + // URI encoded + str = prefix + ',' + encodeURIComponent(str); + } else if (type === 'unenc') { + // unencoded + str = prefix + ',' + str; + } + return str; +}; + +/** + * Decode SVG Data URI string into plain SVG string. + * + * @param {string} str input string + * @return {String} output string + */ +exports.decodeSVGDatauri = function(str) { + var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/; + var match = regexp.exec(str); + + // plain string + if (!match) return str; + + var data = match[3]; + + if (match[2]) { + // base64 + str = new Buffer(data, 'base64').toString('utf8'); + } else if (data.charAt(0) === '%') { + // URI encoded + str = decodeURIComponent(data); + } else if (data.charAt(0) === '<') { + // unencoded + str = data; + } + return str; +}; + +exports.intersectArrays = function(a, b) { + return a.filter(function(n) { + return b.indexOf(n) > -1; + }); +}; + +/** + * Convert a row of numbers to an optimized string view. + * + * @example + * [0, -1, .5, .5] → "0-1 .5.5" + * + * @param {number[]} data + * @param {Object} params + * @param {string?} command path data instruction + * @return {string} + */ +exports.cleanupOutData = function(data, params, command) { + var str = '', + delimiter, + prev; + + data.forEach(function(item, i) { + // space delimiter by default + delimiter = ' '; + + // no extra space in front of first number + if (i == 0) delimiter = ''; + + // no extra space after 'arcto' command flags + if (params.noSpaceAfterFlags && (command == 'A' || command == 'a')) { + var pos = i % 7; + if (pos == 4 || pos == 5) delimiter = ''; + } + + // remove floating-point numbers leading zeros + // 0.5 → .5 + // -0.5 → -.5 + if (params.leadingZero) { + item = removeLeadingZero(item); + } + + // no extra space in front of negative number or + // in front of a floating number if a previous number is floating too + if ( + params.negativeExtraSpace && + delimiter != '' && + (item < 0 || + (String(item).charCodeAt(0) == 46 && prev % 1 !== 0) + ) + ) { + delimiter = ''; + } + // save prev item value + prev = item; + str += delimiter + item; + }); + return str; +}; + +/** + * Remove floating-point numbers leading zero. + * + * @example + * 0.5 → .5 + * + * @example + * -0.5 → -.5 + * + * @param {Float} num input number + * + * @return {String} output number as string + */ +var removeLeadingZero = exports.removeLeadingZero = function(num) { + var strNum = num.toString(); + + if (0 < num && num < 1 && strNum.charCodeAt(0) == 48) { + strNum = strNum.slice(1); + } else if (-1 < num && num < 0 && strNum.charCodeAt(1) == 48) { + strNum = strNum.charAt(0) + strNum.slice(2); + } + return strNum; +}; diff --git a/vendor/svgclean/test.js b/vendor/svgclean/test.js new file mode 100644 index 000000000..b37ab9d65 --- /dev/null +++ b/vendor/svgclean/test.js @@ -0,0 +1,8 @@ +const svgclean = require("./src/svgclean"); +const fs = require("fs"); + +fs.readFile("./test.svg", "utf-8", (err, data) => { + svgclean.optimize({}, data).then((result) => { + console.dir(result); + }); +}); diff --git a/vendor/svgclean/test.svg b/vendor/svgclean/test.svg new file mode 100644 index 000000000..c539cd408 --- /dev/null +++ b/vendor/svgclean/test.svg @@ -0,0 +1,3 @@ +<svg version="1.1" width="10" height="20"> + test +</svg>