From 9f350cdcb378ea11ad0f6cdfa24176cdcc2aa05c Mon Sep 17 00:00:00 2001 From: Alexander <9622929+Yatskov@users.noreply.github.com> Date: Thu, 27 Feb 2020 16:37:28 +0300 Subject: [PATCH] Added webpack and es6 support. (#8) * First commit for webpack build. * More edits for webpack commit. * Updated SelectorTable after it merge to webpack. And removed old files. * Fixed options. * Browser polyfill now es6 imports. * Added support for Id hints. (#11) * Id hints moved to webpack. * Made hints work. * Current Selector id fix. * Quick fix for empty model. * Fixed some bugs connected with sitemap model validation and existing selector change in sitemap when changed type. * fixed bug with sitemap id updates * moved model_example to templates * fixed selectors and graph being not available after scrape Co-authored-by: Max Varlamov <47754003+mxsnq@users.noreply.github.com> * Quick fix for charsets. * fix to validate URLs with date/numeric ranges (#12) * fix to validate URLs with date/numeric ranges * rewritten using URL module * Import validation (#14) * Fixed validation for import sitemap. * Version ++ and merge urls into branch. * start urls must not be empty Co-authored-by: Max Varlamov <47754003+mxsnq@users.noreply.github.com> Co-authored-by: Max Varlamov <47754003+mxsnq@users.noreply.github.com> --- .babelrc | 15 + .eslintrc.js | 45 + .gitignore | 2 + .gitmodules | 3 - .prettierrc | 10 + extension/assets/ICanHaz.js | 552 - extension/assets/LICENSE-d3-js | 26 - extension/assets/LICENSE-icanhaz-js | 26 - extension/assets/LICENSE-jquery-js | 21 - extension/assets/LICENSE-pouchdb-js | 227 - extension/assets/LICENSE-sugar-js | 5 - extension/assets/base64.js | 36 - .../bootstrap-3.0.0/css/bootstrap-theme.css | 384 - .../css/bootstrap-theme.min.css | 1 - .../assets/bootstrap-3.0.0/css/bootstrap.css | 6805 ------------ .../bootstrap-3.0.0/css/bootstrap.min.css | 9 - .../fonts/glyphicons-halflings-regular.eot | Bin 14079 -> 0 bytes .../fonts/glyphicons-halflings-regular.svg | 228 - .../fonts/glyphicons-halflings-regular.ttf | Bin 29512 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 16448 -> 0 bytes .../assets/bootstrap-3.0.0/js/bootstrap.js | 1999 ---- .../bootstrap-3.0.0/js/bootstrap.min.js | 6 - extension/assets/css-selector | 1 - extension/assets/d3.v3.js | 9234 ----------------- extension/assets/d3.v3.min.js | 5 - extension/assets/jquery-2.0.3.js | 8829 ---------------- .../bootstrapValidator.js | 6478 ------------ extension/assets/papaparse.min.js | 6 - extension/assets/pouchdb-nightly.min.js | 4 - extension/assets/sugar-1.4.1.js | 136 - .../background_page/background_script.js | 132 - extension/content_script/content_script.js | 43 - extension/devtools/devtools_init_page.html | 5 - extension/devtools/devtools_init_page.js | 1 - extension/devtools/devtools_scraper_panel.css | 90 - .../devtools/devtools_scraper_panel.html | 50 - extension/devtools/views/SelectorEdit.html | 307 - extension/devtools/views/SitemapCreate.html | 22 - .../devtools/views/SitemapEditMetadata.html | 81 - .../devtools/views/SitemapExportDataCSV.html | 24 - extension/devtools/views/SitemapList.html | 13 - .../devtools/views/SitemapSelectorGraph.html | 1 - extension/devtools/views/Viewport.html | 33 - extension/manifest.json | 123 - extension/options_page/options_page.js | 106 - extension/popup.html | 30 - extension/scripts/App.js | 11 - extension/scripts/ChromePopupBrowser.js | 91 - extension/scripts/Config.js | 56 - extension/scripts/ContentScript.js | 144 - extension/scripts/ContentSelector.js | 397 - extension/scripts/Controller.js | 1490 --- extension/scripts/DataExtractor.js | 322 - .../scripts/DateUtils/SimpleDateFormatter.js | 111 - extension/scripts/ElementQuery.js | 60 - extension/scripts/Job.js | 84 - extension/scripts/Scraper.js | 212 - extension/scripts/Selector.js | 310 - extension/scripts/Selector/ConstantValue.js | 40 - .../scripts/Selector/SelectorDocument.js | 95 - extension/scripts/Selector/SelectorElement.js | 39 - .../Selector/SelectorElementAttribute.js | 51 - .../scripts/Selector/SelectorElementClick.js | 179 - .../scripts/Selector/SelectorElementScroll.js | 71 - .../scripts/Selector/SelectorElementStyle.js | 49 - extension/scripts/Selector/SelectorGroup.js | 59 - extension/scripts/Selector/SelectorHTML.js | 56 - extension/scripts/Selector/SelectorImage.js | 94 - .../scripts/Selector/SelectorInputValue.js | 51 - extension/scripts/Selector/SelectorLink.js | 83 - .../scripts/Selector/SelectorPopupLink.js | 148 - extension/scripts/Selector/SelectorTable.js | 282 - extension/scripts/Selector/SelectorText.js | 58 - extension/scripts/SelectorGraph.js | 149 - extension/scripts/SelectorGraphv2.js | 219 - extension/scripts/SelectorList.js | 281 - extension/scripts/Sitemap.js | 260 - extension/scripts/StoreDevtools.js | 73 - extension/scripts/StorePouchDB.js | 161 - extension/scripts/StoreRestApi.js | 99 - extension/scripts/UniqueElementList.js | 112 - package-lock.json | 3447 ++++++ package.json | 66 + playgrounds/extension/tables.html | 541 +- scripts/build-zip.js | 53 + src/background/background.js | 128 + .../content_script/content_script.css | 86 +- src/content_script/content_script.js | 44 + src/devtools/devtools.html | 9 + src/devtools/devtools.js | 10 + src/devtools/panel.css | 102 + src/devtools/panel.html | 9 + .../devtools/views/DataPreview.html | 19 +- src/devtools/views/SelectorEdit.html | 350 + .../views/SelectorEditTableColumn.html | 6 +- .../devtools/views/SelectorList.html | 18 +- .../devtools/views/SelectorListItem.html | 2 +- .../devtools/views/SitemapBrowseData.html | 15 +- src/devtools/views/SitemapCreate.html | 95 + src/devtools/views/SitemapEditMetadata.html | 97 + .../devtools/views/SitemapExport.html | 2 +- src/devtools/views/SitemapExportDataCSV.html | 24 + .../devtools/views/SitemapImport.html | 4 +- src/devtools/views/SitemapList.html | 12 + .../devtools/views/SitemapListItem.html | 6 +- .../devtools/views/SitemapScrapeConfig.html | 8 +- src/devtools/views/SitemapSelectorGraph.html | 1 + src/devtools/views/Viewport.html | 33 + .../assets/images => src/icons}/LICENSE | 0 .../assets/images => src/icons}/icon128.png | Bin .../assets/images => src/icons}/icon16.png | Bin .../assets/images => src/icons}/icon19.png | Bin .../assets/images => src/icons}/icon38.png | Bin .../assets/images => src/icons}/icon48.png | Bin src/libs/css-selector/lib/CssSelector.js | 306 + src/libs/css-selector/lib/ElementSelector.js | 126 + .../css-selector/lib/ElementSelectorList.js | 40 + .../bootstrapValidator.css | 8 +- .../bootstrapValidator.js | 6738 ++++++++++++ .../libs}/jquery.whencallsequentially.js | 9 +- src/manifest.json | 45 + .../options_page => src/options}/options.html | 40 +- src/options/options.js | 102 + src/popup/popup.html | 29 + src/scripts/App.js | 14 + .../scripts/BackgroundScript.js | 78 +- src/scripts/ChromePopupBrowser.js | 92 + src/scripts/Config.js | 52 + src/scripts/ContentScript.js | 148 + src/scripts/ContentSelector.js | 399 + src/scripts/Controller.js | 1665 +++ src/scripts/DataExtractor.js | 328 + .../scripts/DateUtils/DatePatternSupport.js | 45 +- .../scripts/DateUtils/DateRoller.js | 25 +- src/scripts/DateUtils/SimpleDateFormatter.js | 111 + src/scripts/ElementQuery.js | 55 + src/scripts/Job.js | 87 + src/scripts/Model.js | 28 + {extension => src}/scripts/Queue.js | 42 +- src/scripts/Scraper.js | 213 + src/scripts/Selector.js | 313 + src/scripts/Selector/ConstantValue.js | 45 + src/scripts/Selector/SelectorDocument.js | 102 + src/scripts/Selector/SelectorElement.js | 45 + .../Selector/SelectorElementAttribute.js | 61 + src/scripts/Selector/SelectorElementClick.js | 176 + src/scripts/Selector/SelectorElementScroll.js | 79 + src/scripts/Selector/SelectorElementStyle.js | 59 + src/scripts/Selector/SelectorGroup.js | 68 + src/scripts/Selector/SelectorHTML.js | 65 + src/scripts/Selector/SelectorImage.js | 108 + src/scripts/Selector/SelectorInputValue.js | 56 + src/scripts/Selector/SelectorLink.js | 94 + src/scripts/Selector/SelectorPopupLink.js | 162 + src/scripts/Selector/SelectorTable.js | 297 + src/scripts/Selector/SelectorText.js | 67 + src/scripts/SelectorGraph.js | 198 + src/scripts/SelectorGraphv2.js | 234 + src/scripts/SelectorList.js | 330 + src/scripts/Sitemap.js | 270 + src/scripts/StoreDevtools.js | 72 + src/scripts/StorePouchDB.js | 191 + src/scripts/StoreRestApi.js | 116 + src/scripts/UniqueElementList.js | 117 + webpack.config.js | 126 + yarn.lock | 6796 ++++++++++++ 166 files changed, 25839 insertions(+), 42571 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintrc.js delete mode 100644 .gitmodules create mode 100644 .prettierrc delete mode 100644 extension/assets/ICanHaz.js delete mode 100644 extension/assets/LICENSE-d3-js delete mode 100644 extension/assets/LICENSE-icanhaz-js delete mode 100644 extension/assets/LICENSE-jquery-js delete mode 100644 extension/assets/LICENSE-pouchdb-js delete mode 100644 extension/assets/LICENSE-sugar-js delete mode 100644 extension/assets/base64.js delete mode 100644 extension/assets/bootstrap-3.0.0/css/bootstrap-theme.css delete mode 100644 extension/assets/bootstrap-3.0.0/css/bootstrap-theme.min.css delete mode 100644 extension/assets/bootstrap-3.0.0/css/bootstrap.css delete mode 100644 extension/assets/bootstrap-3.0.0/css/bootstrap.min.css delete mode 100644 extension/assets/bootstrap-3.0.0/fonts/glyphicons-halflings-regular.eot delete mode 100644 extension/assets/bootstrap-3.0.0/fonts/glyphicons-halflings-regular.svg delete mode 100644 extension/assets/bootstrap-3.0.0/fonts/glyphicons-halflings-regular.ttf delete mode 100644 extension/assets/bootstrap-3.0.0/fonts/glyphicons-halflings-regular.woff delete mode 100644 extension/assets/bootstrap-3.0.0/js/bootstrap.js delete mode 100644 extension/assets/bootstrap-3.0.0/js/bootstrap.min.js delete mode 160000 extension/assets/css-selector delete mode 100644 extension/assets/d3.v3.js delete mode 100644 extension/assets/d3.v3.min.js delete mode 100644 extension/assets/jquery-2.0.3.js delete mode 100644 extension/assets/jquery.bootstrapvalidator/bootstrapValidator.js delete mode 100644 extension/assets/papaparse.min.js delete mode 100644 extension/assets/pouchdb-nightly.min.js delete mode 100644 extension/assets/sugar-1.4.1.js delete mode 100644 extension/background_page/background_script.js delete mode 100644 extension/content_script/content_script.js delete mode 100644 extension/devtools/devtools_init_page.html delete mode 100644 extension/devtools/devtools_init_page.js delete mode 100644 extension/devtools/devtools_scraper_panel.css delete mode 100644 extension/devtools/devtools_scraper_panel.html delete mode 100644 extension/devtools/views/SelectorEdit.html delete mode 100644 extension/devtools/views/SitemapCreate.html delete mode 100644 extension/devtools/views/SitemapEditMetadata.html delete mode 100644 extension/devtools/views/SitemapExportDataCSV.html delete mode 100644 extension/devtools/views/SitemapList.html delete mode 100644 extension/devtools/views/SitemapSelectorGraph.html delete mode 100644 extension/devtools/views/Viewport.html delete mode 100644 extension/manifest.json delete mode 100644 extension/options_page/options_page.js delete mode 100644 extension/popup.html delete mode 100644 extension/scripts/App.js delete mode 100644 extension/scripts/ChromePopupBrowser.js delete mode 100644 extension/scripts/Config.js delete mode 100644 extension/scripts/ContentScript.js delete mode 100644 extension/scripts/ContentSelector.js delete mode 100644 extension/scripts/Controller.js delete mode 100644 extension/scripts/DataExtractor.js delete mode 100644 extension/scripts/DateUtils/SimpleDateFormatter.js delete mode 100644 extension/scripts/ElementQuery.js delete mode 100644 extension/scripts/Job.js delete mode 100644 extension/scripts/Scraper.js delete mode 100644 extension/scripts/Selector.js delete mode 100644 extension/scripts/Selector/ConstantValue.js delete mode 100644 extension/scripts/Selector/SelectorDocument.js delete mode 100644 extension/scripts/Selector/SelectorElement.js delete mode 100644 extension/scripts/Selector/SelectorElementAttribute.js delete mode 100644 extension/scripts/Selector/SelectorElementClick.js delete mode 100644 extension/scripts/Selector/SelectorElementScroll.js delete mode 100644 extension/scripts/Selector/SelectorElementStyle.js delete mode 100644 extension/scripts/Selector/SelectorGroup.js delete mode 100644 extension/scripts/Selector/SelectorHTML.js delete mode 100644 extension/scripts/Selector/SelectorImage.js delete mode 100644 extension/scripts/Selector/SelectorInputValue.js delete mode 100644 extension/scripts/Selector/SelectorLink.js delete mode 100644 extension/scripts/Selector/SelectorPopupLink.js delete mode 100644 extension/scripts/Selector/SelectorTable.js delete mode 100644 extension/scripts/Selector/SelectorText.js delete mode 100644 extension/scripts/SelectorGraph.js delete mode 100644 extension/scripts/SelectorGraphv2.js delete mode 100644 extension/scripts/SelectorList.js delete mode 100644 extension/scripts/Sitemap.js delete mode 100644 extension/scripts/StoreDevtools.js delete mode 100644 extension/scripts/StorePouchDB.js delete mode 100644 extension/scripts/StoreRestApi.js delete mode 100644 extension/scripts/UniqueElementList.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/build-zip.js create mode 100644 src/background/background.js rename {extension => src}/content_script/content_script.css (94%) create mode 100644 src/content_script/content_script.js create mode 100644 src/devtools/devtools.html create mode 100644 src/devtools/devtools.js create mode 100644 src/devtools/panel.css create mode 100644 src/devtools/panel.html rename {extension => src}/devtools/views/DataPreview.html (73%) create mode 100644 src/devtools/views/SelectorEdit.html rename {extension => src}/devtools/views/SelectorEditTableColumn.html (73%) rename {extension => src}/devtools/views/SelectorList.html (62%) rename {extension => src}/devtools/views/SelectorListItem.html (98%) rename {extension => src}/devtools/views/SitemapBrowseData.html (56%) create mode 100644 src/devtools/views/SitemapCreate.html create mode 100644 src/devtools/views/SitemapEditMetadata.html rename {extension => src}/devtools/views/SitemapExport.html (96%) create mode 100644 src/devtools/views/SitemapExportDataCSV.html rename {extension => src}/devtools/views/SitemapImport.html (91%) create mode 100644 src/devtools/views/SitemapList.html rename {extension => src}/devtools/views/SitemapListItem.html (87%) rename {extension => src}/devtools/views/SitemapScrapeConfig.html (88%) create mode 100644 src/devtools/views/SitemapSelectorGraph.html create mode 100644 src/devtools/views/Viewport.html rename {extension/assets/images => src/icons}/LICENSE (100%) rename {extension/assets/images => src/icons}/icon128.png (100%) rename {extension/assets/images => src/icons}/icon16.png (100%) rename {extension/assets/images => src/icons}/icon19.png (100%) rename {extension/assets/images => src/icons}/icon38.png (100%) rename {extension/assets/images => src/icons}/icon48.png (100%) create mode 100644 src/libs/css-selector/lib/CssSelector.js create mode 100644 src/libs/css-selector/lib/ElementSelector.js create mode 100644 src/libs/css-selector/lib/ElementSelectorList.js rename {extension/assets => src/libs}/jquery.bootstrapvalidator/bootstrapValidator.css (82%) create mode 100644 src/libs/jquery.bootstrapvalidator/bootstrapValidator.js rename {extension/assets => src/libs}/jquery.whencallsequentially.js (85%) create mode 100644 src/manifest.json rename {extension/options_page => src/options}/options.html (59%) create mode 100644 src/options/options.js create mode 100644 src/popup/popup.html create mode 100644 src/scripts/App.js rename {extension => src}/scripts/BackgroundScript.js (56%) create mode 100644 src/scripts/ChromePopupBrowser.js create mode 100644 src/scripts/Config.js create mode 100644 src/scripts/ContentScript.js create mode 100644 src/scripts/ContentSelector.js create mode 100644 src/scripts/Controller.js create mode 100644 src/scripts/DataExtractor.js rename {extension => src}/scripts/DateUtils/DatePatternSupport.js (56%) rename {extension => src}/scripts/DateUtils/DateRoller.js (74%) create mode 100644 src/scripts/DateUtils/SimpleDateFormatter.js create mode 100644 src/scripts/ElementQuery.js create mode 100644 src/scripts/Job.js create mode 100644 src/scripts/Model.js rename {extension => src}/scripts/Queue.js (61%) create mode 100644 src/scripts/Scraper.js create mode 100644 src/scripts/Selector.js create mode 100644 src/scripts/Selector/ConstantValue.js create mode 100644 src/scripts/Selector/SelectorDocument.js create mode 100644 src/scripts/Selector/SelectorElement.js create mode 100644 src/scripts/Selector/SelectorElementAttribute.js create mode 100644 src/scripts/Selector/SelectorElementClick.js create mode 100644 src/scripts/Selector/SelectorElementScroll.js create mode 100644 src/scripts/Selector/SelectorElementStyle.js create mode 100644 src/scripts/Selector/SelectorGroup.js create mode 100644 src/scripts/Selector/SelectorHTML.js create mode 100644 src/scripts/Selector/SelectorImage.js create mode 100644 src/scripts/Selector/SelectorInputValue.js create mode 100644 src/scripts/Selector/SelectorLink.js create mode 100644 src/scripts/Selector/SelectorPopupLink.js create mode 100644 src/scripts/Selector/SelectorTable.js create mode 100644 src/scripts/Selector/SelectorText.js create mode 100644 src/scripts/SelectorGraph.js create mode 100644 src/scripts/SelectorGraphv2.js create mode 100644 src/scripts/SelectorList.js create mode 100644 src/scripts/Sitemap.js create mode 100644 src/scripts/StoreDevtools.js create mode 100644 src/scripts/StorePouchDB.js create mode 100644 src/scripts/StoreRestApi.js create mode 100644 src/scripts/UniqueElementList.js create mode 100644 webpack.config.js create mode 100644 yarn.lock diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..e93edff6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,15 @@ +{ + "plugins": [ + "@babel/plugin-proposal-optional-chaining" + ], + "presets": [ + ["@babel/preset-env", { + "useBuiltIns": "usage", + "corejs": 3, + "targets": { + // https://jamie.build/last-2-versions + "browsers": ["> 0.25%", "not ie 11", "not op_mini all"] + } + }] + ] +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..08829e16 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,45 @@ +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + }, + env: { + browser: true, + webextensions: true, + }, + extends: ['airbnb-base', 'plugin:prettier/recommended'], + settings: { + 'import/resolver': { + webpack: { + config: './webpack.config.js', + }, + }, + }, + // add your custom rules here + rules: { + // don't require .vue extension when importing + 'import/extensions': [ + 'error', + 'always', + { + js: 'never', + }, + ], + // disallow reassignment of function parameters + // disallow parameter object manipulation except for specific exclusions + 'no-param-reassign': [ + 'error', + { + props: true, + ignorePropertyModificationsFor: [ + 'acc', // for reduce accumulators + 'e', // for e.returnvalue + ], + }, + ], + // disallow default export over named export + 'import/prefer-default-export': 'off', + // allow debugger during development + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + }, +}; diff --git a/.gitignore b/.gitignore index 6bfbc72a..5134015d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .idea projectFilesBackup extension.zip +dist +node_modules /.vs/web-scraper-chrome-extension/v15/.suo /.vs/web-scraper-chrome-extension/v15 diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index c361ff9c..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "extension/assets/css-selector"] - path = extension/assets/css-selector - url = https://github.com/martinsbalodis/css-selector.git diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..15f8ea92 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "arrowParens": "avoid", + "bracketSpacing": true, + "printWidth": 180, + "semi": true, + "singleQuote": true, + "tabWidth": 4, + "trailingComma": "es5", + "useTabs": true +} diff --git a/extension/assets/ICanHaz.js b/extension/assets/ICanHaz.js deleted file mode 100644 index abd9541e..00000000 --- a/extension/assets/ICanHaz.js +++ /dev/null @@ -1,552 +0,0 @@ -/*! - ICanHaz.js version 0.10.2 -- by @HenrikJoreteg - More info at: http://icanhazjs.com - */ -(function () { - /* - mustache.js — Logic-less templates in JavaScript - - See http://mustache.github.com/ for more info. - */ - - var Mustache = function () { - var _toString = Object.prototype.toString; - - Array.isArray = Array.isArray || function (obj) { - return _toString.call(obj) == "[object Array]"; - } - - var _trim = String.prototype.trim, trim; - - if (_trim) { - trim = function (text) { - return text == null ? "" : _trim.call(text); - } - } else { - var trimLeft, trimRight; - - // IE doesn't match non-breaking spaces with \s. - if ((/\S/).test("\xA0")) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; - } else { - trimLeft = /^\s+/; - trimRight = /\s+$/; - } - - trim = function (text) { - return text == null ? "" : - text.toString().replace(trimLeft, "").replace(trimRight, ""); - } - } - - var escapeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - - function escapeHTML(string) { - return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { - return escapeMap[s] || s; - }); - } - - var regexCache = {}; - var Renderer = function () {}; - - Renderer.prototype = { - otag: "{{", - ctag: "}}", - pragmas: {}, - buffer: [], - pragmas_implemented: { - "IMPLICIT-ITERATOR": true - }, - context: {}, - - render: function (template, context, partials, in_recursion) { - // reset buffer & set context - if (!in_recursion) { - this.context = context; - this.buffer = []; // TODO: make this non-lazy - } - - // fail fast - if (!this.includes("", template)) { - if (in_recursion) { - return template; - } else { - this.send(template); - return; - } - } - - // get the pragmas together - template = this.render_pragmas(template); - - // render the template - var html = this.render_section(template, context, partials); - - // render_section did not find any sections, we still need to render the tags - if (html === false) { - html = this.render_tags(template, context, partials, in_recursion); - } - - if (in_recursion) { - return html; - } else { - this.sendLines(html); - } - }, - - /* - Sends parsed lines - */ - send: function (line) { - if (line !== "") { - this.buffer.push(line); - } - }, - - sendLines: function (text) { - if (text) { - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) { - this.send(lines[i]); - } - } - }, - - /* - Looks for %PRAGMAS - */ - render_pragmas: function (template) { - // no pragmas - if (!this.includes("%", template)) { - return template; - } - - var that = this; - var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { - return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); - }); - - return template.replace(regex, function (match, pragma, options) { - if (!that.pragmas_implemented[pragma]) { - throw({message: - "This implementation of mustache doesn't understand the '" + - pragma + "' pragma"}); - } - that.pragmas[pragma] = {}; - if (options) { - var opts = options.split("="); - that.pragmas[pragma][opts[0]] = opts[1]; - } - return ""; - // ignore unknown pragmas silently - }); - }, - - /* - Tries to find a partial in the curent scope and render it - */ - render_partial: function (name, context, partials) { - name = trim(name); - if (!partials || partials[name] === undefined) { - throw({message: "unknown_partial '" + name + "'"}); - } - if (!context || typeof context[name] != "object") { - return this.render(partials[name], context, partials, true); - } - return this.render(partials[name], context[name], partials, true); - }, - - /* - Renders inverted (^) and normal (#) sections - */ - render_section: function (template, context, partials) { - if (!this.includes("#", template) && !this.includes("^", template)) { - // did not render anything, there were no sections - return false; - } - - var that = this; - - var regex = this.getCachedRegex("render_section", function (otag, ctag) { - // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder - return new RegExp( - "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) - - otag + // {{ - "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) - ctag + // }} - - "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped - - otag + // {{ - "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). - ctag + // }} - - "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. - - "g"); - }); - - - // for each {{#foo}}{{/foo}} section do... - return template.replace(regex, function (match, before, type, name, content, after) { - // before contains only tags, no sections - var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", - - // after may contain both sections and tags, so use full rendering function - renderedAfter = after ? that.render(after, context, partials, true) : "", - - // will be computed below - renderedContent, - - value = that.find(name, context); - - if (type === "^") { // inverted section - if (!value || Array.isArray(value) && value.length === 0) { - // false or empty list, render it - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } else if (type === "#") { // normal section - if (Array.isArray(value)) { // Enumerable, Let's loop! - renderedContent = that.map(value, function (row) { - return that.render(content, that.create_context(row), partials, true); - }).join(""); - } else if (that.is_object(value)) { // Object, Use it as subcontext! - renderedContent = that.render(content, that.create_context(value), - partials, true); - } else if (typeof value == "function") { - // higher order section - renderedContent = value.call(context, content, function (text) { - return that.render(text, context, partials, true); - }); - } else if (value) { // boolean section - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } - - return renderedBefore + renderedContent + renderedAfter; - }); - }, - - /* - Replace {{foo}} and friends with values from our view - */ - render_tags: function (template, context, partials, in_recursion) { - // tit for tat - var that = this; - - var new_regex = function () { - return that.getCachedRegex("render_tags", function (otag, ctag) { - return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); - }); - }; - - var regex = new_regex(); - var tag_replace_callback = function (match, operator, name) { - switch(operator) { - case "!": // ignore comments - return ""; - case "=": // set new delimiters, rebuild the replace regexp - that.set_delimiters(name); - regex = new_regex(); - return ""; - case ">": // render partial - return that.render_partial(name, context, partials); - case "{": // the triple mustache is unescaped - case "&": // & operator is an alternative unescape method - return that.find(name, context); - default: // escape the value - return escapeHTML(that.find(name, context)); - } - }; - var lines = template.split("\n"); - for(var i = 0; i < lines.length; i++) { - lines[i] = lines[i].replace(regex, tag_replace_callback, this); - if (!in_recursion) { - this.send(lines[i]); - } - } - - if (in_recursion) { - return lines.join("\n"); - } - }, - - set_delimiters: function (delimiters) { - var dels = delimiters.split(" "); - this.otag = this.escape_regex(dels[0]); - this.ctag = this.escape_regex(dels[1]); - }, - - escape_regex: function (text) { - // thank you Simon Willison - if (!arguments.callee.sRE) { - var specials = [ - '/', '.', '*', '+', '?', '|', - '(', ')', '[', ']', '{', '}', '\\' - ]; - arguments.callee.sRE = new RegExp( - '(\\' + specials.join('|\\') + ')', 'g' - ); - } - return text.replace(arguments.callee.sRE, '\\$1'); - }, - - /* - find `name` in current `context`. That is find me a value - from the view object - */ - find: function (name, context) { - name = trim(name); - - // Checks whether a value is thruthy or false or 0 - function is_kinda_truthy(bool) { - return bool === false || bool === 0 || bool; - } - - var value; - - // check for dot notation eg. foo.bar - if (name.match(/([a-z_]+)\./ig)) { - var childValue = this.walk_context(name, context); - if (is_kinda_truthy(childValue)) { - value = childValue; - } - } else { - if (is_kinda_truthy(context[name])) { - value = context[name]; - } else if (is_kinda_truthy(this.context[name])) { - value = this.context[name]; - } - } - - if (typeof value == "function") { - return value.apply(context); - } - if (value !== undefined) { - return value; - } - // silently ignore unkown variables - return ""; - }, - - walk_context: function (name, context) { - var path = name.split('.'); - // if the var doesn't exist in current context, check the top level context - var value_context = (context[path[0]] != undefined) ? context : this.context; - var value = value_context[path.shift()]; - while (value != undefined && path.length > 0) { - value_context = value; - value = value[path.shift()]; - } - // if the value is a function, call it, binding the correct context - if (typeof value == "function") { - return value.apply(value_context); - } - return value; - }, - - // Utility methods - - /* includes tag */ - includes: function (needle, haystack) { - return haystack.indexOf(this.otag + needle) != -1; - }, - - // by @langalex, support for arrays of strings - create_context: function (_context) { - if (this.is_object(_context)) { - return _context; - } else { - var iterator = "."; - if (this.pragmas["IMPLICIT-ITERATOR"]) { - iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; - } - var ctx = {}; - ctx[iterator] = _context; - return ctx; - } - }, - - is_object: function (a) { - return a && typeof a == "object"; - }, - - /* - Why, why, why? Because IE. Cry, cry cry. - */ - map: function (array, fn) { - if (typeof array.map == "function") { - return array.map(fn); - } else { - var r = []; - var l = array.length; - for(var i = 0; i < l; i++) { - r.push(fn(array[i])); - } - return r; - } - }, - - getCachedRegex: function (name, generator) { - var byOtag = regexCache[this.otag]; - if (!byOtag) { - byOtag = regexCache[this.otag] = {}; - } - - var byCtag = byOtag[this.ctag]; - if (!byCtag) { - byCtag = byOtag[this.ctag] = {}; - } - - var regex = byCtag[name]; - if (!regex) { - regex = byCtag[name] = generator(this.otag, this.ctag); - } - - return regex; - } - }; - - return({ - name: "mustache.js", - version: "0.4.0", - - /* - Turns a template and view into HTML - */ - to_html: function (template, view, partials, send_fun) { - var renderer = new Renderer(); - if (send_fun) { - renderer.send = send_fun; - } - renderer.render(template, view || {}, partials); - if (!send_fun) { - return renderer.buffer.join("\n"); - } - } - }); - }(); - /*! - ICanHaz.js -- by @HenrikJoreteg - */ - /*global */ - (function () { - function trim(stuff) { - if (''.trim) return stuff.trim(); - else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - var ich = { - VERSION: "0.10.2", - templates: {}, - - // grab jquery or zepto if it's there - $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, - - // public function for adding templates - // can take a name and template string arguments - // or can take an object with name/template pairs - // We're enforcing uniqueness to avoid accidental template overwrites. - // If you want a different template, it should have a different name. - addTemplate: function (name, templateString) { - if (typeof name === 'object') { - for (var template in name) { - this.addTemplate(template, name[template]); - } - return; - } - if (ich[name]) { - console.error("Invalid name: " + name + "."); - } else if (ich.templates[name]) { - console.error("Template \"" + name + " \" exists"); - } else { - ich.templates[name] = templateString; - ich[name] = function (data, raw) { - data = data || {}; - var result = Mustache.to_html(ich.templates[name], data, ich.templates); - return (ich.$ && !raw) ? ich.$(trim(result)) : result; - }; - } - }, - - // clears all retrieval functions and empties cache - clearAll: function () { - for (var key in ich.templates) { - delete ich[key]; - } - ich.templates = {}; - }, - - // clears/grabs - refresh: function () { - ich.clearAll(); - ich.grabTemplates(); - }, - - // grabs templates from the DOM and caches them. - // Loop through and add templates. - // Whitespace at beginning and end of all templates inside - - \ No newline at end of file diff --git a/extension/devtools/devtools_init_page.js b/extension/devtools/devtools_init_page.js deleted file mode 100644 index 933883fd..00000000 --- a/extension/devtools/devtools_init_page.js +++ /dev/null @@ -1 +0,0 @@ -chrome.devtools.panels.create("Web Scraper", "../assets/images/icon48.png", "devtools/devtools_scraper_panel.html"); \ No newline at end of file diff --git a/extension/devtools/devtools_scraper_panel.css b/extension/devtools/devtools_scraper_panel.css deleted file mode 100644 index e3bacc8f..00000000 --- a/extension/devtools/devtools_scraper_panel.css +++ /dev/null @@ -1,90 +0,0 @@ -/*body > form, body > div {*/ - /*display:none;*/ -/*}*/ - -a, tbody tr { - cursor: pointer; -} - - -.selector-list-tpl, .sitemap-list-tpl { - display:none -} - -/** - * Compact elements - */ -.navbar-nav>li>a { - padding-top: 3px; - padding-bottom: 3px; -} - -.navbar-text { - margin-top:4px; - margin-bottom:4px; - padding-right:3px; -} - -.navbar { - min-height:26px; - margin-bottom: 6px; -} -.table-condensed tbody>tr>td { - padding:1px 5px; -} - -body { - font-size: 12px; -} - -form .form-control { - font-size: 12px; - padding: 3px 12px; - height: 25px; -} - -textarea.form-control { - height: auto; -} - -form .btn { - font-size: 12px; - padding: 3px 12px; -} - -form .form-group { - margin-bottom:5px; -} - -form select[multiple], select[size] { - height: auto; -} - -#selector-graph .node circle { - cursor: pointer; - fill: #fff; - stroke: steelblue; - stroke-width: 1px; -} - -#selector-graph .node text { - font-size: 11px; -} - -#selector-graph path.link { - fill: none; - stroke: #ccc; - stroke-width: 1px; -} - -.data-preview-modal .modal-dialog { - width:auto; -} - -.data-preview-modal .modal-body { - overflow-y:scroll; -} - -.data-preview-modal tbody tr { - cursor: initial; -} \ No newline at end of file diff --git a/extension/devtools/devtools_scraper_panel.html b/extension/devtools/devtools_scraper_panel.html deleted file mode 100644 index 2f6f11de..00000000 --- a/extension/devtools/devtools_scraper_panel.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extension/devtools/views/SelectorEdit.html b/extension/devtools/views/SelectorEdit.html deleted file mode 100644 index 773225c5..00000000 --- a/extension/devtools/views/SelectorEdit.html +++ /dev/null @@ -1,307 +0,0 @@ -
- -
- - -
- -
-
- -
- - -
- -
-
- -
- - -
-
- - - - - - -
-
-
- -
- - -
-
- - - - - -
-
-
- - - -
- -
-
- - - - - - -
-
-
- - -
- -
-
- - - - - -
-
-
- - -
- -
-
- -
-
-
- - -
- -
-
- -
-
-
- - -
- - -
- -
-
- - -
- - -
- -
-
- - -
- -
- -
-
- -
- -
-
- -
-
-
- - -
- -
-
- -
-
-
- - -
- -
-
- -
-
-
- -
- -
-
- -
-
-
- - -
- - -
- -
-
- - -
- - -
- -
-
- - -
- - -
- -
-
- -
- -
-
- - - Trim will be applied before regex. -
-
- -
-
- -
-
- - -
-
- - -
-
-
- -
- - -
- -
-
- -
- - -
-
- - -
-
-
- -
- - -
- -
-
- -
- - -
- - - - - - - - - - {{#selector.columns}} - - - - - - {{/selector.columns}} - -
ColumnResult keyInclude into result
{{header}}
-
-
- -
-
- -
-
- -
-
- -
-
-
\ No newline at end of file diff --git a/extension/devtools/views/SitemapCreate.html b/extension/devtools/views/SitemapCreate.html deleted file mode 100644 index 4f30c7ac..00000000 --- a/extension/devtools/views/SitemapCreate.html +++ /dev/null @@ -1,22 +0,0 @@ -
-
- - -
- -
-
-
- -
-
- -
-
-
-
-
- -
-
-
\ No newline at end of file diff --git a/extension/devtools/views/SitemapEditMetadata.html b/extension/devtools/views/SitemapEditMetadata.html deleted file mode 100644 index dba31019..00000000 --- a/extension/devtools/views/SitemapEditMetadata.html +++ /dev/null @@ -1,81 +0,0 @@ -
-
-
- - -
- -
-
-
- -
-
- -
-
-
- -
- Supported URL patterns:
- 1. Numeric with optional step and zero padding – [START-END:STEP] – [001-010:10]
- 2. Date interval – [date<PATTERN><START><END>] – [date<dd.MM.yyyy><01.01.2017><now>]
-
    - date placeholder may be yesterday / now / tomorrow
    - other template components (in Java style) -
      - - - - - - - - - - - - - - - - - - - - - - - - -
      yyyyfull year (4 digits)
      yylast 2 digits of year
      MMM  Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
      MMmonth number (01-12)
      ddday of month
      -
    -
-
- -
-
- -
-
-
-
\ No newline at end of file diff --git a/extension/devtools/views/SitemapExportDataCSV.html b/extension/devtools/views/SitemapExportDataCSV.html deleted file mode 100644 index 2496c4fa..00000000 --- a/extension/devtools/views/SitemapExportDataCSV.html +++ /dev/null @@ -1,24 +0,0 @@ -
Console
- -

Export {{_id}} data as CSV

-
- - - -
- - - -
- - - -
- - -
-
- -

- Waiting for process to finish. > Download now! -

diff --git a/extension/devtools/views/SitemapList.html b/extension/devtools/views/SitemapList.html deleted file mode 100644 index 9112e071..00000000 --- a/extension/devtools/views/SitemapList.html +++ /dev/null @@ -1,13 +0,0 @@ -
- - - - - - - - - - -
IDStart URLactions
-
\ No newline at end of file diff --git a/extension/devtools/views/SitemapSelectorGraph.html b/extension/devtools/views/SitemapSelectorGraph.html deleted file mode 100644 index 40320ca9..00000000 --- a/extension/devtools/views/SitemapSelectorGraph.html +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/extension/devtools/views/Viewport.html b/extension/devtools/views/Viewport.html deleted file mode 100644 index 23fe9da4..00000000 --- a/extension/devtools/views/Viewport.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - -
-
\ No newline at end of file diff --git a/extension/manifest.json b/extension/manifest.json deleted file mode 100644 index 3d8ee877..00000000 --- a/extension/manifest.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "manifest_version": 2, - "version": "0.3.1.00", - "name": "Web Scraper", - "short_name": "Web Scraper", - "description": "Tool for data extraction from websites", - "permissions": [ - "", - "tabs", - "notifications", - "storage", - "unlimitedStorage", - "downloads" - ], - "icons": { - "16": "assets/images/icon16.png", - "48": "assets/images/icon48.png", - "128": "assets/images/icon128.png" - }, - "browser_action": { - "default_icon": { - "19": "assets/images/icon19.png", - "38": "assets/images/icon38.png" - }, - "default_title": "Web Scraper", - "default_popup": "popup.html" - }, - "options_page": "options_page/options.html", - "devtools_page": "devtools/devtools_init_page.html", - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", - "background": { - "scripts": [ - "assets/jquery-2.0.3.js", - "assets/papaparse.min.js", - "assets/jquery.whencallsequentially.js", - "assets/papaparse.min.js", - "assets/pouchdb-nightly.min.js", - "assets/base64.js", - "scripts/Selector.js", - "scripts/Selector/SelectorElement.js", - "scripts/Selector/SelectorGroup.js", - "scripts/Selector/SelectorLink.js", - "scripts/Selector/SelectorPopupLink.js", - "scripts/Selector/SelectorText.js", - "scripts/Selector/SelectorInputValue.js", - "scripts/Selector/ConstantValue.js", - "scripts/Selector/SelectorImage.js", - "scripts/Selector/SelectorDocument.js", - "scripts/Selector/SelectorHTML.js", - "scripts/Selector/SelectorElementAttribute.js", - "scripts/Selector/SelectorElementStyle.js", - "scripts/Selector/SelectorTable.js", - "scripts/Selector/SelectorElementScroll.js", - "scripts/Selector/SelectorElementClick.js", - "scripts/SelectorList.js", - "scripts/Sitemap.js", - "scripts/Queue.js", - "scripts/Job.js", - "scripts/Scraper.js", - "scripts/ChromePopupBrowser.js", - "scripts/Config.js", - "scripts/StorePouchDB.js", - "scripts/StoreRestApi.js", - "scripts/StoreDevtools.js", - "scripts/ContentScript.js", - "scripts/BackgroundScript.js", - "scripts/DateUtils/SimpleDateFormatter.js", - "scripts/DateUtils/DateRoller.js", - "scripts/DateUtils/DatePatternSupport.js", - "background_page/background_script.js" - ] - }, - "web_accessible_resources": [ - "assets/images/icon16.png", - "assets/images/icon48.png", - "assets/images/icon128.png", - "assets/images/icon19.png", - "assets/images/icon38.png" - ], - "content_scripts": [ - { - "matches": [ - "*://*/*" - ], - "js": [ - "assets/jquery-2.0.3.js", - "assets/papaparse.min.js", - "assets/jquery.whencallsequentially.js", - "assets/sugar-1.4.1.js", - "assets/css-selector/lib/CssSelector.js", - "assets/base64.js", - "scripts/DataExtractor.js", - "scripts/ContentSelector.js", - "scripts/Selector.js", - "scripts/ElementQuery.js", - "scripts/UniqueElementList.js", - "scripts/Selector/SelectorElement.js", - "scripts/Selector/SelectorGroup.js", - "scripts/Selector/SelectorLink.js", - "scripts/Selector/SelectorPopupLink.js", - "scripts/Selector/SelectorText.js", - "scripts/Selector/SelectorInputValue.js", - "scripts/Selector/ConstantValue.js", - "scripts/Selector/SelectorImage.js", - "scripts/Selector/SelectorDocument.js", - "scripts/Selector/SelectorHTML.js", - "scripts/Selector/SelectorElementAttribute.js", - "scripts/Selector/SelectorElementStyle.js", - "scripts/Selector/SelectorTable.js", - "scripts/Selector/SelectorElementScroll.js", - "scripts/Selector/SelectorElementClick.js", - "scripts/SelectorList.js", - "scripts/Sitemap.js", - "scripts/ContentScript.js", - "scripts/BackgroundScript.js", - "content_script/content_script.js" - ], - "css": [ - "content_script/content_script.css" - ] - } - ] -} \ No newline at end of file diff --git a/extension/options_page/options_page.js b/extension/options_page/options_page.js deleted file mode 100644 index 3ea94265..00000000 --- a/extension/options_page/options_page.js +++ /dev/null @@ -1,106 +0,0 @@ -$(function () { - - // popups for Storage setting input fields - $("#sitemapDb") - .popover({ - title: 'Database for sitemap storage', - html: true, - content: "CouchDB database url
http://example.com/scraper-sitemaps/", - placement: 'bottom' - }) - .blur(function () { - $(this).popover('hide'); - }); - - $("#dataDb") - .popover({ - title: 'Database for scraped data', - html: true, - content: "CouchDB database url. For each sitemap a new DB will be created.
http://example.com/", - placement: 'bottom' - }) - .blur(function () { - $(this).popover('hide'); - }); - - $("#restUrl") - .popover({ - title: 'Url to push your sitemaps.', - html: true, - content: "Rest api url.", - placement: 'bottom' - }) - .blur(function () { - $(this).popover('hide'); - }); - - // switch between configuration types - $("select[name=storageType]").change(function () { - var type = $(this).val(); - - if (type === 'couchdb') { - - $(".form-group.couchdb").show(); - $(".form-group.rest").hide(); - - } else if (type === 'rest') { - - $(".form-group.rest").show(); - $(".form-group.couchdb").hide(); - - } else { - - $(".form-group.rest").hide(); - $(".form-group.couchdb").hide(); - } - }); - - // Extension configuration - var config = new Config(); - - // load previously synced data - config.loadConfiguration(function () { - - $("#storageType").val(config.storageType); - $("#sitemapDb").val(config.sitemapDb); - $("#dataDb").val(config.dataDb); - $("#restUrl").val(config.restUrl); - - $("select[name=storageType]").change(); - }); - - // Sync storage settings - $("form#storage_configuration").submit(function () { - - const storageType = $("#storageType").val(); - const newConfig = { - storageType: storageType, - sitemapDb: '', - dataDb: '', - restUrl : '', - }; - - if (storageType === 'couchdb') { - newConfig.sitemapDb = $("#sitemapDb").val(); - newConfig.dataDb = $("#dataDb").val(); - } - else if (storageType === 'rest') { - newConfig.restUrl = $("#restUrl").val(); - } - - config.updateConfiguration(newConfig, function(){ - if (chrome.runtime.lastError){ - $(".alert") - .attr("id", "error") - .text( "Failed to save options " + chrome.runtime.lastError.message) - .show(); - } else{ - $(".alert") - .attr("id", "success") - .text( "Options successfully updated." ) - .show(); - } - }); - return false; - }); -}); \ No newline at end of file diff --git a/extension/popup.html b/extension/popup.html deleted file mode 100644 index 9fb65a30..00000000 --- a/extension/popup.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - -

- Open Developer tools where you will find Web Scraper tab: -

-

-

- Documentation is available on webscraper.io -

- - \ No newline at end of file diff --git a/extension/scripts/App.js b/extension/scripts/App.js deleted file mode 100644 index b6ec293e..00000000 --- a/extension/scripts/App.js +++ /dev/null @@ -1,11 +0,0 @@ -$(function () { - - // init bootstrap alerts - $(".alert").alert(); - - var store = new StoreDevtools(); - new SitemapController({ - store: store, - templateDir: 'views/' - }); -}); \ No newline at end of file diff --git a/extension/scripts/ChromePopupBrowser.js b/extension/scripts/ChromePopupBrowser.js deleted file mode 100644 index fd6c84cd..00000000 --- a/extension/scripts/ChromePopupBrowser.js +++ /dev/null @@ -1,91 +0,0 @@ -var ChromePopupBrowser = function (options) { - - this.pageLoadDelay = options.pageLoadDelay; - - // @TODO somehow handle the closed window -}; - -ChromePopupBrowser.prototype = { - - _initPopupWindow: function (callback, scope) { - - var browser = this; - if (this.window !== undefined) { - console.log(JSON.stringify(this.window)); - // check if tab exists - chrome.tabs.get(this.tab.id, function (tab) { - if (!tab) { - throw "Scraping window closed"; - } - }); - - - callback.call(scope); - return; - } - - chrome.windows.create({'type': 'popup', width: 1042, height: 768, focused: true, url: 'chrome://newtab'}, function (window) { - browser.window = window; - browser.tab = window.tabs[0]; - - - callback.call(scope); - }); - }, - - loadUrl: function (url, callback) { - - var tab = this.tab; - - var tabLoadListener = function (tabId, changeInfo, tab) { - if(tabId === this.tab.id) { - if (changeInfo.status === 'complete') { - - // @TODO check url ? maybe it would be bad because some sites might use redirects - - // remove event listener - chrome.tabs.onUpdated.removeListener(tabLoadListener); - - // callback tab is loaded after page load delay - setTimeout(callback, this.pageLoadDelay); - } - } - }.bind(this); - chrome.tabs.onUpdated.addListener(tabLoadListener); - - chrome.tabs.update(tab.id, {url: url}); - }, - - close: function () { - chrome.windows.remove(this.window.id); - }, - - fetchData: function (url, sitemap, parentSelectorId, callback, scope) { - - var browser = this; - - this._initPopupWindow(function () { - var tab = browser.tab; - - browser.loadUrl(url, function () { - - var message = { - extractData: true, - sitemap: JSON.parse(JSON.stringify(sitemap)), - parentSelectorId: parentSelectorId - }; - - chrome.tabs.sendMessage(tab.id, message, function (data, selectors) { - console.log("extracted data from web page", data); - - if (selectors && scope) { - // table selector can dynamically add columns (addMissingColumns Feature) - scope.scraper.sitemap.selectors = selectors; - } - - callback.call(scope, data); - }); - }.bind(this)); - }, this); - } -}; \ No newline at end of file diff --git a/extension/scripts/Config.js b/extension/scripts/Config.js deleted file mode 100644 index a050d24b..00000000 --- a/extension/scripts/Config.js +++ /dev/null @@ -1,56 +0,0 @@ -var Config = function () { - -}; - -Config.prototype = { - - sitemapDb: '', - dataDb: '', - restUrl: '', - - defaults: { - storageType: "local", - // this is where sitemap documents are stored - sitemapDb: "scraper-sitemaps", - // this is where scraped data is stored. - // empty for local storage - dataDb: "", - restUrl: "" - }, - - /** - * Loads configuration from chrome extension sync storage - */ - loadConfiguration: function (callback) { - - chrome.storage.sync.get(['sitemapDb', 'dataDb', 'storageType', - 'restUrl'], function (items) { - - this.storageType = items.storageType || this.defaults.storageType; - - this.sitemapDb = this.defaults.sitemapDb; - this.dataDb = this.defaults.dataDb; - this.restUrl = this.defaults.restUrl; - - if (this.storageType === 'couchdb') { - this.sitemapDb = items.sitemapDb || this.defaults.sitemapDb; - this.dataDb = items.dataDb || this.defaults.dataDb; - - } else if (this.storageType === 'rest') { - this.restUrl = items.restUrl || this.defaults.restUrl; - } - - callback(); - }.bind(this)); - }, - - /** - * Saves configuration to chrome extension sync storage - * @param {type} items - * @param {type} callback - * @returns {undefined} - */ - updateConfiguration: function (items, callback) { - chrome.storage.sync.set(items, callback); - } -}; \ No newline at end of file diff --git a/extension/scripts/ContentScript.js b/extension/scripts/ContentScript.js deleted file mode 100644 index e97d80e3..00000000 --- a/extension/scripts/ContentScript.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * ContentScript that can be called from anywhere within the extension - */ -var ContentScript = { - - /** - * Fetch - * @param request.CSSSelector css selector as string - * @returns $.Deferred() - */ - getHTML: function(request) { - - var deferredHTML = $.Deferred(); - var html = $(request.CSSSelector).clone().wrap('

').parent().html(); - deferredHTML.resolve(html); - return deferredHTML.promise(); - }, - - /** - * Removes current content selector if is in use within the page - * @returns $.Deferred() - */ - removeCurrentContentSelector: function() { - - var deferredResponse = $.Deferred(); - var contentSelector = window.cs; - if(contentSelector === undefined) { - deferredResponse.resolve(); - } - else { - contentSelector.removeGUI(); - window.cs = undefined; - deferredResponse.resolve(); - } - - return deferredResponse.promise(); - }, - - /** - * Select elements within the page - * @param request.parentCSSSelector - * @param request.allowedElements - */ - selectSelector: function(request) { - - var deferredResponse = $.Deferred(); - - this.removeCurrentContentSelector().done(function() { - - var contentSelector = new ContentSelector({ - parentCSSSelector: request.parentCSSSelector, - allowedElements: request.allowedElements - }); - window.cs = contentSelector; - - var deferredCSSSelector = contentSelector.getCSSSelector(); - deferredCSSSelector.done(function(response) { - this.removeCurrentContentSelector().done(function(){ - deferredResponse.resolve(response); - window.cs = undefined; - }.bind(this)); - }.bind(this)).fail(function(message) { - deferredResponse.reject(message); - window.cs = undefined; - }.bind(this)); - - }.bind(this)); - - return deferredResponse.promise(); - }, - - /** - * Preview elements - * @param request.parentCSSSelector - * @param request.elementCSSSelector - */ - previewSelector: function(request) { - - var deferredResponse = $.Deferred(); - this.removeCurrentContentSelector().done(function () { - - var contentSelector = new ContentSelector({ - parentCSSSelector: request.parentCSSSelector - }); - window.cs = contentSelector; - - var deferredSelectorPreview = contentSelector.previewSelector(request.elementCSSSelector); - deferredSelectorPreview.done(function() { - deferredResponse.resolve(); - }).fail(function(message) { - deferredResponse.reject(message); - window.cs = undefined; - }); - }); - return deferredResponse; - } -}; - -/** - * - * @param location configure from where the content script is being accessed (ContentScript, BackgroundPage, DevTools) - * @param backgroundScript BackgroundScript client - * @returns ContentScript - */ -var getContentScript = function(location) { - - var contentScript; - - // Handle calls from different places - if(location === "ContentScript") { - contentScript = ContentScript; - contentScript.backgroundScript = getBackgroundScript("ContentScript"); - return contentScript; - } - else if(location === "BackgroundScript" || location === "DevTools") { - - var backgroundScript = getBackgroundScript(location); - - // if called within background script proxy calls to content script - contentScript = {}; - Object.keys(ContentScript).forEach(function(attr) { - if(typeof ContentScript[attr] === 'function') { - contentScript[attr] = function(request) { - - var reqToContentScript = { - contentScriptCall: true, - fn: attr, - request: request - }; - - return backgroundScript.executeContentScript(reqToContentScript); - }; - } - else { - contentScript[attr] = ContentScript[attr]; - } - }); - contentScript.backgroundScript = backgroundScript; - return contentScript; - } - else { - throw "Invalid ContentScript initialization - " + location; - } -}; diff --git a/extension/scripts/ContentSelector.js b/extension/scripts/ContentSelector.js deleted file mode 100644 index d5f9981e..00000000 --- a/extension/scripts/ContentSelector.js +++ /dev/null @@ -1,397 +0,0 @@ -/** - * @param options.parentCSSSelector Elements can be only selected within this element - * @param options.allowedElements Elements that can only be selected - * @constructor - */ -ContentSelector = function(options) { - - // deferred response - this.deferredCSSSelectorResponse = $.Deferred(); - - this.allowedElements = options.allowedElements; - this.parentCSSSelector = options.parentCSSSelector.trim(); - this.alert = options.alert || function(txt) {alert(txt);}; - - if(this.parentCSSSelector) { - this.parent = $(this.parentCSSSelector)[0]; - - // handle situation when parent selector not found - if(this.parent === undefined) { - this.deferredCSSSelectorResponse.reject("parent selector not found"); - this.alert("Parent element not found!"); - return; - } - } - else { - this.parent = $("body")[0]; - } -}; - -ContentSelector.prototype = { - - /** - * get css selector selected by the user - */ - getCSSSelector: function(request) { - - if(this.deferredCSSSelectorResponse.state() !== "rejected") { - - // elements that are selected by the user - this.selectedElements = []; - // element selected from top - this.top = 0; - - // initialize css selector - this.initCssSelector(false); - - this.initGUI(); - } - - return this.deferredCSSSelectorResponse.promise(); - }, - - getCurrentCSSSelector: function() { - - if(this.selectedElements && this.selectedElements.length > 0) { - - var cssSelector; - - // handle special case when parent is selected - if(this.isParentSelected()) { - if(this.selectedElements.length === 1) { - cssSelector = '_parent_'; - } - else if($("#-selector-toolbar [name=diferentElementSelection]").prop("checked")) { - var selectedElements = this.selectedElements.clone(); - selectedElements.splice(selectedElements.indexOf(this.parent),1); - cssSelector = '_parent_, '+this.cssSelector.getCssSelector(selectedElements, this.top); - } - else { - // will trigger error where multiple selections are not allowed - cssSelector = this.cssSelector.getCssSelector(this.selectedElements, this.top); - } - } - else { - cssSelector = this.cssSelector.getCssSelector(this.selectedElements, this.top); - } - - return cssSelector; - } - return ""; - }, - - isParentSelected: function() { - return this.selectedElements.indexOf(this.parent) !== -1; - }, - - /** - * initialize or reconfigure css selector class - * @param allowMultipleSelectors - */ - initCssSelector: function(allowMultipleSelectors) { - this.cssSelector = new CssSelector({ - enableSmartTableSelector: true, - parent: this.parent, - allowMultipleSelectors:allowMultipleSelectors, - ignoredClasses: [ - "-sitemap-select-item-selected", - "-sitemap-select-item-hover", - "-sitemap-parent", - "-web-scraper-img-on-top", - "-web-scraper-selection-active" - ], - query: jQuery - }); - }, - - previewSelector: function (elementCSSSelector) { - - if(this.deferredCSSSelectorResponse.state() !== "rejected") { - - this.highlightParent(); - $(ElementQuery(elementCSSSelector, this.parent)).addClass('-sitemap-select-item-selected'); - this.deferredCSSSelectorResponse.resolve(); - } - - return this.deferredCSSSelectorResponse.promise(); - }, - - initGUI: function () { - - this.highlightParent(); - - // all elements except toolbar - this.$allElements = $(this.allowedElements+":not(#-selector-toolbar):not(#-selector-toolbar *)", this.parent); - // allow selecting parent also - if(this.parent !== document.body) { - this.$allElements.push(this.parent); - } - - this.bindElementHighlight(); - this.bindElementSelection(); - this.bindKeyboardSelectionManipulations(); - this.attachToolbar(); - this.bindMultipleGroupCheckbox(); - this.bindMultipleGroupPopupHide(); - this.bindMoveImagesToTop(); - }, - - bindElementSelection: function () { - this.$allElements.bind("click.elementSelector", function (e) { - var element = e.currentTarget; - if(this.selectedElements.indexOf(element) === -1) { - this.selectedElements.push(element); - } - this.highlightSelectedElements(); - - // Cancel all other events - return false; - }.bind(this)); - }, - - /** - * Add to select elements the element that is under the mouse - */ - selectMouseOverElement: function() { - - var element = this.mouseOverElement; - if(element) { - this.selectedElements.push(element); - this.highlightSelectedElements(); - } - }, - - bindElementHighlight: function () { - - $(this.$allElements).bind("mouseover.elementSelector", function(e) { - // allow event bubbling for other event listeners but not for web scraper. - if(e.target !== e.currentTarget) { - return; - } - - var element = e.currentTarget; - this.mouseOverElement = element; - $(element).addClass("-sitemap-select-item-hover"); - }.bind(this)).bind("mouseout.elementSelector", function(e) { - // allow event bubbling for other event listeners but not for web scraper. - if(e.target !== e.currentTarget) { - return; - } - - var element = e.currentTarget; - this.mouseOverElement = null; - $(element).removeClass("-sitemap-select-item-hover"); - }.bind(this)); - }, - - bindMoveImagesToTop: function() { - - $("body").addClass("-web-scraper-selection-active"); - - // do this only when selecting images - if(this.allowedElements === 'img') { - $("img").filter(function(i, element) { - return $(element).css("position") === 'static'; - }).addClass("-web-scraper-img-on-top"); - } - }, - - unbindMoveImagesToTop: function() { - - $("body.-web-scraper-selection-active").removeClass("-web-scraper-selection-active"); - $("img.-web-scraper-img-on-top").removeClass("-web-scraper-img-on-top"); - }, - - selectChild: function () { - this.top--; - if (this.top < 0) { - this.top = 0; - } - }, - selectParent: function () { - this.top++; - }, - - // User with keyboard arrows can select child or paret elements of selected elements. - bindKeyboardSelectionManipulations: function () { - - // check for focus - var lastFocusStatus; - this.keyPressFocusInterval = setInterval(function() { - var focus = document.hasFocus(); - if(focus === lastFocusStatus) return; - lastFocusStatus = focus; - - $("#-selector-toolbar .key-button").toggleClass("hide", !focus); - $("#-selector-toolbar .key-events").toggleClass("hide", focus); - }.bind(this), 200); - - - // Using up/down arrows user can select elements from top of the - // selected element - $(document).bind("keydown.selectionManipulation", function (event) { - - // select child C - if (event.keyCode === 67) { - this.animateClickedKey($("#-selector-toolbar .key-button-child")); - this.selectChild(); - } - // select parent P - else if (event.keyCode === 80) { - this.animateClickedKey($("#-selector-toolbar .key-button-parent")); - this.selectParent(); - } - // select element - else if (event.keyCode === 83) { - this.animateClickedKey($("#-selector-toolbar .key-button-select")); - this.selectMouseOverElement(); - } - - this.highlightSelectedElements(); - }.bind(this)); - }, - - animateClickedKey: function(element) { - $(element).removeClass("clicked").removeClass("clicked-animation"); - setTimeout(function() { - $(element).addClass("clicked"); - setTimeout(function(){ - $(element).addClass("clicked-animation"); - },100); - },1); - - }, - - highlightSelectedElements: function () { - try { - var resultCssSelector = this.getCurrentCSSSelector(); - - $("body #-selector-toolbar .selector").text(resultCssSelector); - // highlight selected elements - $(".-sitemap-select-item-selected").removeClass('-sitemap-select-item-selected'); - $(ElementQuery(resultCssSelector, this.parent)).addClass('-sitemap-select-item-selected'); - } - catch(err) { - if(err === "found multiple element groups, but allowMultipleSelectors disabled") { - console.log("multiple different element selection disabled"); - - this.showMultipleGroupPopup(); - // remove last added element - this.selectedElements.pop(); - this.highlightSelectedElements(); - } - } - }, - - showMultipleGroupPopup: function() { - $("#-selector-toolbar .popover").attr("style", "display:block !important;"); - }, - - hideMultipleGroupPopup: function() { - $("#-selector-toolbar .popover").attr("style", ""); - }, - - bindMultipleGroupPopupHide: function() { - $("#-selector-toolbar .popover .close").click(this.hideMultipleGroupPopup.bind(this)); - }, - - unbindMultipleGroupPopupHide: function() { - $("#-selector-toolbar .popover .close").unbind("click"); - }, - - bindMultipleGroupCheckbox: function() { - $("#-selector-toolbar [name=diferentElementSelection]").change(function(e) { - if($(e.currentTarget).is(":checked")) { - this.initCssSelector(true); - } - else { - this.initCssSelector(false); - } - }.bind(this)); - }, - unbindMultipleGroupCheckbox: function(){ - $("#-selector-toolbar .diferentElementSelection").unbind("change"); - }, - - attachToolbar: function () { - - var $toolbar = '

' + - '
' + - '
' + - '' + - '
' + - '
×
' + - '
' + - '
' + - '
' + - 'Different type element selection is disabled. If the element ' + - 'you clicked should also be included then enable this and ' + - 'click on the element again. Usually this is not needed.' + - '
' + - '
' + - '
' + - '
' + - '
Enable key events
' + - '
S
' + - '
P
' + - '
C
' + - '
Done selecting!
' + - '
'; - $("body").append($toolbar); - - $("body #-selector-toolbar .done-selecting-button").click(function () { - this.selectionFinished(); - }.bind(this)); - }, - highlightParent: function () { - // do not highlight parent if its the body - if(!$(this.parent).is("body") && !$(this.parent).is("#webpage")) { - $(this.parent).addClass("-sitemap-parent"); - } - }, - - unbindElementSelection: function () { - $(this.$allElements).unbind("click.elementSelector"); - // remove highlighted element classes - this.unbindElementSelectionHighlight(); - }, - unbindElementSelectionHighlight: function () { - $(".-sitemap-select-item-selected").removeClass('-sitemap-select-item-selected'); - $(".-sitemap-parent").removeClass('-sitemap-parent'); - }, - unbindElementHighlight: function () { - $(this.$allElements).unbind("mouseover.elementSelector") - .unbind("mouseout.elementSelector"); - }, - unbindKeyboardSelectionMaipulatios: function () { - $(document).unbind("keydown.selectionManipulation"); - clearInterval(this.keyPressFocusInterval); - }, - removeToolbar: function () { - $("body #-selector-toolbar a").unbind("click"); - $("#-selector-toolbar").remove(); - }, - - /** - * Remove toolbar and unbind events - */ - removeGUI: function() { - - this.unbindElementSelection(); - this.unbindElementHighlight(); - this.unbindKeyboardSelectionMaipulatios(); - this.unbindMultipleGroupPopupHide(); - this.unbindMultipleGroupCheckbox(); - this.unbindMoveImagesToTop(); - this.removeToolbar(); - }, - - selectionFinished: function () { - - var resultCssSelector = this.getCurrentCSSSelector(); - - this.deferredCSSSelectorResponse.resolve({ - CSSSelector: resultCssSelector - }); - } -}; diff --git a/extension/scripts/Controller.js b/extension/scripts/Controller.js deleted file mode 100644 index 830c1063..00000000 --- a/extension/scripts/Controller.js +++ /dev/null @@ -1,1490 +0,0 @@ -var SitemapController = function(options) { - - for (var i in options) { - this[i] = options[i]; - } - this.init(); -}; - -SitemapController.prototype = { - - backgroundScript: getBackgroundScript("DevTools"), - contentScript: getContentScript("DevTools"), - - control: function(controls) { - var controller = this; - - for (var selector in controls) { - for (var event in controls[selector]) { - $(document).on(event, selector, (function(selector, event) { - return function() { - var continueBubbling = controls[selector][event].call(controller, this); - if (continueBubbling !== true) { - return false; - } - }; - })(selector, event)); - } - } - }, - - /** - * Loads templates for ICanHaz - */ - loadTemplates: function(cbAllTemplatesLoaded) { - var templateIds = [ - "Viewport", - "SitemapList", - "SitemapListItem", - "SitemapCreate", - "SitemapImport", - "SitemapExport", - "SitemapBrowseData", - "SitemapScrapeConfig", - "SitemapExportDataCSV", - "SitemapEditMetadata", - "SelectorList", - "SelectorListItem", - "SelectorEdit", - "SelectorEditTableColumn", - "SitemapSelectorGraph", - "DataPreview" - ]; - var templatesLoaded = 0; - var cbLoaded = function(templateId, template) { - templatesLoaded++; - ich.addTemplate(templateId, template); - if (templatesLoaded === templateIds.length) { - cbAllTemplatesLoaded(); - } - }; - - templateIds.forEach(function(templateId) { - $.get(this.templateDir + templateId + ".html", cbLoaded.bind(this, templateId)); - }.bind(this)); - }, - - init: function() { - - this.loadTemplates(function() { - // currently viewed objects - this.clearState(); - - // render main viewport - ich.Viewport().appendTo("body"); - - // cancel all form submits - $("form").bind("submit", function() { - return false; - }); - - this.control({ - "#sitemaps-nav-button": { - click: this.showSitemaps - }, - "#create-sitemap-create-nav-button": { - click: this.showCreateSitemap - }, - "#create-sitemap-import-nav-button": { - click: this.showImportSitemapPanel - }, - "#sitemap-export-nav-button": { - click: this.showSitemapExportPanel - }, - "#sitemap-export-data-csv-nav-button": { - click: this.showSitemapExportDataCsvPanel - }, - "#submit-create-sitemap": { - click: this.createSitemap - }, - "#submit-import-sitemap": { - click: this.importSitemap - }, - "#sitemap-edit-metadata-nav-button": { - click: this.editSitemapMetadata - }, - "#sitemap-selector-list-nav-button": { - click: this.showSitemapSelectorList - }, - "#sitemap-selector-graph-nav-button": { - click: this.showSitemapSelectorGraph - }, - "#sitemap-browse-nav-button": { - click: this.browseSitemapData - }, - "button#submit-edit-sitemap": { - click: this.editSitemapMetadataSave - }, - "#edit-sitemap-metadata-form": { - submit: function() { - return false; - } - }, - "#sitemaps tr": { - click: this.editSitemap - }, - "#sitemaps button[action=delete-sitemap]": { - click: this.deleteSitemap - }, - "#sitemap-scrape-nav-button": { - click: this.showScrapeSitemapConfigPanel - }, - "#submit-scrape-sitemap-form": { - submit: function() { - return false; - } - }, - "#submit-scrape-sitemap": { - click: this.scrapeSitemap - }, - "#sitemaps button[action=browse-sitemap-data]": { - click: this.sitemapListBrowseSitemapData - }, - "#sitemaps button[action=csv-download-sitemap-data]": { - click: this.downloadSitemapData - }, - // @TODO move to tr - "#selector-tree tbody tr": { - click: this.showChildSelectors - }, - "#selector-tree .breadcrumb a": { - click: this.treeNavigationshowSitemapSelectorList - }, - "#selector-tree tr button[action=edit-selector]": { - click: this.editSelector - }, - '#edit-selector select[name=type]': { - change: function(){ this.selectorTypeChanged(true) } - }, - "#edit-selector button[action=save-selector]": { - click: this.saveSelector - }, - "#edit-selector button[action=cancel-selector-editing]": { - click: this.cancelSelectorEditing - }, - "#edit-selector #selectorId": { - keyup: this.updateSelectorParentListOnIdChange - }, - "#selector-tree button[action=add-selector]": { - click: this.addSelector - }, - "#selector-tree tr button[action=delete-selector]": { - click: this.deleteSelector - }, - "#selector-tree tr button[action=preview-selector]": { - click: this.previewSelectorFromSelectorTree - }, - "#selector-tree tr button[action=data-preview-selector]": { - click: this.previewSelectorDataFromSelectorTree - }, - "#edit-selector button[action=select-selector]": { - click: this.selectSelector - }, - "#edit-selector button[action=select-table-header-row-selector]": { - click: this.selectTableHeaderRowSelector - }, - "#edit-selector button[action=refresh-header-row-selector]": { - click: this.refreshTableHeaderRowSelector - }, - "#edit-selector button[action=select-table-data-row-selector]": { - click: this.selectTableDataRowSelector - }, - "#edit-selector button[action=preview-selector]": { - click: this.previewSelector - }, - "#edit-selector button[action=preview-click-element-selector]": { - click: this.previewClickElementSelector - }, - "#edit-selector button[action=preview-table-row-selector]": { - click: this.previewTableRowSelector - }, - "#edit-selector button[action=preview-selector-data]": { - click: this.previewSelectorDataFromSelectorEditing - } - }); - this.showSitemaps(); - }.bind(this)); - }, - - clearState: function() { - this.state = { - // sitemap that is currently open - currentSitemap: null, - // selector ids that are shown in the navigation - editSitemapBreadcumbsSelectors: null, - currentParentSelectorId: null, - currentSelector: null - }; - }, - - setStateEditSitemap: function(sitemap) { - this.state.currentSitemap = sitemap; - this.state.editSitemapBreadcumbsSelectors = [ - { id: "_root" } - ]; - this.state.currentParentSelectorId = "_root"; - }, - - setActiveNavigationButton: function(navigationId) { - $(".nav .active").removeClass("active"); - $("#" + navigationId + "-nav-button").closest("li").addClass("active"); - - if (navigationId.match(/^sitemap-/)) { - $("#sitemap-nav-button").removeClass("disabled"); - $("#sitemap-nav-button").closest("li").addClass("active"); - $("#navbar-active-sitemap-id").text("(" + this.state.currentSitemap._id + ")"); - } else { - $("#sitemap-nav-button").addClass("disabled"); - $("#navbar-active-sitemap-id").text(""); - } - - if (navigationId.match(/^create-sitemap-/)) { - $("#create-sitemap-nav-button").closest("li").addClass("active"); - } - }, - - /** - * Returns bootstrapValidator object for current form in viewport - */ - getFormValidator: function() { - - var validator = $("#viewport form").data("bootstrapValidator"); - return validator; - }, - - /** - * Returns whether current form in the viewport is valid - * @returns {Boolean} - */ - isValidForm: function() { - var validator = this.getFormValidator(); - - //validator.validate(); - // validate method calls submit which is not needed in this case. - for (var field in validator.options.fields) { - validator.validateField(field); - } - - var valid = validator.isValid(); - return valid; - }, - - /** - * Add validation to sitemap creation or editing form - */ - initSitemapValidation: function() { - - $("#viewport form").bootstrapValidator({ - fields: { - "_id": { - validators: { - notEmpty: { - message: "The sitemap id is required and cannot be empty" - }, - stringLength: { - min: 3, - message: "The sitemap id should be atleast 3 characters long" - }, - regexp: { - regexp: /^[a-z][a-z0-9_\$\(\)\+\-/]+$/, - message: "Only lowercase characters (a-z), digits (0-9), or any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter." - }, - // placeholder for sitemap id existance validation - callback: { - message: "Sitemap with this id already exists", - callback: function(value, validator) { - return true; - }.bind(this) - } - } - }, - "startUrls": { - validators: { - notEmpty: { - message: "The start URL is required and cannot be empty" - }, - callback: { - message: "The start URLs are not valid. Please use \",\" as a seperator.", - callback: function(value, validator) { - function isUrlValid(url) { - return /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(url); - } - - var isValid = true; - $.each(value.split(",").map((item) => item.trim()), function(i, url) { - isValid = isUrlValid(url) ? isValid : false; - }); - return isValid; - } - } - } - } - } - }); - }, - - showCreateSitemap: function() { - this.setActiveNavigationButton("create-sitemap-create"); - var sitemapForm = ich.SitemapCreate(); - $("#viewport").html(sitemapForm); - this.initSitemapValidation(); - - return true; - }, - - initImportStiemapValidation: function() { - $("#viewport form").bootstrapValidator({ - fields: { - "_id": { - validators: { - stringLength: { - min: 3, - message: "The sitemap id should be atleast 3 characters long" - }, - regexp: { - regexp: /^[a-z][a-z0-9_\$\(\)\+\-/]+$/, - message: "Only lowercase characters (a-z), digits (0-9), or any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter." - }, - // placeholder for sitemap id existance validation - callback: { - message: "Sitemap with this id already exists", - callback: function(value, validator) { - return true; - }.bind(this) - } - } - }, - sitemapJSON: { - validators: { - notEmpty: { - message: "Sitemap JSON is required and cannot be empty" - }, - callback: { - message: "JSON is not valid", - callback: function(value, validator) { - try { - JSON.parse(value); - } catch (e) { - return false; - } - return true; - }.bind(this) - } - } - } - } - }); - }, - - showImportSitemapPanel: function() { - this.setActiveNavigationButton("create-sitemap-import"); - var sitemapForm = ich.SitemapImport(); - $("#viewport").html(sitemapForm); - this.initImportStiemapValidation(); - return true; - }, - - showSitemapExportPanel: function() { - this.setActiveNavigationButton("sitemap-export"); - var sitemap = this.state.currentSitemap; - var sitemapJSON = sitemap.exportSitemap(); - var sitemapExportForm = ich.SitemapExport({ - sitemapJSON: sitemapJSON - }); - $("#viewport").html(sitemapExportForm); - return true; - }, - - showSitemaps: function() { - - this.clearState(); - this.setActiveNavigationButton("sitemaps"); - - this.store.getAllSitemaps(function(sitemaps) { - $sitemapListPanel = ich.SitemapList(); - sitemaps.forEach(function(sitemap) { - $sitemap = ich.SitemapListItem(sitemap); - $sitemap.data("sitemap", sitemap); - $sitemapListPanel.find("tbody").append($sitemap); - }); - $("#viewport").html($sitemapListPanel); - }); - }, - - getSitemapFromMetadataForm: function() { - - var id = $("#viewport form input[name=_id]").val(); - var $startUrlInputs = $("#viewport form .input-start-url"); - var startUrls = $startUrlInputs.val().split(",").map((item) => item.trim()); - - return { - id: id, - startUrls: startUrls - }; - }, - - createSitemap: function(form) { - - // cancel submit if invalid form - if (!this.isValidForm()) { - return false; - } - - var sitemapData = this.getSitemapFromMetadataForm(); - - // check whether sitemap with this id already exist - this.store.sitemapExists(sitemapData.id, function(sitemapExists) { - if (sitemapExists) { - var validator = this.getFormValidator(); - validator.updateStatus("_id", "INVALID", "callback"); - } else { - var sitemap = new Sitemap({ - _id: sitemapData.id, - startUrls: sitemapData.startUrls, - selectors: [] - }); - this.store.createSitemap(sitemap, function(sitemap) { - this._editSitemap(sitemap, ["_root"]); - }.bind(this, sitemap)); - } - - }.bind(this)); - }, - - importSitemap: function() { - - // cancel submit if invalid form - if (!this.isValidForm()) { - return false; - } - - // load data from form - var sitemapJSON = $("[name=sitemapJSON]").val(); - var id = $("input[name=_id]").val(); - var sitemap = new Sitemap(); - sitemap.importSitemap(sitemapJSON); - if (id.length) { - sitemap._id = id; - } - // check whether sitemap with this id already exist - this.store.sitemapExists(sitemap._id, function(sitemapExists) { - if (sitemapExists) { - var validator = this.getFormValidator(); - validator.updateStatus("_id", "INVALID", "callback"); - } else { - this.store.createSitemap(sitemap, function(sitemap) { - this._editSitemap(sitemap, ["_root"]); - }.bind(this, sitemap)); - } - }.bind(this)); - }, - - editSitemapMetadata: function(button) { - - this.setActiveNavigationButton("sitemap-edit-metadata"); - - var sitemap = this.state.currentSitemap; - var $sitemapMetadataForm = ich.SitemapEditMetadata(sitemap); - $("#viewport").html($sitemapMetadataForm); - this.initSitemapValidation(); - - return true; - }, - - editSitemapMetadataSave: function(button) { - var sitemap = this.state.currentSitemap; - var sitemapData = this.getSitemapFromMetadataForm(); - - // cancel submit if invalid form - if (!this.isValidForm()) { - return false; - } - - // check whether sitemap with this id already exist - this.store.sitemapExists(sitemapData.id, function(sitemapExists) { - if (sitemap._id !== sitemapData.id && sitemapExists) { - var validator = this.getFormValidator(); - validator.updateStatus("_id", "INVALID", "callback"); - return; - } - - // change data - sitemap.startUrls = sitemapData.startUrls; - - // just change sitemaps url - if (sitemapData.id === sitemap._id) { - this.store.saveSitemap(sitemap, function(sitemap) { - this.showSitemapSelectorList(); - }.bind(this)); - } - // id changed. we need to delete the old one and create a new one - else { - var newSitemap = new Sitemap(sitemap); - var oldSitemap = sitemap; - newSitemap._id = sitemapData.id; - this.store.createSitemap(newSitemap, function(newSitemap) { - this.store.deleteSitemap(oldSitemap, function() { - this.state.currentSitemap = newSitemap; - this.showSitemapSelectorList(); - }.bind(this)); - }.bind(this)); - } - - }.bind(this)); - }, - - /** - * Callback when sitemap edit button is clicked in sitemap grid - */ - editSitemap: function(tr) { - - var sitemap = $(tr).data("sitemap"); - this._editSitemap(sitemap); - }, - _editSitemap: function(sitemap) { - this.setStateEditSitemap(sitemap); - this.setActiveNavigationButton("sitemap"); - - this.showSitemapSelectorList(); - }, - showSitemapSelectorList: function() { - - this.setActiveNavigationButton("sitemap-selector-list"); - - var sitemap = this.state.currentSitemap; - var parentSelectors = this.state.editSitemapBreadcumbsSelectors; - var parentSelectorId = this.state.currentParentSelectorId; - - var $selectorListPanel = ich.SelectorList({ - parentSelectors: parentSelectors - }); - var selectors = sitemap.getDirectChildSelectors(parentSelectorId); - selectors.forEach(function(selector) { - $selector = ich.SelectorListItem(selector); - $selector.data("selector", selector); - $selectorListPanel.find("tbody").append($selector); - }); - $("#viewport").html($selectorListPanel); - - return true; - }, - showSitemapSelectorGraph: function() { - this.setActiveNavigationButton("sitemap-selector-graph"); - var sitemap = this.state.currentSitemap; - var $selectorGraphPanel = ich.SitemapSelectorGraph(); - $("#viewport").html($selectorGraphPanel); - var graphDiv = $("#selector-graph")[0]; - var graph = new SelectorGraphv2(sitemap); - graph.draw(graphDiv, $(document).width(), 200); - return true; - }, - showChildSelectors: function(tr) { - var selector = $(tr).data("selector"); - var parentSelectors = this.state.editSitemapBreadcumbsSelectors; - this.state.currentParentSelectorId = selector.id; - parentSelectors.push(selector); - - this.showSitemapSelectorList(); - }, - - treeNavigationshowSitemapSelectorList: function(button) { - var parentSelectors = this.state.editSitemapBreadcumbsSelectors; - var controller = this; - $("#selector-tree .breadcrumb li a").each(function(i, parentSelectorButton) { - if (parentSelectorButton === button) { - parentSelectors.splice(i + 1); - controller.state.currentParentSelectorId = parentSelectors[i].id; - } - }); - this.showSitemapSelectorList(); - }, - - initSelectorValidation: function() { - - $("#viewport form").bootstrapValidator({ - fields: { - "id": { - validators: { - notEmpty: { - message: "Sitemap id required and cannot be empty" - }, - stringLength: { - min: 3, - message: "The sitemap id should be atleast 3 characters long" - }, - regexp: { - regexp: /^[^_].*$/, - message: "Selector id cannot start with an underscore _" - } - } - }, - selector: { - validators: { - notEmpty: { - message: "Selector is required and cannot be empty" - } - } - }, - regex: { - validators: { - callback: { - message: "JavaScript does not support regular expressions that can match 0 characters.", - callback: function(value, validator) { - // allow no regex - if (!value) { - return true; - } - - try { - var matches = "".match(new RegExp(value)); - return !(matches !== null && matches[0] === ""); - } catch (e) { - return false; - } - } - } - } - }, - regexgroup: { - validators: { - callback: { - message: "Regex group must be numeric", - callback: function(value, validator) { - if (value === "") { - return true; - } - return !isNaN(value); - } - } - } - }, - clickElementSelector: { - validators: { - notEmpty: { - message: "Click selector is required and cannot be empty" - } - } - }, - tableHeaderRowSelector: { - validators: { - notEmpty: { - message: "Header row selector is required and cannot be empty" - } - } - }, - tableDataRowSelector: { - validators: { - notEmpty: { - message: "Data row selector is required and cannot be empty" - } - } - }, - delay: { - validators: { - numeric: { - message: "Delay must be numeric" - } - } - }, - paginationLimit: { - validators: { - numeric: { - message: "Pagination limit must be numeric or empty" - }, - callback: { - message: "Pagination limit must be 1 at least", - callback: function(value, validator) { - if (!value) { - return true; - } - return value >= 1; - } - } - } - }, - parentSelectors: { - validators: { - notEmpty: { - message: "You must choose at least one parent selector" - }, - callback: { - message: "Cannot handle recursive element selectors", - callback: function(value, validator, $field) { - - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - return !sitemap.selectors.hasRecursiveElementSelectors(); - - }.bind(this) - } - } - } - } - }); - }, - editSelector: function(button) { - var selector = $(button).closest("tr").data("selector"); - this._editSelector(selector); - }, - updateSelectorParentListOnIdChange: function() { - - var selector = this.getCurrentlyEditedSelector(); - $(".currently-edited").val(selector.id).text(selector.id); - }, - _editSelector: function(selector) { - - var sitemap = this.state.currentSitemap; - var selectorIds = sitemap.getPossibleParentSelectorIds(); - - var $editSelectorForm = ich.SelectorEdit({ - selector: selector, - selectorIds: selectorIds, - selectorTypes: [ - { - type: "SelectorText", - title: "Text" - }, - { - type: "ConstantValue", - title: "Constant value" - }, - { - type: "SelectorInputValue", - title: "Input value" - }, - { - type: "SelectorLink", - title: "Link" - }, - { - type: "SelectorPopupLink", - title: "Popup Link" - }, - { - type: "SelectorImage", - title: "Image" - }, - { - type: "SelectorDocument", - title: "Document" - }, - { - type: "SelectorTable", - title: "Table" - }, - { - type: "SelectorElementAttribute", - title: "Element attribute" - }, - { - type: "SelectorElementStyle", - title: "Element style" - }, - { - type: "SelectorHTML", - title: "HTML" - }, - { - type: "SelectorElement", - title: "Element" - }, - { - type: "SelectorElementScroll", - title: "Element scroll down" - }, - { - type: "SelectorElementClick", - title: "Element click" - }, - { - type: "SelectorGroup", - title: "Grouped" - } - ] - }); - $("#viewport").html($editSelectorForm); - // mark initially opened selector as currently edited - $("#edit-selector #parentSelectors option").each(function(i, element) { - if ($(element).val() === selector.id) { - $(element).addClass("currently-edited"); - } - }); - - // set clickType - if (selector.clickType) { - $editSelectorForm.find("[name=clickType]").val(selector.clickType); - } - - // set clickElementUniquenessType - if (selector.clickElementUniquenessType) { - $editSelectorForm.find("[name=clickElementUniquenessType]").val(selector.clickElementUniquenessType); - } - - // handle selects seperately - $editSelectorForm.find("[name=type]").val(selector.type); - selector.parentSelectors.forEach(function(parentSelectorId) { - $editSelectorForm.find("#parentSelectors [value='" + parentSelectorId + "']").attr("selected", "selected"); - }); - - this.state.currentSelector = selector; - this.selectorTypeChanged(false); - this.initSelectorValidation(); - }, - - selectorTypeChanged: function(changeTrigger) { - var type = $("#edit-selector select[name=type]").val(); - var features = window[type].getFeatures(); - $("#edit-selector .feature").hide(); - features.forEach(function(feature) { - $("#edit-selector .feature-" + feature).show(); - }); - - if (changeTrigger && type === "SelectorLink"){ - $("#edit-selector [name=extractAttribute]").val("href"); - } - - // add this selector to possible parent selector - var selector = this.getCurrentlyEditedSelector(); - if (selector.canHaveChildSelectors()) { - if ($("#edit-selector #parentSelectors .currently-edited").length === 0) { - var $option = $(""); - $option.text(selector.id).val(selector.id); - $("#edit-selector #parentSelectors").append($option); - } - } - // remove if type doesn't allow to have child selectors - else { - $("#edit-selector #parentSelectors .currently-edited").remove(); - } - }, - saveSelector: function(button) { - - var sitemap = this.state.currentSitemap; - var selector = this.state.currentSelector; - var newSelector = this.getCurrentlyEditedSelector(); - - // cancel submit if invalid form - if (!this.isValidForm()) { - return false; - } - - // cancel possible element selection - this.contentScript.removeCurrentContentSelector().done(function() { - sitemap.updateSelector(selector, newSelector); - - this.store.saveSitemap(sitemap, function() { - this.showSitemapSelectorList(); - }.bind(this)); - }.bind(this)); - }, - /** - * Get selector from selector editing form - */ - getCurrentlyEditedSelector: function() { - var id = $("#edit-selector [name=id]").val(); - var selectorsSelector = $("#edit-selector [name=selector]").val(); - var tableDataRowSelector = $("#edit-selector [name=tableDataRowSelector]").val(); - var tableHeaderRowSelector = $("#edit-selector [name=tableHeaderRowSelector]").val(); - var tableAddMissingColumns = $("#edit-selector [name=tableAddMissingColumns]").is(":checked"); - var verticalTable = $("#edit-selector [name=verticalTable]").is(":checked"); - var clickElementSelector = $("#edit-selector [name=clickElementSelector]").val(); - var type = $("#edit-selector [name=type]").val(); - var clickElementUniquenessType = $("#edit-selector [name=clickElementUniquenessType]").val(); - var clickType = $("#edit-selector [name=clickType]").val(); - var paginationLimit = $("#edit-selector [name=paginationLimit]").val(); - var discardInitialElements = $("#edit-selector [name=discardInitialElements]").is(":checked"); - var multiple = $("#edit-selector [name=multiple]").is(":checked"); - var downloadImage = $("#edit-selector [name=downloadImage]").is(":checked"); - var downloadDocument = $("#edit-selector [name=downloadDocument]").is(":checked"); - var clickPopup = $("#edit-selector [name=clickPopup]").is(":checked"); - var delay = $("#edit-selector [name=delay]").val(); - var extractAttribute = $("#edit-selector [name=extractAttribute]").val(); - var extractStyle = $("#edit-selector [name=extractStyle]").val(); - var value = $("#edit-selector [name=value]").val(); - var parentSelectors = $("#edit-selector [name=parentSelectors]").val(); - var columns = []; - var $columnHeaders = $("#edit-selector .column-header"); - var $columnNames = $("#edit-selector .column-name"); - var $columnExtracts = $("#edit-selector .column-extract"); - var stringReplacement = { - replaceString: $("#edit-selector [name=replaceString]").val(), - replacementString: $("#edit-selector [name=replacementString]").val() - }; - var textmanipulation = { - removeHtml: $("#edit-selector [name=removeHtml]").is(":checked"), - trimText: $("#edit-selector [name=trimText]").is(":checked"), - replaceText: $("#edit-selector [name=replaceText]").val(), - replacementText: $("#edit-selector [name=replacementText]").val(), - textPrefix: $("#edit-selector [name=textPrefix]").val(), - textSuffix: $("#edit-selector [name=textSuffix]").val(), - regex: $("#edit-selector [name=regex]").val(), - regexgroup: $("#edit-selector [name=regexgroup]").val() - }; - - $columnHeaders.each(function(i) { - var header = $($columnHeaders[i]).val(); - var name = $($columnNames[i]).val(); - var extract = $($columnExtracts[i]).is(":checked"); - columns.push({ - header: header, - name: name, - extract: extract - }); - }); - - var newSelector = new Selector({ - id: id, - selector: selectorsSelector, - tableHeaderRowSelector: tableHeaderRowSelector, - tableAddMissingColumns: tableAddMissingColumns, - tableDataRowSelector: tableDataRowSelector, - clickElementSelector: clickElementSelector, - clickElementUniquenessType: clickElementUniquenessType, - clickType: clickType, - paginationLimit: paginationLimit, - discardInitialElements: discardInitialElements, - type: type, - multiple: multiple, - verticalTable: verticalTable, - downloadImage: downloadImage, - downloadDocument: downloadDocument, - clickPopup: clickPopup, - extractAttribute: extractAttribute, - extractStyle: extractStyle, - value: value, - parentSelectors: parentSelectors, - columns: columns, - delay: delay, - textmanipulation: textmanipulation, - stringReplacement: stringReplacement - }); - return newSelector; - }, - /** - * @returns {Sitemap|*} Cloned Sitemap with currently edited selector - */ - getCurrentlyEditedSelectorSitemap: function() { - var sitemap = this.state.currentSitemap.clone(); - var selector = sitemap.getSelectorById(this.state.currentSelector.id); - var newSelector = this.getCurrentlyEditedSelector(); - sitemap.updateSelector(selector, newSelector); - return sitemap; - }, - cancelSelectorEditing: function(button) { - - // cancel possible element selection - this.contentScript.removeCurrentContentSelector().done(function() { - this.showSitemapSelectorList(); - }.bind(this)); - }, - addSelector: function() { - - var parentSelectorId = this.state.currentParentSelectorId; - var sitemap = this.state.currentSitemap; - - var selector = new Selector({ - parentSelectors: [parentSelectorId], - type: "SelectorText", - multiple: false - }); - - this._editSelector(selector, sitemap); - }, - deleteSelector: function(button) { - - var sitemap = this.state.currentSitemap; - var selector = $(button).closest("tr").data("selector"); - sitemap.deleteSelector(selector); - - this.store.saveSitemap(sitemap, function() { - this.showSitemapSelectorList(); - }.bind(this)); - }, - deleteSitemap: function(button) { - var sitemap = $(button).closest("tr").data("sitemap"); - var controller = this; - this.store.deleteSitemap(sitemap, function() { - controller.showSitemaps(); - }); - }, - initScrapeSitemapConfigValidation: function() { - - $("#viewport form").bootstrapValidator({ - fields: { - "requestInterval": { - validators: { - notEmpty: { - message: "The request interval is required and cannot be empty" - }, - numeric: { - message: "The request interval must be numeric" - }, - callback: { - message: "The request interval must be atleast 2000 milliseconds", - callback: function(value, validator) { - return value >= 2000; - } - } - } - }, - "requestIntervalRandomness": { - validators: { - notEmpty: { - message: "The request interval randomness is required and cannot be empty" - }, - numeric: { - message: "The request interval randomness must be numeric" - } - } - }, - "pageLoadDelay": { - validators: { - notEmpty: { - message: "The page load delay is required and cannot be empty" - }, - numeric: { - message: "The page laod delay must be numeric" - }, - callback: { - message: "The page load delay must be atleast 500 milliseconds", - callback: function(value, validator) { - return value >= 500; - } - } - } - } - } - }); - }, - showScrapeSitemapConfigPanel: function() { - - this.setActiveNavigationButton("sitemap-scrape"); - var scrapeConfigPanel = ich.SitemapScrapeConfig(); - $("#viewport").html(scrapeConfigPanel); - this.initScrapeSitemapConfigValidation(); - return true; - }, - scrapeSitemap: function() { - - if (!this.isValidForm()) { - return false; - } - - var requestInterval = $("input[name=requestInterval]").val(); - var pageLoadDelay = $("input[name=pageLoadDelay]").val(); - var intervalRandomness = $("input[name=requestIntervalRandomness]").val(); - - - var sitemap = this.state.currentSitemap; - var request = { - scrapeSitemap: true, - sitemap: JSON.parse(JSON.stringify(sitemap)), - requestInterval: requestInterval, - pageLoadDelay: pageLoadDelay, - requestIntervalRandomness: intervalRandomness - }; - - // show sitemap scraping panel - this.getFormValidator().destroy(); - $(".scraping-in-progress").removeClass("hide"); - $("#submit-scrape-sitemap").closest(".form-group").hide(); - $("#scrape-sitemap-config input").prop("disabled", true); - - chrome.runtime.sendMessage(request, function(selectors) { - // table selector can dynamically add columns - // replace current selector (columns) with the dynamicly created once - sitemap.selectors = []; - for (var n = 0; n < selectors.length; n++) { - var selector = selectors[n]; - sitemap.selectors.push(new Selector(selector)); - } - this.browseSitemapData(); - }.bind(this)); - return false; - }, - sitemapListBrowseSitemapData: function(button) { - var sitemap = $(button).closest("tr").data("sitemap"); - this.setStateEditSitemap(sitemap); - this.browseSitemapData(); - }, - browseSitemapData: function() { - - this.setActiveNavigationButton("sitemap-browse"); - var sitemap = this.state.currentSitemap; - this.store.getSitemapData(sitemap, function(data) { - - var dataColumns = sitemap.getDataColumns(); - - var dataPanel = ich.SitemapBrowseData({ - columns: dataColumns - }); - $("#viewport").html(dataPanel); - - // display data - // Doing this the long way so there aren't xss vulnerubilites - // while working with data or with the selector titles - var $tbody = $("#sitemap-data tbody"); - data.forEach(function(row) { - var $tr = $(""); - dataColumns.forEach(function(column) { - var $td = $(""); - var cellData = row[column]; - if (typeof cellData === "object") { - cellData = JSON.stringify(cellData); - } - $td.text(cellData); - $tr.append($td); - }); - $tbody.append($tr); - }); - }.bind(this)); - - return true; - }, - - showSitemapExportDataCsvPanel: function() { - this.setActiveNavigationButton("sitemap-export-data-csv"); - - var sitemap = this.state.currentSitemap; - var exportPanel = ich.SitemapExportDataCSV(sitemap); - $("#viewport").html(exportPanel); - - $(".result").hide(); - - // generate data - $("#generate-csv").click(function() { - $(".result").show(); - $(".download-button").hide(); - - var options = { - "delimiter": $("#delimiter").val(), - "newline": $("#newline").prop("checked"), - "containBom": $("#utf-bom").prop("checked") - }; - - this.store.getSitemapData(sitemap, function(data) { - var blob = sitemap.getDataExportCsvBlob(data, options); - $(".download-button a").attr("href", window.URL.createObjectURL(blob)); - $(".download-button a").attr("download", sitemap._id + ".csv"); - $(".download-button").show(); - }.bind(this)); - }.bind(this)); - - return true; - }, - - selectSelector: function(button) { - - var input = $(button).closest(".form-group").find("input.selector-value"); - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); - var deferredSelector = this.contentScript.selectSelector({ - parentCSSSelector: parentCSSSelector, - allowedElements: selector.getItemCSSSelector() - }); - - deferredSelector.done(function(result) { - - $(input).val(result.CSSSelector); - - // update validation for selector field - var validator = this.getFormValidator(); - validator.revalidateField(input); - - // @TODO how could this be encapsulated? - // update header row, data row selectors after selecting the table. selectors are updated based on tables - // inner html - if (selector.type === "SelectorTable") { - - this.getSelectorHTML().done(function(html) { - var verticalTable = this.getCurrentlyEditedSelector().verticalTable; - var tableHeaderRowSelector = SelectorTable.getTableHeaderRowSelectorFromTableHTML(html, verticalTable); - var tableDataRowSelector = SelectorTable.getTableDataRowSelectorFromTableHTML(html, verticalTable); - $("input[name=tableHeaderRowSelector]").val(tableHeaderRowSelector); - $("input[name=tableDataRowSelector]").val(tableDataRowSelector); - - var headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(tableHeaderRowSelector, html, verticalTable); - this.renderTableHeaderColumns(headerColumns); - }.bind(this)); - } - - }.bind(this)); - }, - - getCurrentStateParentSelectorIds: function() { - - var parentSelectorIds = this.state.editSitemapBreadcumbsSelectors.map(function(selector) { - return selector.id; - }); - - return parentSelectorIds; - }, - - refreshTableHeaderRowSelector: function(button) { - var input = $(button).closest(".form-group").find("input.selector-value"), - value = input.val(); - var verticalTable = this.getCurrentlyEditedSelector().verticalTable; - this.getSelectorHTML().done(function(html) { - var tableHeaderRowSelector = SelectorTable.getTableHeaderRowSelectorFromTableHTML(html, verticalTable); - var tableDataRowSelector = SelectorTable.getTableDataRowSelectorFromTableHTML(html, verticalTable); - $("input[name=tableHeaderRowSelector]").val(tableHeaderRowSelector); - $("input[name=tableDataRowSelector]").val(tableDataRowSelector); - - var headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(value, html, verticalTable); - this.renderTableHeaderColumns(headerColumns); - }.bind(this)); - - var validator = this.getFormValidator(); - validator.revalidateField(input); - }, - - selectTableHeaderRowSelector: function(button) { - - var input = $(button).closest(".form-group").find("input.selector-value"); - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); - - var deferredSelector = this.contentScript.selectSelector({ - parentCSSSelector: parentCSSSelector, - allowedElements: "tr" - }); - - deferredSelector.done(function(result) { - - var tableHeaderRowSelector = result.CSSSelector; - $(input).val(tableHeaderRowSelector); - - this.getSelectorHTML().done(function(html) { - - var headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(tableHeaderRowSelector, html, this.getCurrentlyEditedSelector().verticalTable); - this.renderTableHeaderColumns(headerColumns); - - }.bind(this)); - - // update validation for selector field - var validator = this.getFormValidator(); - validator.revalidateField(input); - - }.bind(this)); - }, - - selectTableDataRowSelector: function(button) { - - var input = $(button).closest(".form-group").find("input.selector-value"); - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); - - var deferredSelector = this.contentScript.selectSelector({ - parentCSSSelector: parentCSSSelector, - allowedElements: "tr" - }); - - deferredSelector.done(function(result) { - - $(input).val(result.CSSSelector); - - // update validation for selector field - var validator = this.getFormValidator(); - validator.revalidateField(input); - - }.bind(this)); - }, - - /** - * update table selector column editing fields - */ - renderTableHeaderColumns: function(headerColumns) { - - // reset previous columns - var $tbody = $(".feature-columns table tbody"); - $tbody.html(""); - headerColumns.forEach(function(column) { - var $row = ich.SelectorEditTableColumn(column); - $tbody.append($row); - }); - }, - - /** - * Returns HTML that the current selector would select - */ - getSelectorHTML: function() { - - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var CSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); - var deferredHTML = this.contentScript.getHTML({ CSSSelector: CSSSelector }); - - return deferredHTML; - }, - previewSelector: function(button) { - - if (!$(button).hasClass("preview")) { - - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); - var deferredSelectorPreview = this.contentScript.previewSelector({ - parentCSSSelector: parentCSSSelector, - elementCSSSelector: selector.selector - }); - - deferredSelectorPreview.done(function() { - $(button).addClass("preview"); - }); - } else { - - this.contentScript.removeCurrentContentSelector(); - $(button).removeClass("preview"); - } - }, - previewClickElementSelector: function(button) { - - if (!$(button).hasClass("preview")) { - - var sitemap = this.state.currentSitemap; - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); - - var deferredSelectorPreview = this.contentScript.previewSelector({ - parentCSSSelector: parentCSSSelector, - elementCSSSelector: selector.clickElementSelector - }); - - deferredSelectorPreview.done(function() { - $(button).addClass("preview"); - }); - } else { - this.contentScript.removeCurrentContentSelector(); - $(button).removeClass("preview"); - } - }, - previewTableRowSelector: function(button) { - - if (!$(button).hasClass("preview")) { - - var sitemap = this.getCurrentlyEditedSelectorSitemap(); - var selector = this.getCurrentlyEditedSelector(); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); - var rowSelector = $(button).closest(".form-group").find("input").val(); - - var deferredSelectorPreview = this.contentScript.previewSelector({ - parentCSSSelector: parentCSSSelector, - elementCSSSelector: rowSelector - }); - - deferredSelectorPreview.done(function() { - $(button).addClass("preview"); - }); - } else { - this.contentScript.removeCurrentContentSelector(); - $(button).removeClass("preview"); - } - }, - previewSelectorFromSelectorTree: function(button) { - - if (!$(button).hasClass("preview")) { - - var sitemap = this.state.currentSitemap; - var selector = $(button).closest("tr").data("selector"); - var currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); - var parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); - var deferredSelectorPreview = this.contentScript.previewSelector({ - parentCSSSelector: parentCSSSelector, - elementCSSSelector: selector.selector - }); - - deferredSelectorPreview.done(function() { - $(button).addClass("preview"); - }); - } else { - - this.contentScript.removeCurrentContentSelector(); - $(button).removeClass("preview"); - } - }, - previewSelectorDataFromSelectorTree: function(button) { - var sitemap = this.state.currentSitemap; - var selector = $(button).closest("tr").data("selector"); - this.previewSelectorData(sitemap, selector.id); - }, - previewSelectorDataFromSelectorEditing: function() { - var sitemap = this.state.currentSitemap.clone(); - var selector = sitemap.getSelectorById(this.state.currentSelector.id); - var newSelector = this.getCurrentlyEditedSelector(); - sitemap.updateSelector(selector, newSelector); - this.previewSelectorData(sitemap, newSelector.id); - }, - /** - * Returns a list of selector ids that the user has opened - * @returns {Array} - */ - getStateParentSelectorIds: function() { - var parentSelectorIds = []; - this.state.editSitemapBreadcumbsSelectors.forEach(function(selector) { - parentSelectorIds.push(selector.id); - }); - return parentSelectorIds; - }, - previewSelectorData: function(sitemap, selectorId) { - - // data preview will be base on how the selector tree is opened - var parentSelectorIds = this.getStateParentSelectorIds(); - - var request = { - previewSelectorData: true, - sitemap: JSON.parse(JSON.stringify(sitemap)), - parentSelectorIds: parentSelectorIds, - selectorId: selectorId - }; - chrome.runtime.sendMessage(request, function(response) { - - if (response.length === 0) { - return; - } - var dataColumns = Object.keys(response[0]); - - console.log(dataColumns); - - var $dataPreviewPanel = ich.DataPreview({ - columns: dataColumns - }); - $("#viewport").append($dataPreviewPanel); - $dataPreviewPanel.modal("show"); - // display data - // Doing this the long way so there aren't xss vulnerubilites - // while working with data or with the selector titles - var $tbody = $("tbody", $dataPreviewPanel); - response.forEach(function(row) { - var $tr = $(""); - dataColumns.forEach(function(column) { - var $td = $(""); - var cellData = row[column]; - if (typeof cellData === "object") { - cellData = JSON.stringify(cellData); - } - $td.text(cellData); - $tr.append($td); - }); - $tbody.append($tr); - }); - - var windowHeight = $(window).height(); - - $(".data-preview-modal .modal-body").height(windowHeight - 130); - - // remove modal from dom after it is closed - $dataPreviewPanel.on("hidden.bs.modal", function() { - $(this).remove(); - }); - }); - } -}; diff --git a/extension/scripts/DataExtractor.js b/extension/scripts/DataExtractor.js deleted file mode 100644 index 6dc29fea..00000000 --- a/extension/scripts/DataExtractor.js +++ /dev/null @@ -1,322 +0,0 @@ -DataExtractor = function (options) { - - if (options.sitemap instanceof Sitemap) { - this.sitemap = options.sitemap; - } - else { - this.sitemap = new Sitemap(options.sitemap); - } - - this.parentSelectorId = options.parentSelectorId; - this.parentElement = options.parentElement || $("html")[0]; -}; - -DataExtractor.prototype = { - - /** - * Returns a list of independent selector lists. follow=true splits selectors in trees. - * Two side by side type=multiple selectors split trees. - */ - findSelectorTrees: function () { - return this._findSelectorTrees(this.parentSelectorId, new SelectorList()); - }, - - /** - * the selector cannot return multiple records and it also cannot create new jobs. Also all of its child selectors - * must have the same features - * @param selector - * @returns {boolean} - */ - selectorIsCommonToAllTrees: function (selector) { - - // selectors which return mutiple items cannot be common to all - // selectors - if (selector.willReturnMultipleRecords()) { - return false; - } - - // Link selectors which will follow to a new page also cannot be common - // to all selectors - if (selector.canCreateNewJobs() - && this.sitemap.getDirectChildSelectors(selector.id).length > 0) { - return false; - } - - // also all child selectors must have the same features - var childSelectors = this.sitemap.getAllSelectors(selector.id); - for (var i in childSelectors) { - var childSelector = childSelectors[i]; - if (!this.selectorIsCommonToAllTrees(childSelector)) { - return false; - } - } - return true; - }, - - getSelectorsCommonToAllTrees: function (parentSelectorId) { - var commonSelectors = []; - var childSelectors = this.sitemap.getDirectChildSelectors(parentSelectorId); - - childSelectors.forEach(function (childSelector) { - - if (this.selectorIsCommonToAllTrees(childSelector)) { - commonSelectors.push(childSelector); - // also add all child selectors which. Child selectors were also checked - - var selectorChildSelectors = this.sitemap.getAllSelectors(childSelector.id); - selectorChildSelectors.forEach(function (selector) { - if (commonSelectors.indexOf(selector) === -1) { - commonSelectors.push(selector); - } - }); - - } - }.bind(this)); - - return commonSelectors; - }, - - _findSelectorTrees: function (parentSelectorId, commonSelectorsFromParent) { - - var commonSelectors = commonSelectorsFromParent.concat(this.getSelectorsCommonToAllTrees(parentSelectorId)); - - // find selectors that will be making a selector tree - var selectorTrees = []; - var childSelectors = this.sitemap.getDirectChildSelectors(parentSelectorId); - childSelectors.forEach(function (selector) { - - if (!this.selectorIsCommonToAllTrees(selector)) { - // this selector will be making a new selector tree. But this selector might contain some child - // selectors that are making more trees so here should be a some kind of seperation for that - if (!selector.canHaveLocalChildSelectors()) { - var selectorTree = commonSelectors.concat([selector]); - selectorTrees.push(selectorTree); - } - else { - // find selector tree within this selector - var commonSelectorsFromParent = commonSelectors.concat([selector]); - var childSelectorTrees = this._findSelectorTrees(selector.id, commonSelectorsFromParent); - selectorTrees = selectorTrees.concat(childSelectorTrees); - } - } - }.bind(this)); - - // it there were not any selectors that make a separate tree then all common selectors make up a single selector tree - if (selectorTrees.length === 0) { - return [commonSelectors]; - } - else { - return selectorTrees; - } - }, - - getSelectorTreeCommonData: function (selectors, parentSelectorId, parentElement) { - - var childSelectors = selectors.getDirectChildSelectors(parentSelectorId); - var deferredDataCalls = []; - childSelectors.forEach(function (selector) { - if (!selectors.willReturnMultipleRecords(selector.id)) { - deferredDataCalls.push(this.getSelectorCommonData.bind(this,selectors, selector, parentElement)); - } - }.bind(this)); - - var deferredResponse = $.Deferred(); - $.whenCallSequentially(deferredDataCalls).done(function(responses) { - - var commonData = {}; - responses.forEach(function(data) { - commonData = Object.merge(commonData, data); - }); - deferredResponse.resolve(commonData); - }); - - return deferredResponse; - }, - - getSelectorCommonData: function(selectors, selector, parentElement) { - - var d = $.Deferred(); - var deferredData = selector.getData(parentElement); - deferredData.done(function(data) { - - if (selector.willReturnElements()) { - var newParentElement = data[0]; - var deferredChildCommonData = this.getSelectorTreeCommonData(selectors, selector.id, newParentElement); - deferredChildCommonData.done(function(data){ - d.resolve(data); - }); - } - else { - d.resolve(data[0]); - } - }.bind(this)); - - return d; - }, - - /** - * Returns all data records for a selector that can return multiple records - */ - getMultiSelectorData: function(selectors, selector, parentElement, commonData) { - - var deferredResponse = $.Deferred(); - - // if the selector is not an Element selector then its fetched data is the result. - if (!selector.willReturnElements()) { - - var deferredData = selector.getData(parentElement); - deferredData.done(function(selectorData) { - var newCommonData = Object.clone(commonData, true); - var resultData = []; - - selectorData.forEach(function (record) { - Object.merge(record, newCommonData, true); - resultData.push(record); - }.bind(this)); - - deferredResponse.resolve(resultData); - }.bind(this)); - - } - - // handle situation when this selector is an elementSelector - var deferredData = selector.getData(parentElement); - deferredData.done(function(selectorData) { - var deferredDataCalls = []; - - selectorData.forEach(function (element) { - - var newCommonData = Object.clone(commonData, true); - var childRecordDeferredCall = this.getSelectorTreeData.bind(this, selectors, selector.id, element, newCommonData); - deferredDataCalls.push(childRecordDeferredCall); - }.bind(this)); - - $.whenCallSequentially(deferredDataCalls).done(function(responses) { - var resultData = []; - responses.forEach(function(childRecordList) { - childRecordList.forEach(function(childRecord){ - var rec = new Object(); - Object.merge(rec, childRecord, true); - resultData.push(rec); - }); - }); - deferredResponse.resolve(resultData); - }.bind(this)); - }.bind(this)); - - return deferredResponse; - }, - - getSelectorTreeData: function (selectors, parentSelectorId, parentElement, commonData) { - - var childSelectors = selectors.getDirectChildSelectors(parentSelectorId); - var childCommonDataDeferred = this.getSelectorTreeCommonData(selectors, parentSelectorId, parentElement); - var deferredResponse = $.Deferred(); - - childCommonDataDeferred.done(function(childCommonData) { - commonData = Object.merge(commonData, childCommonData); - - var dataDeferredCalls = []; - - childSelectors.forEach(function (selector) { - if (selectors.willReturnMultipleRecords(selector.id)) { - - var newCommonData = Object.clone(commonData, true); - var dataDeferredCall = this.getMultiSelectorData.bind(this, selectors, selector, parentElement, newCommonData); - dataDeferredCalls.push(dataDeferredCall); - } - }.bind(this)); - - // merge all data records together - $.whenCallSequentially(dataDeferredCalls).done(function(responses) { - var resultData = []; - responses.forEach(function(childRecords) { - childRecords.forEach(function(childRecord){ - var rec = new Object(); - Object.merge(rec, childRecord, true); - resultData.push(rec); - }); - }); - - if (resultData.length === 0) { - // If there are no multi record groups then return common data. - // In a case where common data is empty return nothing. - if(Object.keys(commonData).length === 0) { - deferredResponse.resolve([]); - } - else { - - deferredResponse.resolve([commonData]); - } - } - else { - deferredResponse.resolve(resultData); - } - - }.bind(this)); - }.bind(this)); - - return deferredResponse; - }, - - getData: function () { - - var selectorTrees = this.findSelectorTrees(); - var dataDeferredCalls = []; - - selectorTrees.forEach(function (selectorTree) { - - var deferredTreeDataCall = this.getSelectorTreeData.bind(this, selectorTree, this.parentSelectorId, this.parentElement, {}); - dataDeferredCalls.push(deferredTreeDataCall); - }.bind(this)); - - var responseDeferred = $.Deferred(); - $.whenCallSequentially(dataDeferredCalls).done(function(responses) { - var results = []; - responses.forEach(function(dataResults) { - results = results.concat(dataResults); - }.bind(this)); - responseDeferred.resolve(results); - }.bind(this)); - return responseDeferred; - }, - - getSingleSelectorData: function(parentSelectorIds, selectorId) { - - // to fetch only single selectors data we will create a sitemap that only contains this selector, his - // parents and all child selectors - var sitemap = this.sitemap; - var selector = this.sitemap.selectors.getSelector(selectorId); - var childSelectors = sitemap.selectors.getAllSelectors(selectorId); - var parentSelectors = []; - for(var i = parentSelectorIds.length-1;i>=0;i--) { - var id = parentSelectorIds[i]; - if(id === '_root') break; - var parentSelector = this.sitemap.selectors.getSelector(id); - parentSelectors.push(parentSelector); - } - - // merge all needed selectors together - var selectors = parentSelectors.concat(childSelectors); - selectors.push(selector); - sitemap.selectors = new SelectorList(selectors); - - var parentSelectorId; - // find the parent that leaded to the page where required selector is being used - for(var i = parentSelectorIds.length-1;i>=0;i--) { - var id = parentSelectorIds[i]; - if(id === '_root') { - parentSelectorId = id; - break; - } - var parentSelector = this.sitemap.selectors.getSelector(parentSelectorIds[i]); - if(!parentSelector.willReturnElements()) { - parentSelectorId = id; - break; - } - } - this.parentSelectorId = parentSelectorId; - - return this.getData(); - } -}; diff --git a/extension/scripts/DateUtils/SimpleDateFormatter.js b/extension/scripts/DateUtils/SimpleDateFormatter.js deleted file mode 100644 index 93a0adc3..00000000 --- a/extension/scripts/DateUtils/SimpleDateFormatter.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Formatter for Date, parse and format with pattern - * - * @author © Denis Bakhtenkov denis.bakhtenkov@gmail.com - * @version 2016 - * @param {String} pattern - * default is dd.MM.yyyy - * @returns {SimpleDateFormatter} - */ -var SimpleDateFormatter = function (pattern) { - this.pattern = pattern || "dd.MM.yyyy"; - this.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; -}; - -/** - * Return pattern - * @returns {String} - */ -SimpleDateFormatter.prototype.getPattern = function () { - return this.pattern; -}; - -/** - * 'dd.MM.yyyy hh:mm:ss' - * @param {Date} date - * @returns {String} - */ -SimpleDateFormatter.prototype.format = function (date) { - - /** - * Adding left 'zero' if value's length less than digits - * @param {Number} value - * @param {Number} digits - * @returns {String} - */ - function lzero(value, digits) { - digits = digits || 2; - var result = value.toString(); - while (result.length < digits) { - result = "0" + result; - } - return result; - } - - var variants = { - yyyy: date.getFullYear(), - yy: lzero(date.getFullYear() % 100), - MMM: this.months[date.getMonth()], - MM: lzero(date.getMonth() + 1), - dd: lzero(date.getDate()), - hh: lzero(date.getHours()), - mm: lzero(date.getMinutes()), - sss: lzero(date.getMilliseconds(), 3), - ss: lzero(date.getSeconds()) - }; - - var format = this.pattern; - - for (var i in variants) { - format = format.replace(i, variants[i]); - } - - return format; -}; - -/** - * 16.06.2016 - * dd.MM.yyyy - * - * @param {String} string - * @returns {Date} - */ -SimpleDateFormatter.prototype.parse = function (string) { - - var date = new Date(0); - var pat = this.pattern; - var input = string; - var variants = { - yyyy: "date.setFullYear(parseInt(value));", - yy: "date.setYear(parseInt(value) + 2000);", - MMM: "date.setMonth(parseInt(value));", - MM: "date.setMonth(parseInt(value) - 1);", - dd: "date.setDate(parseInt(value));", - hh: "date.setHours(parseInt(value));", - mm: "date.setMinutes(parseInt(value));", - sss: "date.setMilliseconds(parseInt(value));", - ss: "date.setSeconds(parseInt(value));" - }; - - for (var i in variants) { - var pos = pat.search(i); - if (pos !== -1) { - var value = input.substr(pos, i.length); - input = input.substring(0, pos) + input.substring(pos + i.length); - pat = pat.substring(0, pos) + pat.substring(pos + i.length); - if (i === "MMM") { - for (var j in this.months) { - if (value === this.months[j]) { - value = j; - eval(variants[i]); - break; - } - } - } else { - eval(variants[i]); - } - } - } - - return date; -}; \ No newline at end of file diff --git a/extension/scripts/ElementQuery.js b/extension/scripts/ElementQuery.js deleted file mode 100644 index b05c743b..00000000 --- a/extension/scripts/ElementQuery.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Element selector. Uses jQuery as base and adds some more features - * @param parentElement - * @param selector - */ -ElementQuery = function(CSSSelector, parentElement) { - - CSSSelector = CSSSelector || ""; - - var selectedElements = []; - - var addElement = function(element) { - if(selectedElements.indexOf(element) === -1) { - selectedElements.push(element); - } - }; - - var selectorParts = ElementQuery.getSelectorParts(CSSSelector); - selectorParts.forEach(function(selector) { - - // handle special case when parent is selected - if(selector === "_parent_") { - $(parentElement).each(function(i, element){ - addElement(element); - }); - } - else { - var elements = $(selector, parentElement); - elements.each(function(i, element) { - addElement(element); - }); - } - }); - - return selectedElements; -}; - -ElementQuery.getSelectorParts = function(CSSSelector) { - - var selectors = CSSSelector.split(/(,|".*?"|'.*?'|\(.*?\))/); - - var resultSelectors = []; - var currentSelector = ""; - selectors.forEach(function(selector) { - if(selector === ',') { - if(currentSelector.trim().length) { - resultSelectors.push(currentSelector.trim()); - } - currentSelector = ""; - } - else { - currentSelector += selector; - } - }); - if(currentSelector.trim().length) { - resultSelectors.push(currentSelector.trim()); - } - - return resultSelectors; -}; diff --git a/extension/scripts/Job.js b/extension/scripts/Job.js deleted file mode 100644 index c3d0bcb6..00000000 --- a/extension/scripts/Job.js +++ /dev/null @@ -1,84 +0,0 @@ -var Job = function (url, parentSelector, scraper, parentJob, baseData) { - - if (parentJob !== undefined) { - this.url = this.combineUrls(parentJob.url, url); - } - else { - this.url = url; - } - this.parentSelector = parentSelector; - this.scraper = scraper; - this.dataItems = []; - this.baseData = baseData || {}; -}; - -Job.prototype = { - - combineUrls: function (parentUrl, childUrl) { - - var urlMatcher = new RegExp("(https?://)?([a-z0-9\\-\\.]+\\.[a-z0-9\\-]+(:\\d+)?|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d+)?)?(\\/[^\\?]*\\/|\\/)?([^\\?]*)?(\\?.*)?", "i"); - - var parentMatches = parentUrl.match(urlMatcher); - var childMatches = childUrl.match(urlMatcher); - - // special case for urls like this: ?a=1 or like-this/ - if (childMatches[1] === undefined && childMatches[2] === undefined && childMatches[5] === undefined && childMatches[6] === undefined) { - - var url = parentMatches[1] + parentMatches[2] + parentMatches[5] + parentMatches[6] + childMatches[7]; - return url; - } - - if (childMatches[1] === undefined) { - childMatches[1] = parentMatches[1]; - } - if (childMatches[2] === undefined) { - childMatches[2] = parentMatches[2]; - } - if (childMatches[5] === undefined) { - if(parentMatches[5] === undefined) { - childMatches[5] = '/'; - } - else { - childMatches[5] = parentMatches[5]; - } - } - - if (childMatches[6] === undefined) { - childMatches[6] = ""; - } - if (childMatches[7] === undefined) { - childMatches[7] = ""; - } - - return childMatches[1] + childMatches[2] + childMatches[5] + childMatches[6] + childMatches[7]; - }, - - execute: function (browser, callback, scope) { - - var sitemap = this.scraper.sitemap; - var job = this; - browser.fetchData(this.url, sitemap, this.parentSelector, function (results) { - // merge data with data from initialization - for (var i in results) { - var result = results[i]; - for (var key in this.baseData) { - if(!(key in result)) { - result[key] = this.baseData[key]; - } - } - this.dataItems.push(result); - } - - if (sitemap) { - // table selector can dynamically add columns (addMissingColumns Feature) - sitemap.selectors = this.scraper.sitemap.selectors; - } - - console.log(job); - callback(job); - }.bind(this), this); - }, - getResults: function () { - return this.dataItems; - } -}; diff --git a/extension/scripts/Scraper.js b/extension/scripts/Scraper.js deleted file mode 100644 index da3d3f8a..00000000 --- a/extension/scripts/Scraper.js +++ /dev/null @@ -1,212 +0,0 @@ -Scraper = function (options) { - this.queue = options.queue; - this.sitemap = options.sitemap; - this.store = options.store; - this.browser = options.browser; - this.resultWriter = null; // db instance for scraped data writing - this.requestInterval = parseInt(options.requestInterval); - this.requestIntervalRandomness = parseInt(options.requestIntervalRandomness); - this.pageLoadDelay = parseInt(options.pageLoadDelay); -}; - -Scraper.prototype = { - - /** - * Scraping delay between two page opening requests - */ - requestInterval: 2000, - _timeNextScrapeAvailable: 0, - - initFirstJobs: function () { - - var urls = this.sitemap.getStartUrls(); - - urls.forEach(function (url) { - var firstJob = new Job(url, "_root", this); - this.queue.add(firstJob); - }.bind(this)); - }, - - run: function (executionCallback) { - - var scraper = this; - - // callback when scraping is finished - this.executionCallback = executionCallback; - - this.initFirstJobs(); - - this.store.initSitemapDataDb(this.sitemap._id, function (resultWriter) { - scraper.resultWriter = resultWriter; - scraper._run(); - }); - }, - - recordCanHaveChildJobs: function (record) { - if (record._follow === undefined) { - return false; - } - - var selectorId = record._followSelectorId; - var childSelectors = this.sitemap.getDirectChildSelectors(selectorId); - if (childSelectors.length === 0) { - return false; - } - else { - return true; - } - }, - - getFileFilename: function(url) { - - var parts = url.split("/"); - var filename = parts[parts.length-1]; - filename = filename.replace(/\?/g, ""); - if(filename.length > 130) { - filename = filename.substr(0, 130); - } - return filename; - }, - - /** - * Save files for user if the records contains them - * @param record - */ - saveFile: function(record) { - - let deferredResponse = $.Deferred(); - let deferredFileStoreCalls = []; - let prefixLength = "_fileBase64-".length; - - for(let attr in record) { - if(attr.substr(0, prefixLength) === "_fileBase64-") { - var selectorId = attr.substring(prefixLength, attr.length); - deferredFileStoreCalls.push(function(selectorId) { - - var fileBase64 = record['_fileBase64-'+selectorId]; - var documentFilename = record["_filename"+selectorId]; - - var deferredDownloadDone = $.Deferred(); - var deferredBlob = Base64.base64ToBlob(fileBase64, record['_fileMimeType-'+selectorId]); - - delete record['_fileMimeType-'+selectorId]; - delete record['_fileBase64-'+selectorId]; - delete record["_filename"+selectorId]; - - deferredBlob.done(function(blob) { - - var downloadUrl = window.URL.createObjectURL(blob); - var fileSavePath = this.sitemap._id+'/'+selectorId+'/'+documentFilename; - - // download file using chrome api - var downloadRequest = { - url: downloadUrl, - filename: fileSavePath - }; - - // wait for the download to finish - chrome.downloads.download(downloadRequest, function(downloadId) { - var cbDownloaded = function(downloadItem) { - if(downloadItem.id === downloadId && downloadItem.state) { - if(downloadItem.state.current === "complete") { - deferredDownloadDone.resolve(); - chrome.downloads.onChanged.removeListener(cbDownloaded); - } - else if(downloadItem.state.current === "interrupted") { - deferredDownloadDone.reject("download failed"); - chrome.downloads.onChanged.removeListener(cbDownloaded); - } - } - }; - - chrome.downloads.onChanged.addListener(cbDownloaded); - }); - }.bind(this)); - - return deferredDownloadDone.promise(); - - }.bind(this, selectorId)); - } - } - - $.whenCallSequentially(deferredFileStoreCalls).done(function() { - deferredResponse.resolve(); - }); - - return deferredResponse.promise(); - }, - - - - - // @TODO remove recursion and add an iterative way to run these jobs. - _run: function () { - - var job = this.queue.getNextJob(); - if (job === false) { - console.log("Scraper execution is finished"); - this.executionCallback(); - return; - } - - job.execute(this.browser, function (job) { - - var scrapedRecords = []; - var deferredDatamanipulations = []; - - var records = job.getResults(); - records.forEach(function (record) { - //var record = JSON.parse(JSON.stringify(rec)); - - deferredDatamanipulations.push(this.saveFile.bind(this, record)); - - // @TODO refactor job exstraction to a seperate method - if (this.recordCanHaveChildJobs(record)) { - var followSelectorId = record._followSelectorId; - var followURL = record['_follow']; - var followSelectorId = record['_followSelectorId']; - delete record['_follow']; - delete record['_followSelectorId']; - var newJob = new Job(followURL, followSelectorId, this, job, record); - if (this.queue.canBeAdded(newJob)) { - this.queue.add(newJob); - } - // store already scraped links - else { - console.log("Ignoring next") - console.log(record); -// scrapedRecords.push(record); - } - } - else { - if (record._follow !== undefined) { - delete record['_follow']; - delete record['_followSelectorId']; - } - scrapedRecords.push(record); - } - - }.bind(this)); - - $.whenCallSequentially(deferredDatamanipulations).done(function () { - this.store.saveSitemap(this.sitemap, function () { }); - this.resultWriter.writeDocs(scrapedRecords, function () { - - var now = (new Date()).getTime(); - // delay next job if needed - this._timeNextScrapeAvailable = now + this.requestInterval + Math.random()*this.requestIntervalRandomness; - if(now >= this._timeNextScrapeAvailable) { - this._run(); - } - else { - var delay = this._timeNextScrapeAvailable - now; - setTimeout(function() { - this._run(); - }.bind(this), delay); - } - }.bind(this)); - }.bind(this)); - - }.bind(this)); - } -}; diff --git a/extension/scripts/Selector.js b/extension/scripts/Selector.js deleted file mode 100644 index 98e4ed98..00000000 --- a/extension/scripts/Selector.js +++ /dev/null @@ -1,310 +0,0 @@ -var Selector = (function () { - - function Selector(selector) { - this.updateData(selector); - this.initType(); - }; - - Selector.prototype = { - /** - * Manipulates return data from selector. - * @param data - */ - manipulateData: function (data) { - - var regex = function (content, regex, regexgroup) { - try { - content = $.trim(content); - var matches = content.match(new RegExp(regex, 'gm')), - groupDefined = regexgroup !== ""; - - regexgroup = groupDefined ? regexgroup : 0; - - - if (matches !== null) { - return matches[regexgroup]; - } - else { - return ''; - } - } catch (e) { console.log("%c Skipping regular expression: " + e.message, 'background: red; color: white;'); } - }; - - var removeHtml = function (content) { - return $("
").html(content).text(); - } - - var trimText = function (content) { - return content.trim(); - } - - var replaceText = function (content, replaceText, replacementText) { - var replace; - try { - var regex = new RegExp(replaceText, 'gm'); - replace = regex.test(content) ? regex : replaceText; - } catch (e) { replace = replaceText; } - - return content.replace(replace, replacementText); - } - - var textPrefix = function (content, prefix) { - return content = prefix + content; - } - - var textSuffix = function (content, suffix) { - return content += suffix; - } - - $(data).each(function (i, element) { - var content = element[this.id], - isString = typeof content === 'string' || content instanceof String, - isUnderlyingString = !isString && $(content).text() !== "", - isArray = Array.isArray(content), - isTextmManipulationDefined = typeof this.textmanipulation != 'undefined' && this.textmanipulation !== "", - textManipulationAvailable = (isString || isUnderlyingString) && isTextmManipulationDefined; - - if (textManipulationAvailable) { - content = isString ? content : $(content).text(); - - // use key in object since unit tests might not define each property - var keys = [] - for (var key in this.textmanipulation) { - if (!this.textmanipulation.hasOwnProperty(key)) { continue; } - keys.push(key) - } - - function propertyIsAvailable(key) { - return keys.indexOf(key) >= 0; - } - - if (propertyIsAvailable("regex")) { - var group = this.textmanipulation.regexgroup; - var value = this.textmanipulation.regex; - group = typeof group != 'undefined' ? group : ""; - if (value !== '') { content = regex(content, value, group); } - } - - if (propertyIsAvailable("removeHtml")) { - if (this.textmanipulation.removeHtml) { - content = removeHtml(content); - } - } - - if (propertyIsAvailable("trimText")) { - if (this.textmanipulation.trimText) { - content = trimText(content); - } - } - - if (propertyIsAvailable("replaceText")) { - var replacement = this.textmanipulation.replacementText; - replacement = typeof replacement != 'undefined' ? replacement : ""; - content = replaceText(content, this.textmanipulation.replaceText, replacement); - } - - if (propertyIsAvailable("textPrefix")) { - if (this.textmanipulation.textPrefix !== '') { - content = textPrefix(content, this.textmanipulation.textPrefix) - }; - } - - if (propertyIsAvailable("textSuffix")) { - if (this.textmanipulation.textSuffix !== '') { - content = textSuffix(content, this.textmanipulation.textSuffix) - }; - } - - element[this.id] = content; - } else if (isArray && isTextmManipulationDefined) { - element[this.id] = JSON.stringify(content); - this.manipulateData(element); - } - - }.bind(this)); - }, - - /** - * Is this selector configured to return multiple items? - * @returns {boolean} - */ - willReturnMultipleRecords: function () { - return this.canReturnMultipleRecords() && this.multiple; - }, - - /** - * Update current selector configuration - * @param data - */ - updateData: function (data) { - var allowedKeys = ['id', 'type', 'selector', 'parentSelectors']; - allowedKeys = allowedKeys.concat(window[data.type].getFeatures()); - - // update data - for (var key in data) { - if (allowedKeys.indexOf(key) !== -1 || typeof data[key] === 'function') { - this[key] = data[key]; - } - } - - // remove values that are not needed for this type of selector - for (var key in this) { - if (allowedKeys.indexOf(key) === -1 && typeof this[key] !== 'function') { - delete this[key]; - } - } - }, - - /** - * CSS selector which will be used for element selection - * @returns {string} - */ - getItemCSSSelector: function () { - return "*"; - }, - - /** - * override objects methods based on seletor type - */ - initType: function () { - - if (window[this.type] === undefined) { - throw "Selector type not defined " + this.type; - } - - // overrides objects methods - for (var i in window[this.type]) { - this[i] = window[this.type][i]; - } - }, - - /** - * Check whether a selector is a paren selector of this selector - * @param selectorId - * @returns {boolean} - */ - hasParentSelector: function (selectorId) { - return (this.parentSelectors.indexOf(selectorId) !== -1); - }, - - removeParentSelector: function (selectorId) { - var index = this.parentSelectors.indexOf(selectorId); - if (index !== -1) { - this.parentSelectors.splice(index, 1); - } - }, - - renameParentSelector: function (originalId, replacementId) { - if (this.hasParentSelector(originalId)) { - var pos = this.parentSelectors.indexOf(originalId); - this.parentSelectors.splice(pos, 1, replacementId); - } - }, - - getDataElements: function (parentElement) { - - var elements = ElementQuery(this.selector, parentElement); - if (this.multiple) { - return elements; - } - else if (elements.length > 0) { - return [elements[0]]; - } - else { - return []; - } - }, - - stringReplace: function(url, stringReplacement){ - - if (stringReplacement && stringReplacement.replaceString) { - var replace; - var replacement = stringReplacement.replacementString || ""; - try { - var regex = new RegExp(stringReplacement.replaceString, 'gm'); - replace = regex.test(url) ? regex : stringReplacement.replaceString; - } catch (e) { - replace = stringReplacement.replaceString; - } - - return url.replace(replace, replacement); - } else { - return url; - } - - }, - - getData: function (parentElement) { - - var d = $.Deferred(); - var timeout = this.delay || 0; - - // this works much faster because $.whenCallSequentially isn't running next data extraction immediately - if (timeout === 0) { - var deferredData = this._getData(parentElement); - deferredData.done(function (data) { - this.manipulateData(data); - d.resolve(data); - }.bind(this)); - } - else { - setTimeout(function () { - var deferredData = this._getData(parentElement); - deferredData.done(function (data) { - this.manipulateData(data); - d.resolve(data); - }.bind(this)); - }.bind(this), timeout); - } - - return d.promise(); - }, - - - getFilenameFromUrl: function(url) { - - var parts = url.split("/"); - var filename = parts[parts.length-1]; - filename = filename.replace(/\?/g, ""); - if(filename.length > 130) { - filename = filename.substr(0, 130); - } - return filename; - }, - - downloadFileAsBase64: function(url) { - - var deferredResponse = $.Deferred(); - var xhr = new XMLHttpRequest(); - var fileName = this.getFilenameFromUrl(url); - xhr.onreadystatechange = function() { - if (this.readyState == 4) { - if(this.status == 200) { - var blob = this.response; - var mimeType = blob.type; - var deferredBlob = Base64.blobToBase64(blob); - - deferredBlob.done(function(fileBase64) { - deferredResponse.resolve({ - mimeType: mimeType, - fileBase64: fileBase64, - filename: fileName - }); - }); - } - else { - deferredResponse.reject(xhr.statusText); - } - } - }; - xhr.open('GET', url); - xhr.responseType = 'blob'; - xhr.send(); - - return deferredResponse.promise(); - } - }; - - return Selector; -})(); - diff --git a/extension/scripts/Selector/ConstantValue.js b/extension/scripts/Selector/ConstantValue.js deleted file mode 100644 index a8dba5e9..00000000 --- a/extension/scripts/Selector/ConstantValue.js +++ /dev/null @@ -1,40 +0,0 @@ -var ConstantValue = { - - canReturnMultipleRecords: function () { - return false; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - - willReturnElements: function () { - return false; - }, - - _getData: function (parentElement) { - - let dfd = $.Deferred(); - let data = {}; - data[this.id] = this.value; - - dfd.resolve([data]); - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['value'] - } -}; diff --git a/extension/scripts/Selector/SelectorDocument.js b/extension/scripts/Selector/SelectorDocument.js deleted file mode 100644 index 2f4a9b81..00000000 --- a/extension/scripts/Selector/SelectorDocument.js +++ /dev/null @@ -1,95 +0,0 @@ -var SelectorDocument = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - - willReturnElements: function () { - return false; - }, - - _getData: function (parentElement) { - - var elements = this.getDataElements(parentElement); - - var dfd = $.Deferred(); - - // return empty record if not multiple type and no elements found - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id] = null; - dfd.resolve([data]); - return dfd; - } - - // extract links one by one - var deferredDataExtractionCalls = []; - $(elements).each(function (k, element) { - - deferredDataExtractionCalls.push(function (element) { - - var href = this.stringReplace(element.href, this.stringReplacement); - var deferredData = $.Deferred(); - var data = {}; - - data[this.id] = $(element).text(); - - data[this.id + '-href'] = href; - - if(!this.downloadDocument) { - deferredData.resolve(data); - } - else if (href) { - var deferredFileBase64 = this.downloadFileAsBase64(href); - - deferredFileBase64.done(function(base64Response) { - - data['_fileBase64-'+this.id] = base64Response.fileBase64; - data['_fileMimeType-'+this.id] = base64Response.mimeType; - data['_filename'+this.id] = base64Response.filename; - - deferredData.resolve(data); - }.bind(this)).fail(function() { - - deferredData.resolve(data); - }); - } else { - deferredData.resolve(data); - } - return deferredData.promise(); - }.bind(this, element)); - }.bind(this)); - - $.whenCallSequentially(deferredDataExtractionCalls).done(function (responses) { - var result = []; - responses.forEach(function (dataResult) { - result.push(dataResult); - }); - dfd.resolve(result); - }); - - return dfd.promise(); - }, - - - getDataColumns: function () { - return [this.id, this.id + '-href']; - }, - - getFeatures: function () { - return ['selector','multiple', 'delay','downloadDocument','stringReplacement'] - } - - -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorElement.js b/extension/scripts/Selector/SelectorElement.js deleted file mode 100644 index b9190f10..00000000 --- a/extension/scripts/Selector/SelectorElement.js +++ /dev/null @@ -1,39 +0,0 @@ -var SelectorElement = { - - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return true; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return true; - }, - - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - dfd.resolve(jQuery.makeArray(elements)); - - return dfd.promise(); - }, - - getDataColumns: function () { - return []; - }, - - getFeatures: function () { - return ['selector','multiple', 'delay'] - } -}; diff --git a/extension/scripts/Selector/SelectorElementAttribute.js b/extension/scripts/Selector/SelectorElementAttribute.js deleted file mode 100644 index 796043b6..00000000 --- a/extension/scripts/Selector/SelectorElementAttribute.js +++ /dev/null @@ -1,51 +0,0 @@ -var SelectorElementAttribute = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - - var result = []; - $(elements).each(function (k, element) { - var data = {}; - - data[this.id] = $(element).attr(this.extractAttribute); - result.push(data); - }.bind(this)); - - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id + '-src'] = null; - result.push(data); - } - dfd.resolve(result); - - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'extractAttribute', 'delay', 'textmanipulation'] - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorElementClick.js b/extension/scripts/Selector/SelectorElementClick.js deleted file mode 100644 index 8627260b..00000000 --- a/extension/scripts/Selector/SelectorElementClick.js +++ /dev/null @@ -1,179 +0,0 @@ -var SelectorElementClick = { - - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return true; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return true; - }, - - getClickElements: function(parentElement) { - var clickElements = ElementQuery(this.clickElementSelector, parentElement); - return clickElements; - }, - - /** - * Check whether element is still reachable from html. Useful to check whether the element is removed from DOM. - * @param element - */ - isElementInHTML: function(element) { - return $(element).closest("html").length !== 0; - }, - - getElementCSSSelector: function(element) { - - var nthChild, prev; - for(nthChild = 1, prev = element.previousElementSibling; prev !== null;prev = prev.previousElementSibling, nthChild++); - var tagName = element.tagName.toLocaleLowerCase(); - var cssSelector = tagName+":nth-child("+nthChild+")"; - - while(element.parentElement) { - element = element.parentElement; - var tagName = element.tagName.toLocaleLowerCase(); - if(tagName === 'body' || tagName === 'html') { - cssSelector = tagName+">"+cssSelector; - } - else { - for(nthChild = 1, prev = element.previousElementSibling; prev !== null;prev = prev.previousElementSibling, nthChild++); - cssSelector = tagName+":nth-child("+nthChild+")>"+cssSelector; - } - } - - return cssSelector; - }, - - triggerButtonClick: function(clickElement) { - - var cssSelector = this.getElementCSSSelector(clickElement); - - // this function will trigger the click from browser land - var script = document.createElement("script"); - script.type = "text/javascript"; - script.text = "" + - "(function(){ " + - "var el = document.querySelectorAll('"+cssSelector+"')[0]; " + - "el.click(); " + - "})();"; - document.body.appendChild(script); - }, - - getClickElementUniquenessType: function() { - - if(this.clickElementUniquenessType === undefined) { - return 'uniqueText'; - } - else { - return this.clickElementUniquenessType; - } - }, - - _getData: function(parentElement) { - - var paginationLimit = parseInt(this.paginationLimit); - var paginationCount = 1; - var delay = parseInt(this.delay) || 0; - var deferredResponse = $.Deferred(); - var foundElements = new UniqueElementList('uniqueHTMLText'); - var clickElements = this.getClickElements(parentElement); - var doneClickingElements = new UniqueElementList(this.getClickElementUniquenessType()); - - // add elements that are available before clicking - var elements = this.getDataElements(parentElement); - elements.forEach(foundElements.push.bind(foundElements)); - - // discard initial elements - if(this.discardInitialElements) { - foundElements = new UniqueElementList('uniqueText'); - } - - // no elements to click at the beginning - if(clickElements.length === 0) { - deferredResponse.resolve(foundElements); - return deferredResponse.promise(); - } - - // initial click and wait - var currentClickElement = clickElements[0]; - this.triggerButtonClick(currentClickElement); - var nextElementSelection = (new Date()).getTime()+delay; - - // infinitely scroll down and find all items - var interval = setInterval(function() { - - // find those click elements that are not in the black list - var allClickElements = this.getClickElements(parentElement); - clickElements = []; - allClickElements.forEach(function(element) { - if(!doneClickingElements.isAdded(element)) { - clickElements.push(element); - } - }); - - var now = (new Date()).getTime(); - // sleep. wait when to extract next elements - if(now < nextElementSelection) { - //console.log("wait"); - return; - } - - // add newly found elements to element foundElements array. - var elements = this.getDataElements(parentElement); - var addedAnElement = false; - elements.forEach(function(element) { - var added = foundElements.push(element); - if(added) { - addedAnElement = true; - } - }); - //console.log("added", addedAnElement); - - // no new elements found. Stop clicking this button - if(!addedAnElement) { - doneClickingElements.push(currentClickElement); - } - - // continue clicking and add delay, but if there is nothing - // more to click the finish - //console.log("total buttons", clickElements.length) - if(clickElements.length === 0 || paginationCount >= paginationLimit) { - clearInterval(interval); - deferredResponse.resolve(foundElements); - } - else { - paginationCount++; - //console.log("click"); - currentClickElement = clickElements[0]; - // click on elements only once if the type is clickonce - if(this.clickType === 'clickOnce') { - doneClickingElements.push(currentClickElement); - } - this.triggerButtonClick(currentClickElement); - nextElementSelection = now+delay; - } - }.bind(this), 50); - - return deferredResponse.promise(); - }, - - getDataColumns: function () { - return []; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'delay', 'clickElementSelector', 'clickType', - 'discardInitialElements', 'clickElementUniquenessType', - 'paginationLimit']; - } -}; diff --git a/extension/scripts/Selector/SelectorElementScroll.js b/extension/scripts/Selector/SelectorElementScroll.js deleted file mode 100644 index bc6d523d..00000000 --- a/extension/scripts/Selector/SelectorElementScroll.js +++ /dev/null @@ -1,71 +0,0 @@ -var SelectorElementScroll = { - - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return true; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return true; - }, - scrollToBottom: function() { - window.scrollTo(0,document.body.scrollHeight); - }, - _getData: function (parentElement) { - - var paginationLimit = parseInt(this.paginationLimit); - var paginationCount = 1; - var delay = parseInt(this.delay) || 0; - var deferredResponse = $.Deferred(); - var foundElements = []; - - // initially scroll down and wait - this.scrollToBottom(); - var nextElementSelection = (new Date()).getTime()+delay; - - // infinitely scroll down and find all items - var interval = setInterval(function() { - - var now = (new Date()).getTime(); - // sleep. wait when to extract next elements - if(now < nextElementSelection) { - return; - } - - var elements = this.getDataElements(parentElement); - // no new elements found or pagination limit - if(elements.length === foundElements.length || paginationCount >= paginationLimit) { - clearInterval(interval); - deferredResponse.resolve(jQuery.makeArray(elements)); - } - else { - paginationCount++; - // continue scrolling and add delay - foundElements = elements; - this.scrollToBottom(); - nextElementSelection = now+delay; - } - - }.bind(this), 50); - - return deferredResponse.promise(); - }, - - getDataColumns: function () { - return []; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'delay', 'paginationLimit']; - } -}; diff --git a/extension/scripts/Selector/SelectorElementStyle.js b/extension/scripts/Selector/SelectorElementStyle.js deleted file mode 100644 index 89b075d0..00000000 --- a/extension/scripts/Selector/SelectorElementStyle.js +++ /dev/null @@ -1,49 +0,0 @@ -var SelectorElementStyle = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - var elements = this.getDataElements(parentElement); - - var result = []; - $(elements).each(function (k, element) { - var data = {}; - data[this.id] = $(element).css(this.extractStyle); - result.push(data); - }.bind(this)); - - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id + '-src'] = null; - result.push(data); - } - dfd.resolve(result); - - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'extractStyle', 'delay', 'textmanipulation'] - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorGroup.js b/extension/scripts/Selector/SelectorGroup.js deleted file mode 100644 index 3c1acbae..00000000 --- a/extension/scripts/Selector/SelectorGroup.js +++ /dev/null @@ -1,59 +0,0 @@ -var SelectorGroup = { - - canReturnMultipleRecords: function () { - return false; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - // cannot reuse this.getDataElements because it depends on *multiple* property - var elements = $(this.selector, parentElement); - - var records = []; - $(elements).each(function (k, element) { - var data = {}; - - data[this.id] = $(element).text(); - - if (this.extractAttribute) { - data[this.id + '-' + this.extractAttribute] = $(element).attr(this.extractAttribute); - } - - if (this.extractStyle) { - data[this.id + '-' + this.extractStyle] = $(element).css(this.extractStyle); - } - - records.push(data); - }.bind(this)); - - var result = {}; - result[this.id] = records; - - dfd.resolve([result]); - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['selector', 'delay', 'extractAttribute', 'textmanipulation', 'extractStyle'] - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorHTML.js b/extension/scripts/Selector/SelectorHTML.js deleted file mode 100644 index 92fe17f2..00000000 --- a/extension/scripts/Selector/SelectorHTML.js +++ /dev/null @@ -1,56 +0,0 @@ -var SelectorHTML = { - - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - - var result = []; - $(elements).each(function (k, element) { - var data = {}; - var html = $(element).html(); - - // do something - - data[this.id] = html; - - result.push(data); - }.bind(this)); - - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id] = null; - result.push(data); - } - - dfd.resolve(result); - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'textmanipulation', 'delay'] - } -}; diff --git a/extension/scripts/Selector/SelectorImage.js b/extension/scripts/Selector/SelectorImage.js deleted file mode 100644 index bde30e9b..00000000 --- a/extension/scripts/Selector/SelectorImage.js +++ /dev/null @@ -1,94 +0,0 @@ -var SelectorImage = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - - var deferredDataCalls = []; - $(elements).each(function(i, element) { - deferredDataCalls.push(function() { - - var deferredData = $.Deferred(), - data = {}, - src = element.src; - - // get url from style - if (src == null) { - src = $(element).css("background-image"); - src = /^url\((['"]?)(.*)\1\)$/.exec(src); - src = src ? src[2] : ""; - } - - src = this.stringReplace(src, this.stringReplacement); - - data[this.id + '-src'] = src; - - // download image if required - if(!this.downloadImage) { - deferredData.resolve(data); - } - else { - var deferredFileBase64 = this.downloadFileAsBase64(src); - deferredFileBase64.done(function(imageResponse) { - - data['_fileBase64-'+this.id] = imageResponse.fileBase64; - data['_fileMimeType-'+this.id] = imageResponse.mimeType; - data['_filename'+this.id] = imageResponse.filename; - - deferredData.resolve(data); - }.bind(this)).fail(function() { - // failed to download image continue. - // @TODO handle errror - deferredData.resolve(data); - }); - } - - return deferredData.promise(); - }.bind(this)); - }.bind(this)); - - $.whenCallSequentially(deferredDataCalls).done(function(dataResults) { - - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id+'-src'] = null; - dataResults.push(data); - } - - dfd.resolve(dataResults); - }); - - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id + '-src']; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'delay', 'downloadImage', 'stringReplacement'] - }, - - getItemCSSSelector: function() { - return ["img", "div"]; - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorInputValue.js b/extension/scripts/Selector/SelectorInputValue.js deleted file mode 100644 index addf7ed0..00000000 --- a/extension/scripts/Selector/SelectorInputValue.js +++ /dev/null @@ -1,51 +0,0 @@ -var SelectorInputValue = { - - canReturnMultipleRecords: function () { - return false; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return true; - }, - - canCreateNewJobs: function () { - return false; - }, - - willReturnElements: function () { - return false; - }, - - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - - var result = []; - $(elements).each(function (k, element) { - $(element).val(this.value); - }.bind(this)); - - - var data = {}; - data[this.id] = this.value; - result.push(data); - - - dfd.resolve(result); - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['value', 'selector'] - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorLink.js b/extension/scripts/Selector/SelectorLink.js deleted file mode 100644 index 5f52ca02..00000000 --- a/extension/scripts/Selector/SelectorLink.js +++ /dev/null @@ -1,83 +0,0 @@ -var SelectorLink = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return true; - }, - - willReturnElements: function () { - return false; - }, - - _getData: function (parentElement) { - var elements = this.getDataElements(parentElement); - - var dfd = $.Deferred(); - - // return empty record if not multiple type and no elements found - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id] = null; - dfd.resolve([data]); - return dfd; - } - - // extract links one by one - var deferredDataExtractionCalls = []; - $(elements).each(function (k, element) { - - deferredDataExtractionCalls.push(function(element) { - var deferredData = $.Deferred(); - var data = {}; - - var extracted_value; - if (this.extractAttribute) { - extracted_value = element[this.extractAttribute]; - } else { - extracted_value = $(element).text(); - } - extracted_value = this.stringReplace(extracted_value, this.stringReplacement); - - data[this.id] = $(element).text(); - data[this.id + '-href'] = extracted_value; - data._followSelectorId= this.id; - data._follow = extracted_value; - deferredData.resolve(data); - - return deferredData; - }.bind(this, element)); - }.bind(this)); - - $.whenCallSequentially(deferredDataExtractionCalls).done(function(responses) { - var result = []; - responses.forEach(function(dataResult) { - result.push(dataResult); - }); - dfd.resolve(result); - }); - - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id, this.id + '-href']; - }, - - getFeatures: function () { - return ['selector', 'extractAttribute', 'multiple', 'delay', 'stringReplacement'] - }, - - getItemCSSSelector: function() { - return "a"; - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorPopupLink.js b/extension/scripts/Selector/SelectorPopupLink.js deleted file mode 100644 index 3a393b36..00000000 --- a/extension/scripts/Selector/SelectorPopupLink.js +++ /dev/null @@ -1,148 +0,0 @@ -var SelectorPopupLink = { - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return true; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return true; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - var elements = this.getDataElements(parentElement); - - var dfd = $.Deferred(); - - // return empty record if not multiple type and no elements found - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id] = null; - dfd.resolve([data]); - return dfd; - } - - // extract links one by one - var deferredDataExtractionCalls = []; - $(elements).each(function (k, element) { - - deferredDataExtractionCalls.push(function(element) { - - var deferredData = $.Deferred(); - - var data = {}; - data[this.id] = $(element).text(); - data._followSelectorId = this.id; - - var deferredPopupURL = this.getPopupURL(element); - deferredPopupURL.done(function(url) { - data[this.id + '-href'] = url; - data._follow = url; - deferredData.resolve(data); - }.bind(this)); - - return deferredData; - }.bind(this, element)); - }.bind(this)); - - $.whenCallSequentially(deferredDataExtractionCalls).done(function(responses) { - var result = []; - responses.forEach(function(dataResult) { - result.push(dataResult); - }); - dfd.resolve(result); - }); - - return dfd.promise(); - }, - - getElementCSSSelector: function(element) { - - var nthChild, prev; - for(nthChild = 1, prev = element.previousElementSibling; prev !== null;prev = prev.previousElementSibling, nthChild++); - var tagName = element.tagName.toLocaleLowerCase(); - var cssSelector = tagName+":nth-child("+nthChild+")"; - - while(element.parentElement) { - element = element.parentElement; - var tagName = element.tagName.toLocaleLowerCase(); - if(tagName === 'body' || tagName === 'html') { - cssSelector = tagName+">"+cssSelector; - } - else { - for(nthChild = 1, prev = element.previousElementSibling; prev !== null;prev = prev.previousElementSibling, nthChild++); - cssSelector = tagName+":nth-child("+nthChild+")>"+cssSelector; - } - } - - return cssSelector; - }, - - /** - * Gets an url from a window.open call by mocking the window.open function - * @param element - * @returns $.Deferred() - */ - getPopupURL: function(element) { - - // override window.open function. we need to execute this in page scope. - // we need to know how to find this element from page scope. - var cssSelector = this.getElementCSSSelector(element); - - // this function will catch window.open call and place the requested url as the elements data attribute - var script = document.createElement("script"); - script.type = "text/javascript"; - script.text = "" + - "(function(){ " + - "var open = window.open; " + - "var el = document.querySelectorAll('"+cssSelector+"')[0]; " + - "var openNew = function() { " + - "var url = arguments[0]; " + - "el.dataset.webScraperExtractUrl = url; " + - "window.open = open; " + - "};" + - "window.open = openNew; " + - "el.click(); " + - "})();"; - document.body.appendChild(script); - - // wait for url to be available - var deferredURL = $.Deferred(); - var timeout = Math.abs(5000/30); // 5s timeout to generate an url for popup - var interval = setInterval(function() { - var url = $(element).data("web-scraper-extract-url"); - if(url) { - deferredURL.resolve(url); - clearInterval(interval); - script.remove(); - } - // timeout popup opening - if(timeout-- <= 0) { - clearInterval(interval); - script.remove(); - } - }, 30); - - return deferredURL.promise(); - }, - - getDataColumns: function () { - return [this.id, this.id + '-href']; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'delay'] - }, - - getItemCSSSelector: function() { - return "*"; - } -}; \ No newline at end of file diff --git a/extension/scripts/Selector/SelectorTable.js b/extension/scripts/Selector/SelectorTable.js deleted file mode 100644 index bbe3c94a..00000000 --- a/extension/scripts/Selector/SelectorTable.js +++ /dev/null @@ -1,282 +0,0 @@ -var SelectorTable = { - - canReturnMultipleRecords: function() { - return true; - }, - - canHaveChildSelectors: function() { - return false; - }, - - canHaveLocalChildSelectors: function() { - return false; - }, - - canCreateNewJobs: function() { - return false; - }, - - willReturnElements: function() { - return false; - }, - - getTableHeaderColumns: function($table, verticalTable) { - var columns = {}; - var headerRowSelector = this.getTableHeaderRowSelector(); - var $headerRow = $table.find(headerRowSelector); - - if ($headerRow.length > 0) { - if ($headerRow.length > 1) { - if ($headerRow[0].nodeName === "TR") { - $headerRow = $headerRow.find("th:first-child"); - if ($headerRow.length === 0) { - console.log("%c Please specify row header cell selector ", "background: red; color: white;"); - } - } - } else if ($headerRow.find("th").length) { - $headerRow = $headerRow.find("th"); - } else if ($headerRow.find("td").length) { - $headerRow = $headerRow.find("td"); - } - - $headerRow.each(function(i, value) { - var header = $(value).text().trim(); - columns[header] = { - index: i + 1 - }; - }.bind(this)); - - this.addMissingColumns($headerRow); - } - return columns; - }, - - addMissingColumns(headerRow) { - headerRow.each(function(i, value) { - if (this.tableAddMissingColumns) { - var header = $(value).text().trim(); - var column = $.grep(this.columns, function(h) { - return h.name === header; - }); - - if (column.length !== 1) { - this.columns.push({ - header: header, - extract: true - }); - } - } - }.bind(this)); - }, - - getVerticalDataCells: function(table, dataSelector) { - var selectors = $(table).find(dataSelector), - isRow = selectors[0].nodeName === "TR", - result = []; - - if (isRow) { - console.log("%c Please specify row data cell selector ", "background: red; color: white;"); - } else { - for (var i = 0; i < (selectors.length); i++) { - result.push({}); - } - selectors.each(function(i, dataCell) { - if (dataCell.cellIndex === 0) { - console.log("%c Vertical rows can't have first column as data cell ", "background: red; color: white;"); - } else { - var headerCellName = $(dataCell).closest("tr").find("th, td")[0].innerText; - - var listDataColumnName = this.getDataColumnName(headerCellName); - var dataCellvalue = dataCell.innerText; - if (listDataColumnName) { - result[dataCell.cellIndex - 1][listDataColumnName] = dataCellvalue; - } - - } - }.bind(this)); - } - - return result; - }, - - _getData: function(parentElement) { - - var dfd = $.Deferred(); - var verticalTable = this.verticalTable; - var tables = this.getDataElements(parentElement); - - var result = []; - $(tables).each(function(k, table) { - var dataSelector = this.getTableDataRowSelector(); - if (verticalTable) { - var columnsList = this.getVerticalDataCells(table, dataSelector); - columnsList.forEach(function(column) { - if (!$.isEmptyObject(column)) { - result.push(column); - } - - }); - } else { - var columnIndices = this.getTableHeaderColumns($(table)); - $(table).find(dataSelector).each(function(i, dataCell) { - var data = {}; - - this.columns.forEach(function(column) { - var header = columnIndices[column.header.trim()]; - var rowText = $(dataCell).find(">:nth-child(" + header.index + ")").text().trim(); - if (column.extract) { - data[column.name] = rowText; - } - }); - result.push(data); - }.bind(this)); - } - }.bind(this)); - - dfd.resolve(result); - return dfd.promise(); - }, - - getDataColumns: function() { - - var dataColumns = []; - this.columns.forEach(function(column) { - if (column.extract === true) { - dataColumns.push(column.name); - } - }); - return dataColumns; - }, - - getDataColumnName: function(header) { - - var answer = this.columns.find(function(column) { - return (column.extract && header === column.header.trim()); - }); - if (answer) { - return answer.name; - } - - }, - - /** - * Extract table header column info from html - * @param html - */ - getTableHeaderColumnsFromHTML: function(headerRowSelector, html, verticalTable) { - var $table = $(html); - var $headerRowColumns = $table.find(headerRowSelector); - - var columns = []; - if (!verticalTable) { - if ($headerRowColumns.length > 1) { - $headerRowColumns = $headerRowColumns.find("th:first-child"); - } else if ($headerRowColumns.find("th").length) { - $headerRowColumns = $headerRowColumns.find("th"); - } else if ($headerRowColumns.find("td").length) { - $headerRowColumns = $headerRowColumns.find("td"); - } - } - $headerRowColumns.each(function(i, columnEl) { - var header = columnEl.innerText; - if (header) { - columns.push({ - header: header, - name: header, - extract: true - }); - } - }); - return columns; - }, - - getTableHeaderRowSelectorFromTableHTML: function(html, verticalTable) { - var $table = $(html); - var firstRow = $table.find("tr:first-child"); - var rowCount = $table.find("tr").length; - - if ($table.find("thead tr:has(td:not(:empty)), thead tr:has(th:not(:empty))").length) { - - if ($table.find("thead tr").length === 1) { - return "thead tr"; - } else { - var $rows = $table.find("thead tr"); - // first row with data - var rowIndex = $rows.index($rows.filter(":has(td:not(:empty)),:has(th:not(:empty))")[0]); - return "thead tr:nth-of-type(" + (rowIndex + 1) + ")"; - } - } else { - if (!verticalTable) { - if (firstRow.find("th:not(:empty)").length > 1) { - return "tr:nth-of-type(1)"; - } else if (firstRow.find("th:first-child:not(:empty)").length === 1 && firstRow.children().length > 1) { - return "tr"; - } else if ($table.find("tr td:not(:empty), tr th:not(:empty)").length) { - var $rows = $table.find("tr"); - // first row with data - var rowIndex = $rows.index($rows.filter(":has(td:not(:empty)),:has(th:not(:empty))")[0]); - return "tr:nth-of-type(" + (rowIndex + 1) + ")"; - } else { - return ""; - } - } else { - if (firstRow.find("th").length) { - return "tr>th"; - } else { - return "tr>td:nth-of-type(1)"; - } - } - - - } - }, - - getTableDataRowSelectorFromTableHTML: function(html, verticalTable) { - - var $table = $(html); - if ($table.find("thead tr:has(td:not(:empty)), thead tr:has(th:not(:empty))").length) { - - return "tbody tr"; - } else { - if (!verticalTable) { - if ($table.find("tr td:not(:empty), tr th:not(:empty)").length) { - var $rows = $table.find("tr"); - // first row with data - var rowIndex = $rows.index($rows.filter(":has(td:not(:empty)),:has(th:not(:empty))")[0]); - return "tr:nth-of-type(n+" + (rowIndex + 2) + ")"; - } - } else { - if ($table.find("th").length) return "tr>td"; - else return "tr>td:nth-of-type(n+2)"; - } - - } - }, - - getFeatures: function() { - return ["selector", "multiple", "columns", "delay", "tableDataRowSelector", "tableHeaderRowSelector", "tableAddMissingColumns", "verticalTable"]; - }, - - getItemCSSSelector: function() { - return "table"; - }, - - getTableHeaderRowSelector: function() { - // handle legacy selectors - if (this.tableHeaderRowSelector === undefined) { - return "thead tr"; - } else { - return this.tableHeaderRowSelector; - } - }, - - getTableDataRowSelector: function() { - // handle legacy selectors - if (this.tableDataRowSelector === undefined) { - return "tbody tr"; - } else { - return this.tableDataRowSelector; - } - } - -}; diff --git a/extension/scripts/Selector/SelectorText.js b/extension/scripts/Selector/SelectorText.js deleted file mode 100644 index 6440298e..00000000 --- a/extension/scripts/Selector/SelectorText.js +++ /dev/null @@ -1,58 +0,0 @@ -var SelectorText = { - - canReturnMultipleRecords: function () { - return true; - }, - - canHaveChildSelectors: function () { - return false; - }, - - canHaveLocalChildSelectors: function () { - return false; - }, - - canCreateNewJobs: function () { - return false; - }, - willReturnElements: function () { - return false; - }, - _getData: function (parentElement) { - - var dfd = $.Deferred(); - - var elements = this.getDataElements(parentElement); - - var result = []; - $(elements).each(function (k, element) { - var data = {}; - - // remove script, style tag contents from text results - var $element_clone = $(element).clone(); - $element_clone.find("script, style").remove(); - //
replace br tags with newlines - $element_clone.find("br").after("\n"); - data[this.id] = $element_clone.text(); - - result.push(data); - }.bind(this)); - - if (this.multiple === false && elements.length === 0) { - var data = {}; - data[this.id] = null; - result.push(data); - } - - dfd.resolve(result); - return dfd.promise(); - }, - - getDataColumns: function () { - return [this.id]; - }, - - getFeatures: function () { - return ['selector', 'multiple', 'delay', 'textmanipulation'] - } -}; diff --git a/extension/scripts/SelectorGraph.js b/extension/scripts/SelectorGraph.js deleted file mode 100644 index 314b341a..00000000 --- a/extension/scripts/SelectorGraph.js +++ /dev/null @@ -1,149 +0,0 @@ -var SelectorGraph = function (sitemap) { - this.sitemap = sitemap; - this.nodes = []; - this.nodes.push({id: '_root', parentSelectors: []}); - sitemap.selectors.forEach(function (selector) { - this.nodes.push(JSON.parse(JSON.stringify(selector))); - }.bind(this)); -}; - -SelectorGraph.prototype = { - - getNodes: function () { - return this.nodes; - }, - - getLabelAnchors: function () { - var labelAnchors = []; - this.nodes.forEach(function (node) { - labelAnchors.push({node: node}); - labelAnchors.push({node: node}); - }); - return labelAnchors; - }, - - getLabelAnchorLinks: function () { - var labelAnchorLinks = []; - for (var i = 0; i < this.nodes.length; i++) { - labelAnchorLinks.push({ - source: i * 2, - target: i * 2 + 1, - weight: 1 - }); - } - return labelAnchorLinks; - }, - - getNodeById: function (nodeId) { - for (var i in this.nodes) { - var node = this.nodes[i]; - if (node.id === nodeId) { - return node; - } - } - }, - - getLinks: function () { - var links = []; - this.nodes.forEach(function (selector) { - selector.parentSelectors.forEach(function (parentSelectorId) { - var parentSelector = this.getNodeById(parentSelectorId); - links.push({ - source: selector, - target: parentSelector, - weight: 1 - }); - }.bind(this)); - }.bind(this)); - return links; - }, - - draw: function (element, w, h) { - - var labelDistance = 0; - - var vis = d3.select(element).append("svg:svg").attr("width", w).attr("height", h); - - var nodes = this.getNodes(); - var labelAnchors = this.getLabelAnchors(); - var labelAnchorLinks = this.getLabelAnchorLinks(); - var links = this.getLinks(); - - var force = d3.layout.force().size([w, h]).nodes(nodes).links(links).gravity(1).linkDistance(50).charge(-3000).linkStrength(function (x) { - return x.weight * 10 - }); - - force.start(); - - var force2 = d3.layout.force().nodes(labelAnchors).links(labelAnchorLinks).gravity(0).linkDistance(0).linkStrength(8).charge(-100).size([w, h]); - force2.start(); - - var link = vis.selectAll("line.link").data(links).enter().append("svg:line").attr("class", "link").style("stroke", "#CCC"); - - var node = vis.selectAll("g.node").data(force.nodes()).enter().append("svg:g").attr("class", "node"); - node.append("svg:circle").attr("r", 5).style("fill", "#555").style("stroke", "#FFF").style("stroke-width", 3); - node.call(force.drag); - - - var anchorLink = vis.selectAll("line.anchorLink").data(labelAnchorLinks)//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); - - var anchorNode = vis.selectAll("g.anchorNode").data(force2.nodes()).enter().append("svg:g").attr("class", "anchorNode"); - anchorNode.append("svg:circle").attr("r", 0).style("fill", "#FFF"); - anchorNode.append("svg:text").text(function (d, i) { - return i % 2 == 0 ? "" : d.node.id - }).style("fill", "#555").style("font-family", "Arial").style("font-size", 12); - - var updateLink = function () { - this.attr("x1",function (d) { - return d.source.x; - }).attr("y1",function (d) { - return d.source.y; - }).attr("x2",function (d) { - return d.target.x; - }).attr("y2", function (d) { - return d.target.y; - }); - - } - - var updateNode = function () { - this.attr("transform", function (d) { - return "translate(" + d.x + "," + d.y + ")"; - }); - - } - - force.on("tick", function () { - - force2.start(); - - node.call(updateNode); - - anchorNode.each(function (d, i) { - if (i % 2 == 0) { - d.x = d.node.x; - d.y = d.node.y; - } else { - var b = this.childNodes[1].getBBox(); - - var diffX = d.x - d.node.x; - var diffY = d.y - d.node.y; - - var dist = Math.sqrt(diffX * diffX + diffY * diffY); - - var shiftX = b.width * (diffX - dist) / (dist * 2); - shiftX = Math.max(-b.width, Math.min(0, shiftX)); - var shiftY = 5; - this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); - } - }); - - - anchorNode.call(updateNode); - - link.call(updateLink); - anchorLink.call(updateLink); - - }); - } -}; \ No newline at end of file diff --git a/extension/scripts/SelectorGraphv2.js b/extension/scripts/SelectorGraphv2.js deleted file mode 100644 index 51e93ff6..00000000 --- a/extension/scripts/SelectorGraphv2.js +++ /dev/null @@ -1,219 +0,0 @@ -var SelectorGraphv2 = function (sitemap) { - this.sitemap = sitemap; -}; - -SelectorGraphv2.prototype = { - - /** - * Inits d3.layout.tree - */ - initTree: function (w, h) { - - this.tree = d3.layout.tree().size([h, w]); - this.tree.children(this.getSelectorVisibleChildren.bind(this)); - }, - getSelectorChildren: function (parentSelector) { - - if (parentSelector.childSelectors === undefined) { - parentSelector.childSelectors = this.sitemap.selectors.getDirectChildSelectors(parentSelector.id).fullClone(); - } - - if (parentSelector.childSelectors.length === 0) { - return null; - } - else { - return parentSelector.childSelectors; - } - }, - - getSelectorVisibleChildren: function (parentSelector) { - - // initially hide selector children - if (parentSelector.visibleChildren === undefined) { - parentSelector.visibleChildren = false; - } - - if (parentSelector.visibleChildren === false) { - return null; - } - - return this.getSelectorChildren(parentSelector); - - }, - - selectorHasChildren: function (parentSelector) { - - var children = this.sitemap.selectors.getDirectChildSelectors(parentSelector.id); - var selectorHasChildren = children.length > 0; - return selectorHasChildren; - }, - - /** - * function for line drawing between two nodes - */ - diagonal: d3.svg.diagonal() - .projection(function (d) { - return [d.y, d.x]; - }), - - draw: function (element, w, h) { - var m = [20, 120, 20, 120], - w = w - m[1] - m[3], - h = h - m[0] - m[2], - i = 0, - root, - selectorList; - - this.initTree(w, h); - - // @TODO use element - this.svg = d3.select(element).append("svg:svg") - .attr("width", w + m[1] + m[3]) - .attr("height", h + m[0] + m[2]) - .append("svg:g") - .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); - - this.root = { - id: '_root', - x0: h / 2, - y0: 0, - i: '_root' - }; - - this.update(this.root); - }, - - /** - * Color for selectors circle - * @param selector - */ - getNodeColor: function (selector) { - - if (this.selectorHasChildren(selector) && !selector.visibleChildren) { - return "lightsteelblue"; - } - else { - return "#fff"; - } - }, - - update: function (source) { - var duration = 500; - - // Compute the new tree layout. - var nodes = this.tree.nodes(this.root).reverse(); - - // Normalize for fixed-depth. - nodes.forEach(function (d) { - d.y = d.depth * 100; - }); - var i = 0; - // Update the nodes… - var node = this.svg.selectAll("g.node") - .data(nodes, function (d) { - if (d.i === undefined) { - d.i = d.id; - d.i = source.i + "/" + d.i; - } - return d.i; - }); - - // Enter any new nodes at the parent's previous position. - var nodeEnter = node.enter().append("svg:g") - .attr("class", "node") - .attr("transform", function (d) { - return "translate(" + source.y0 + "," + source.x0 + ")"; - }) - .on("click", function (d) { - this.toggle(d); - this.update(d); - }.bind(this)); - - nodeEnter.append("svg:circle") - .attr("r", 1e-6) - .style("fill", this.getNodeColor.bind(this)); - - nodeEnter.append("svg:text") - .attr("x", function (d) { - return this.selectorHasChildren(d) ? -10 : 10; - }.bind(this)) - .attr("dy", ".35em") - .attr("text-anchor", function (d) { - return this.selectorHasChildren(d) ? "end" : "start"; - }.bind(this)) - .text(function (d) { - return d.id; - }) - .style("fill-opacity", 1e-6); - - // Transition nodes to their new position. - var nodeUpdate = node.transition() - .duration(duration) - .attr("transform", function (d) { - return "translate(" + d.y + "," + d.x + ")"; - }); - - nodeUpdate.select("circle") - .attr("r", 6) - .style("fill", this.getNodeColor.bind(this)); - - nodeUpdate.select("text") - .style("fill-opacity", 1); - - // Transition exiting nodes to the parent's new position. - var nodeExit = node.exit().transition() - .duration(duration) - .attr("transform", function (d) { - return "translate(" + source.y + "," + source.x + ")"; - }) - .remove(); - - nodeExit.select("circle") - .attr("r", 1e-6); - - nodeExit.select("text") - .style("fill-opacity", 1e-6); - - // Update the links… - var link = this.svg.selectAll("path.link") - .data(this.tree.links(nodes), function (d) { - return d.target.i; - }); - - // Enter any new links at the parent's previous position. - link.enter().insert("svg:path", "g") - .attr("class", "link") - .attr("d", function (d) { - var o = {x: source.x0, y: source.y0}; - var res = this.diagonal({source: o, target: o}); - return res; - }.bind(this)) - .transition() - .duration(duration) - .attr("d", this.diagonal); - - // Transition links to their new position. - link.transition() - .duration(duration) - .attr("d", this.diagonal); - - // Transition exiting nodes to the parent's new position. - link.exit().transition() - .duration(duration) - .attr("d", function (d) { - var o = {x: source.x, y: source.y}; - return this.diagonal({source: o, target: o}); - }.bind(this)) - .remove(); - - // Stash the old positions for transition. - nodes.forEach(function (d) { - d.x0 = d.x; - d.y0 = d.y; - }); - }, - - toggle: function (d) { - d.visibleChildren = !d.visibleChildren; - } -}; \ No newline at end of file diff --git a/extension/scripts/SelectorList.js b/extension/scripts/SelectorList.js deleted file mode 100644 index d925cd66..00000000 --- a/extension/scripts/SelectorList.js +++ /dev/null @@ -1,281 +0,0 @@ -var SelectorList = function (selectors) { - - if(selectors === undefined) { - return; - } - - for(var i = 0;i 0; i--) { - - var parentSelectorId = parentSelectorIds[i]; - var parentSelector = this.getSelector(parentSelectorId); - if(parentSelector.willReturnElements()) { - CSSSelector = parentSelector.selector + " " + CSSSelector; - } - else { - break; - } - } - - return CSSSelector; -}; - -SelectorList.prototype.hasRecursiveElementSelectors = function() { - - var RecursionFound = false; - - this.forEach(function(topSelector) { - var visitedSelectors = []; - - var checkRecursion = function(parentSelector) { - - // already visited - if(visitedSelectors.indexOf(parentSelector) !== -1) { - RecursionFound = true; - return; - } - - if(parentSelector.willReturnElements()) { - visitedSelectors.push(parentSelector); - var childSelectors = this.getDirectChildSelectors(parentSelector.id); - childSelectors.forEach(checkRecursion); - visitedSelectors.pop(); - } - }.bind(this); - - checkRecursion(topSelector); - - }.bind(this)); - - return RecursionFound; -}; - diff --git a/extension/scripts/Sitemap.js b/extension/scripts/Sitemap.js deleted file mode 100644 index dcfcca1d..00000000 --- a/extension/scripts/Sitemap.js +++ /dev/null @@ -1,260 +0,0 @@ -/* global DatePatternSupport */ - -var Sitemap = function (sitemapObj) { - this.initData(sitemapObj); -}; - -Sitemap.prototype = { - - initData: function (sitemapObj) { - for (let key in sitemapObj) { - this[key] = sitemapObj[key]; - } - - if (!Array.isArray(this.startUrls)) { - let startUrl = this.startUrls; - this.startUrls = startUrl ? [startUrl] : []; - } - - var selectors = this.selectors; - this.selectors = new SelectorList(this.selectors); - }, - - /** - * Returns all selectors or recursively find and return all child selectors of a parent selector. - * @param parentSelectorId - * @returns {Array} - */ - getAllSelectors: function (parentSelectorId) { - - return this.selectors.getAllSelectors(parentSelectorId); - }, - - /** - * Returns only selectors that are directly under a parent - * @param parentSelectorId - * @returns {Array} - */ - getDirectChildSelectors: function (parentSelectorId) { - return this.selectors.getDirectChildSelectors(parentSelectorId); - }, - - /** - * Returns all selector id parameters - * @returns {Array} - */ - getSelectorIds: function () { - var ids = ['_root']; - this.selectors.forEach(function(selector){ - ids.push(selector.id); - }); - return ids; - }, - - /** - * Returns only selector ids which can have child selectors - * @returns {Array} - */ - getPossibleParentSelectorIds: function () { - var ids = ['_root']; - this.selectors.forEach(function(selector){ - if(selector.canHaveChildSelectors()){ - ids.push(selector.id); - } - }.bind(this)); - return ids; - }, - - getStartUrls: function() { - - var startUrls = this.startUrls; - startUrls = DatePatternSupport.expandUrl(startUrls); - - var nextUrls = function (url) { - var urls = []; - var lpad = function (str, length) { - while (str.length < length) - str = "0" + str; - return str; - }; - - var re = /^(.*?)\[(\d+)\-(\d+)(:(\d+))?\](.*)$/; - var matches = url.match(re); - if (matches) { - var startStr = matches[2]; - var endStr = matches[3]; - var start = parseInt(startStr); - var end = parseInt(endStr); - var incremental = 1; - console.log(matches[5]); - if (matches[5] !== undefined) { - incremental = parseInt(matches[5]); - } - var nextSet = nextUrls(matches[6]); - for (var i = start; i <= end; i += incremental) { - var current; - - // with zero padding - if (startStr.length === endStr.length) { - current = matches[1] + lpad(i.toString(), startStr.length); - } - else { - current = matches[1] + i; - } - nextSet.forEach(function (next) { - urls.push(current + next); - }); - } - } else { - urls.push(url); - } - return urls; - }; - var urls = []; - - startUrls.forEach(function(startUrl) { - urls = urls.concat(nextUrls(startUrl)); - }); - - return urls; - }, - - updateSelector: function (selector, selectorData) { - - // selector is undefined when creating a new one - if(selector === undefined) { - selector = new Selector(selectorData); - } - - // update child selectors - if (selector.id !== undefined && selector.id !== selectorData.id) { - this.selectors.forEach(function (currentSelector) { - currentSelector.renameParentSelector(selector.id, selectorData.id) - }); - - // update cyclic selector - var pos = selectorData.parentSelectors.indexOf(selector.id); - if (pos !== -1) { - selectorData.parentSelectors.splice(pos, 1, selectorData.id); - } - } - - selector.updateData(selectorData); - - if (this.getSelectorIds().indexOf(selector.id) === -1) { - this.selectors.push(selector); - } - }, - deleteSelector: function (selectorToDelete) { - - this.selectors.forEach(function(selector) { - if(selector.hasParentSelector(selectorToDelete.id)) { - selector.removeParentSelector(selectorToDelete.id); - if(selector.parentSelectors.length === 0) { - this.deleteSelector(selector) - } - } - }.bind(this)); - - for (var i in this.selectors) { - if (this.selectors[i].id === selectorToDelete.id) { - this.selectors.splice(i, 1); - break; - } - } - }, - getDataTableId: function () { - return this._id.replace(/\./g, '_'); - }, - exportSitemap: function () { - function removeEmpty(obj) { - Object.keys(obj).forEach( - function(key) { - if (obj[key] && typeof obj[key] === 'object') { - removeEmpty(obj[key]); - if (Object.keys(obj[key]).length === 0) { - delete obj[key]; - } - } else if (obj[key] === false || obj[key] === [] || obj[key] === '') { - delete obj[key]; - } - }); - } - let sitemapObj = JSON.parse(JSON.stringify(this)); - delete sitemapObj._rev; - removeEmpty(sitemapObj); - return JSON.stringify(sitemapObj); - }, - importSitemap: function (sitemapJSON) { - var sitemapObj = JSON.parse(sitemapJSON); - this.initData(sitemapObj); - }, - // return a list of columns than can be exported - getDataColumns: function () { - var columns = []; - this.selectors.forEach(function (selector) { - columns = columns.concat(selector.getDataColumns()); - }); - - var uniqueColumns = []; - $.each(columns, function (i, e) { - if ($.inArray(e, uniqueColumns) == -1) uniqueColumns.push(e); - }); - - return uniqueColumns; - }, - getDataExportCsvBlob: function (data, option) { - - var delimiterKey = "delimiter"; - var newlineKey = "newline"; - var containBomKey = "containBom"; - - var columns = this.getDataColumns(), - // default delimiter is comma - delimiter = option.hasOwnProperty(delimiterKey) ? option[delimiterKey] : ',', - // per default, new line is included at end of lines - newline = option.hasOwnProperty(newlineKey) ? (option[newlineKey] == true ? "\r\n" : "") : "\r\n", - // per default, utf8 BOM is included at the beginning. - prepend = option.hasOwnProperty(containBomKey) ? (option[containBomKey] == true ? '\ufeff' : '') : '\ufeff', // utf-8 bom char - options = { - quotes: false, - quoteChar: '"', - delimiter: delimiter, - header: true, - newline: "\r\n" // between value rows - }, - jsonData = []; - - // data - data.forEach(function (row) { - var jsonRow = {}; - columns.forEach(function (column) { - var cellData = row[column]; - if (cellData === undefined) { - cellData = ""; - } - else if (typeof cellData === 'object') { - cellData = JSON.stringify(cellData); - } - - jsonRow[column] = cellData; - }); - jsonData.push(jsonRow); - }); - - return new Blob([prepend + Papa.unparse(jsonData, options) + newline], {type: 'text/csv'}); - }, - getSelectorById: function (selectorId) { - return this.selectors.getSelectorById(selectorId); - }, - /** - * Create full clone of sitemap - * @returns {Sitemap} - */ - clone: function () { - var clonedJSON = JSON.parse(JSON.stringify(this)); - var sitemap = new Sitemap(clonedJSON); - return sitemap; - } -}; - diff --git a/extension/scripts/StoreDevtools.js b/extension/scripts/StoreDevtools.js deleted file mode 100644 index a7a8bdc3..00000000 --- a/extension/scripts/StoreDevtools.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * From devtools panel there is no possibility to execute XHR requests. So all requests to a remote CouchDb must be - * handled through Background page. StoreDevtools is a simply a proxy store - * @constructor - */ -var StoreDevtools = function () { - -}; - -StoreDevtools.prototype = { - createSitemap: function (sitemap, callback) { - - var request = { - createSitemap: true, - sitemap: JSON.parse(JSON.stringify(sitemap)) - }; - - chrome.runtime.sendMessage(request, function (callbackFn, originalSitemap, newSitemap) { - originalSitemap._rev = newSitemap._rev; - callbackFn(originalSitemap); - }.bind(this, callback, sitemap)); - }, - saveSitemap: function (sitemap, callback) { - this.createSitemap(sitemap, callback); - }, - deleteSitemap: function (sitemap, callback) { - - var request = { - deleteSitemap: true, - sitemap: JSON.parse(JSON.stringify(sitemap)) - }; - chrome.runtime.sendMessage(request, function (response) { - callback(); - }); - }, - getAllSitemaps: function (callback) { - - var request = { - getAllSitemaps: true - }; - - chrome.runtime.sendMessage(request, function (response) { - - var sitemaps = []; - - for (var i in response) { - sitemaps.push(new Sitemap(response[i])); - } - callback(sitemaps); - }); - }, - getSitemapData: function (sitemap, callback) { - var request = { - getSitemapData: true, - sitemap: JSON.parse(JSON.stringify(sitemap)) - }; - - chrome.runtime.sendMessage(request, function (response) { - callback(response); - }); - }, - sitemapExists: function (sitemapId, callback) { - - var request = { - sitemapExists: true, - sitemapId: sitemapId - }; - - chrome.runtime.sendMessage(request, function (response) { - callback(response); - }); - } -}; \ No newline at end of file diff --git a/extension/scripts/StorePouchDB.js b/extension/scripts/StorePouchDB.js deleted file mode 100644 index 729f8729..00000000 --- a/extension/scripts/StorePouchDB.js +++ /dev/null @@ -1,161 +0,0 @@ -var StorePouchDB = function (config) { - this.config = config; - - // configure couchdb - this.sitemapDb = new PouchDB(this.config.sitemapDb); -}; - -var StoreScrapeResultWriter = function(db) { - this.db = db; -}; - -/** -* Make sure all obj have the same properties -* They can differe if table selector retrieves dynamic columns -*/ -var normalizeProperties = function (docs) { - // get all keys of the objects - var keys = []; - docs.forEach(function (doc) { - for (var key in doc) { - if (doc.hasOwnProperty(key) && keys.indexOf(key) === -1) { keys.push(key); } - }; - }); - - // add missing keys to objects - docs.forEach(function (doc) { - var objKeys = Object.keys(doc) - keys.forEach(function (key) { - if (!(key in doc)) { - doc[key] = ""; - } - }); - }); -}; - -StoreScrapeResultWriter.prototype = { - - writeDocs: function(docs, callback) { - if(docs.length === 0) { - callback(); - } - else { - - normalizeProperties(docs); - this.db.bulkDocs({docs:docs}, function(err, response) { - if(err !== null) { - console.log("Error while persisting scraped data to db", err); - } - callback(); - }); - } - } -}; - -StorePouchDB.prototype = { - - sanitizeSitemapDataDbName: function(dbName) { - return 'sitemap-data-'+dbName.replace(/[^a-z0-9_\$\(\)\+\-/]/gi, "_"); - }, - getSitemapDataDbLocation: function(sitemapId) { - var dbName = this.sanitizeSitemapDataDbName(sitemapId); - return this.config.dataDb+dbName; - }, - getSitemapDataDb: function(sitemapId) { - - var dbLocation = this.getSitemapDataDbLocation(sitemapId); - return new PouchDB(dbLocation); - }, - - /** - * creates or clears a sitemap db - * @param {type} sitemapId - * @returns {undefined} - */ - initSitemapDataDb: function(sitemapId, callback) { - var dbLocation = this.getSitemapDataDbLocation(sitemapId); - var store = this; - - PouchDB.destroy(dbLocation, function() { - var db = store.getSitemapDataDb(sitemapId); - var dbWriter = new StoreScrapeResultWriter(db); - callback(dbWriter); - }); - }, - - createSitemap: function (sitemap, callback) { - - var sitemapJson = JSON.parse(JSON.stringify(sitemap)); - - if(!sitemap._id) { - console.log("cannot save sitemap without an id", sitemap); - } - - this.sitemapDb.put(sitemapJson, function(sitemap, err, response) { - // @TODO handle err - if (response) { - sitemap._rev = response.rev; - } - callback(sitemap); - }.bind(this, sitemap)); - }, - saveSitemap: function (sitemap, callback) { - // @TODO remove - this.createSitemap(sitemap, callback); - }, - deleteSitemap: function (sitemap, callback) { - - sitemap = JSON.parse(JSON.stringify(sitemap)); - - this.sitemapDb.remove(sitemap, function(err, response){ - // @TODO handle err - - // delete sitemap data db - var dbLocation = this.getSitemapDataDbLocation(sitemap._id); - PouchDB.destroy(dbLocation, function() { - callback(); - }.bind(this)); - }.bind(this)); - }, - getAllSitemaps: function (callback) { - - this.sitemapDb.allDocs({include_docs: true}, function(err, response) { - var sitemaps = []; - for (var i in response.rows) { - var sitemap = response.rows[i].doc; - if (!chrome.extension) { - sitemap = new Sitemap(sitemap); - } - - sitemaps.push(sitemap); - } - callback(sitemaps); - }); - }, - - getSitemapData: function (sitemap, callback) { - - var db = this.getSitemapDataDb(sitemap._id); - db.allDocs({include_docs: true}, function(err, response) { - var responseData = []; - for (var i in response.rows) { - var doc = response.rows[i].doc; - responseData.push(doc); - } - normalizeProperties(responseData); - callback(responseData); - }.bind(this)); - }, - // @TODO make this call lighter - sitemapExists: function (sitemapId, callback) { - this.getAllSitemaps(function (sitemaps) { - var sitemapFound = false; - for (var i in sitemaps) { - if (sitemaps[i]._id === sitemapId) { - sitemapFound = true; - } - } - callback(sitemapFound); - }); - } -}; \ No newline at end of file diff --git a/extension/scripts/StoreRestApi.js b/extension/scripts/StoreRestApi.js deleted file mode 100644 index bf1e3168..00000000 --- a/extension/scripts/StoreRestApi.js +++ /dev/null @@ -1,99 +0,0 @@ -var StoreRestApi = function (config) { - this.base_uri = config.restUrl; - this.localDataStore = new StorePouchDB(config); -}; - -StoreRestApi.prototype = { - - createSitemap: function (sitemap, callback) { - this.saveSitemap(sitemap, callback); - }, - saveSitemap: function (sitemap, callback) { - base_uri = this.base_uri; - this.sitemapExists(sitemap._id, function (exists) { - if (exists) { - //update sitemap - $.ajax({ - type : "PUT", - url: new URL('/sitemaps/' + sitemap._id, base_uri).href, - data: new Sitemap(sitemap).exportSitemap(), - success : function() { - callback(sitemap) - }, - error : function(jqXHR, textStatus, errorThrown) { - alert("StoreApi: Error updating sitemap.") - }, - contentType : "application/json" - }); - - } else { - //create new sitemap - $.ajax({ - type : "POST", - url: new URL('/sitemaps/', base_uri).href, - data: new Sitemap(sitemap).exportSitemap(), - success : function() { - callback(sitemap) - }, - error : function(jqXHR, textStatus, errorThrown) { - alert("StoreApi: Error creating sitemap.") - }, - contentType : "application/json" - }); - } - }); - }, - deleteSitemap: function (sitemap, callback) { - $.ajax({ - type : "DELETE", - url: new URL('/sitemaps/' + sitemap._id, this.base_uri).href, - success : callback, - error : function(jqXHR, textStatus, errorThrown) { - alert("StoreApi: Error deleting sitemap.") - }, - contentType : "application/json" - }); - }, - getAllSitemaps: function (callback) { - $.ajax({ - type : "GET", - url : new URL('/sitemaps/', this.base_uri).href, - success : function (data) { - let sitemaps = []; - for (let i in data) { - sitemaps.push(new Sitemap(data[i])); - } - callback(sitemaps); - }, - error : function(jqXHR, textStatus, errorThrown) { - alert("StoreApi: Could not get all sitemaps.") - }, - contentType : "application/json" - }); - }, - sitemapExists: function (sitemapId, callback) { - $.ajax({ - type : "GET", - url : new URL('/sitemaps/', this.base_uri).href, - success : function (data) { - let exists = false; - for (let i in data) { - if (data[i]._id === sitemapId){ - exists = true; - } - } - callback(exists); - }, - error : function(jqXHR, textStatus, errorThrown) { - alert("StoreApi: Could not get all sitemaps.") - }, - contentType : "application/json" - }); - }, - initSitemapDataDb: function(sitemapId, callback) { - this.localDataStore.initSitemapDataDb(sitemapId, callback); - }, - getSitemapData: function (sitemap, callback) { - this.localDataStore.getSitemapData(sitemap, callback); - } -}; diff --git a/extension/scripts/UniqueElementList.js b/extension/scripts/UniqueElementList.js deleted file mode 100644 index 67c3ec2a..00000000 --- a/extension/scripts/UniqueElementList.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Only Elements unique will be added to this array - * @constructor - */ -UniqueElementList = function(clickElementUniquenessType) { - this.clickElementUniquenessType = clickElementUniquenessType; - this.addedElements = {}; -}; - -UniqueElementList.prototype = new Array; - -UniqueElementList.prototype.push = function(element) { - - var getStyles = function(_elem, _style) { - var computedStyle; - if ( typeof _elem.currentStyle != 'undefined' ) { - computedStyle = _elem.currentStyle; - } else { - computedStyle = document.defaultView.getComputedStyle(_elem, null); - } - return _style ? computedStyle[_style] : computedStyle; - }; - - var copyComputedStyle = function(src, dest) { - var styles = getStyles(src); - for ( var i in styles ) { - // Do not use `hasOwnProperty`, nothing will get copied - if ( typeof i == "string" && i != "cssText" && !/\d/.test(i) ) { - // The try is for setter only properties - try { - dest.style[i] = styles[i]; - // `fontSize` comes before `font` If `font` is empty, `fontSize` gets - // overwritten. So make sure to reset this property. (hackyhackhack) - // Other properties may need similar treatment - if ( i == "font" ) { - dest.style.fontSize = styles.fontSize; - } - } catch (e) {} - } - } - }; - - if(this.isAdded(element)) { - return false; - } - else { - var elementUniqueId = this.getElementUniqueId(element); - this.addedElements[elementUniqueId] = true; - var clone = $(element).clone(true)[0]; - - // clone computed styles (to extract images from background) - var items = element.getElementsByTagName("*"); - var itemsCloned = clone.getElementsByTagName("*"); - $(items).each(function(i, item) { - copyComputedStyle(item, itemsCloned[i]); - }); - - Array.prototype.push.call(this, clone); - return true; - } -}; - -UniqueElementList.prototype.getElementUniqueId = function(element) { - - if(this.clickElementUniquenessType === 'uniqueText') { - var elementText = $(element).text().trim(); - return elementText; - } - else if(this.clickElementUniquenessType === 'uniqueHTMLText') { - - var elementHTML = $("
").append($(element).eq(0).clone()).html(); - return elementHTML; - } - else if(this.clickElementUniquenessType === 'uniqueHTML') { - - // get element without text - var $element = $(element).eq(0).clone(); - - var removeText = function($element) { - $element.contents() - .filter(function() { - if(this.nodeType !== 3) { - removeText($(this)); - } - return this.nodeType == 3; //Node.TEXT_NODE - }).remove(); - }; - removeText($element); - - var elementHTML = $("
").append($element).html(); - return elementHTML; - } - else if(this.clickElementUniquenessType === 'uniqueCSSSelector') { - var cs = new CssSelector({ - enableSmartTableSelector: false, - parent: $("body")[0], - enableResultStripping:false - }); - var CSSSelector = cs.getCssSelector([element]); - return CSSSelector; - } - else { - throw "Invalid clickElementUniquenessType "+this.clickElementUniquenessType; - } -}; - -UniqueElementList.prototype.isAdded = function(element) { - - var elementUniqueId = this.getElementUniqueId(element); - var isAdded = elementUniqueId in this.addedElements; - return isAdded; -}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..93f9e332 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3447 @@ +{ + "name": "web-scraper-chrome-extension", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abstract-leveldown": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz", + "integrity": "sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q==", + "requires": { + "level-concat-iterator": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "argsarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz", + "integrity": "sha1-bnIHtOzbObCviDA/pa4ivajfYcs=" + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "optional": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "optional": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "optional": true + }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true, + "optional": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "optional": true + }, + "babel-cli": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", + "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", + "dev": true, + "requires": { + "babel-core": "^6.26.0", + "babel-polyfill": "^6.26.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "chokidar": "^1.6.1", + "commander": "^2.11.0", + "convert-source-map": "^1.5.0", + "fs-readdir-recursive": "^1.0.0", + "glob": "^7.1.2", + "lodash": "^4.17.4", + "output-file-sync": "^1.1.2", + "path-is-absolute": "^1.0.1", + "slash": "^1.0.0", + "source-map": "^0.5.6", + "v8flags": "^2.1.1" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true, + "optional": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "optional": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "optional": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true, + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "optional": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "optional": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "optional": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "optional": true + }, + "core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "optional": true + }, + "deferred-leveldown": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", + "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", + "requires": { + "abstract-leveldown": "~6.2.1", + "inherits": "^2.0.3" + }, + "dependencies": { + "abstract-leveldown": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.2.tgz", + "integrity": "sha512-/a+Iwj0rn//CX0EJOasNyZJd2o8xur8Ce9C57Sznti/Ilt/cb6Qd8/k98A4ZOklXgTG+iAYYUs1OTG0s1eH+zQ==", + "requires": { + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + } + } + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encoding-down": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", + "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", + "requires": { + "abstract-leveldown": "^6.2.1", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0" + }, + "dependencies": { + "abstract-leveldown": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.2.tgz", + "integrity": "sha512-/a+Iwj0rn//CX0EJOasNyZJd2o8xur8Ce9C57Sznti/Ilt/cb6Qd8/k98A4ZOklXgTG+iAYYUs1OTG0s1eH+zQ==", + "requires": { + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + } + } + } + }, + "end-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/end-stream/-/end-stream-0.1.0.tgz", + "integrity": "sha1-MgA/P0OKKwFDFoE3+PpumGbIHtU=", + "requires": { + "write-stream": "~0.4.3" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "requires": { + "prr": "~1.0.1" + } + }, + "es6-denodeify": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz", + "integrity": "sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8=" + }, + "es6-templates": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=", + "dev": true, + "requires": { + "recast": "~0.11.12", + "through": "~2.3.6" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "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 + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "optional": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "optional": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "optional": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "optional": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-future": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", + "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=" + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "fetch-cookie": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.0.tgz", + "integrity": "sha512-Mm5pGlT3agW6t71xVM7vMZPIvI7T4FaTuFW4jari6dVzYHFDb3WZZsGpN22r/o3XMdkM0E7sPd1EGeyVbH2Tgg==", + "requires": { + "es6-denodeify": "^0.1.1", + "tough-cookie": "^2.3.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "optional": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "optional": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "optional": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": 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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "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" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "optional": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true, + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "optional": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "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 + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "html-loader": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.5.5.tgz", + "integrity": "sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog==", + "dev": true, + "requires": { + "es6-templates": "^0.2.3", + "fastparse": "^1.1.1", + "html-minifier": "^3.5.8", + "loader-utils": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + } + }, + "icanhaz": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/icanhaz/-/icanhaz-0.10.3.tgz", + "integrity": "sha1-sIDiz7MDX34okiC6BSRfKIPk9Lo=" + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.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==", + "dev": true, + "optional": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "optional": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true, + "optional": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "optional": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "optional": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true, + "optional": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "optional": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true, + "optional": true + }, + "level": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-5.0.1.tgz", + "integrity": "sha512-wcak5OQeA4rURGacqS62R/xNHjCYnJSQDBOlm4KNUGJVE9bWv2B04TclqReYejN+oD65PzD4FsqeWoI5wNC5Lg==", + "requires": { + "level-js": "^4.0.0", + "level-packager": "^5.0.0", + "leveldown": "^5.0.0", + "opencollective-postinstall": "^2.0.0" + } + }, + "level-codec": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.1.tgz", + "integrity": "sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q==" + }, + "level-concat-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", + "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==" + }, + "level-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", + "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", + "requires": { + "errno": "~0.1.1" + } + }, + "level-iterator-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", + "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.4.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } + }, + "level-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-4.0.1.tgz", + "integrity": "sha512-m5JRIyHZn5VnCCFeRegJkn5bQd3MJK5qZX12zg3Oivc8+BUIS2yFS6ANMMeHX2ieGxucNvEn6/ZnyjmZQLLUWw==", + "requires": { + "abstract-leveldown": "~6.0.1", + "immediate": "~3.2.3", + "inherits": "^2.0.3", + "ltgt": "^2.1.2", + "typedarray-to-buffer": "~3.1.5" + }, + "dependencies": { + "immediate": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", + "integrity": "sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=" + } + } + }, + "level-packager": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.0.tgz", + "integrity": "sha512-3pbJmDgGvp/lUQNULPoYQZtUbhMI8KoViYDw7Sa0kWl1mPeHWWJF7T/9upWI/NTMuEikkEE/cd6wBvmrW1+ZnQ==", + "requires": { + "encoding-down": "^6.3.0", + "levelup": "^4.3.2" + }, + "dependencies": { + "levelup": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.3.2.tgz", + "integrity": "sha512-cRTjU4ktWo59wf13PHEiOayHC3n0dOh4i5+FHr4tv4MX9+l7mqETicNq3Aj07HKlLdk0z5muVoDL2RD+ovgiyA==", + "requires": { + "deferred-leveldown": "~5.3.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + } + } + } + }, + "level-supports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", + "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "requires": { + "xtend": "^4.0.2" + }, + "dependencies": { + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } + }, + "level-write-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/level-write-stream/-/level-write-stream-1.0.0.tgz", + "integrity": "sha1-P3+7Z5pVE3wP6zA97nZuEu4Twdw=", + "requires": { + "end-stream": "~0.1.0" + } + }, + "leveldown": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.0.2.tgz", + "integrity": "sha512-Ib6ygFYBleS8x2gh3C1AkVsdrUShqXpe6jSTnZ6sRycEXKhqVf+xOSkhgSnjidpPzyv0d95LJVFrYQ4NuXAqHA==", + "requires": { + "abstract-leveldown": "~6.0.0", + "fast-future": "~1.0.2", + "napi-macros": "~1.8.1", + "node-gyp-build": "~3.8.0" + } + }, + "levelup": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.0.2.tgz", + "integrity": "sha512-cx9PmLENwbGA3svWBEbeO2HazpOSOYSXH4VA+ahVpYyurvD+SDSfURl29VBY2qgyk+Vfy2dJd71SBRckj/EZVA==", + "requires": { + "deferred-leveldown": "~5.0.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "xtend": "~4.0.0" + }, + "dependencies": { + "deferred-leveldown": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.0.1.tgz", + "integrity": "sha512-BXohsvTedWOLkj2n/TY+yqVlrCWa2Zs8LSxh3uCAgFOru7/pjxKyZAexGa1j83BaKloER4PqUyQ9rGPJLt9bqA==", + "requires": { + "abstract-leveldown": "~6.0.0", + "inherits": "^2.0.3" + } + } + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "optional": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "optional": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true, + "optional": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "optional": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "napi-macros": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-1.8.2.tgz", + "integrity": "sha512-Tr0DNY4RzTaBG2W2m3l7ZtFuJChTH6VZhXVhkGGjF/4cZTt+i8GcM9ozD+30Lmr4mDoZ5Xx34t2o4GJqYWDGcg==" + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.4.1.tgz", + "integrity": "sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw==" + }, + "node-gyp-build": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.8.0.tgz", + "integrity": "sha512-bYbpIHyRqZ7sVWXxGpz8QIRug5JZc/hzZH4GbdT9HTZi6WmKCZ8GLvP8OZ9TTiIBvwPFKgtGrlWQSXDAvYdsPw==" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "optional": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "optional": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "output-file-sync": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", + "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.4", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.0" + } + }, + "papaparse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-4.1.0.tgz", + "integrity": "sha1-csia+3gKFezGt2v+ryrqOFeCMDI=" + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "optional": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true, + "optional": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "optional": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "optional": true + }, + "pouchdb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/pouchdb/-/pouchdb-7.1.1.tgz", + "integrity": "sha512-8bXWclixNJZqokvxGHRsG19zehSJiaZaz4dVYlhXhhUctz7gMcNTElHjPBzBdZlKKvt9aFDndmXN1VVE53Co8g==", + "requires": { + "argsarray": "0.0.1", + "buffer-from": "1.1.0", + "clone-buffer": "1.0.0", + "double-ended-queue": "2.1.0-0", + "fetch-cookie": "0.7.0", + "immediate": "3.0.6", + "inherits": "2.0.3", + "level": "5.0.1", + "level-codec": "9.0.1", + "level-write-stream": "1.0.0", + "leveldown": "5.0.2", + "levelup": "4.0.2", + "ltgt": "2.2.1", + "node-fetch": "2.4.1", + "readable-stream": "1.0.33", + "spark-md5": "3.0.0", + "through2": "3.0.1", + "uuid": "3.2.1", + "vuvuzela": "1.0.3" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", + "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "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" + } + } + } + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + } + } + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true, + "optional": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "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==", + "dev": true, + "optional": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "optional": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "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==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "dev": true, + "requires": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "optional": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true, + "optional": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "optional": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "optional": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true, + "optional": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "optional": true + }, + "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==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "optional": true, + "requires": { + "ret": "~0.1.10" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "optional": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "optional": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "optional": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true, + "optional": true + }, + "spark-md5": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.0.tgz", + "integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8=" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "optional": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "optional": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "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==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "optional": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "optional": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "optional": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "optional": true + } + } + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true, + "optional": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "optional": true + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "^1.1.1" + } + }, + "vuvuzela": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz", + "integrity": "sha1-O+FF5YJxxzylUnndhR8SpoIRSws=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-stream": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz", + "integrity": "sha1-g8yMA0fQr2BXqThitOOuAd5cgcE=", + "requires": { + "readable-stream": "~0.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-0.0.4.tgz", + "integrity": "sha1-8y124/uGM0SlSNeZIwBxc2ZbO40=" + } + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..6d9e6be3 --- /dev/null +++ b/package.json @@ -0,0 +1,66 @@ +{ + "name": "web-scraper-chrome-extension", + "version": "0.3.5.00", + "description": "Web data extraction tool implemented as chrome extension", + "scripts": { + "lint": "eslint --ext .js,.vue src", + "prettier": "prettier \"src/**/*.{js,vue}\"", + "prettier:write": "npm run prettier -- --write", + "build": "cross-env NODE_ENV=production webpack --hide-modules", + "build:dev": "cross-env NODE_ENV=development webpack --hide-modules", + "build-zip": "node scripts/build-zip.js", + "watch": "npm run build -- --watch", + "watch:dev": "cross-env HMR=true npm run build:dev -- --watch" + }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "dependencies": { + "icanhaz": "0.10.3", + "papaparse": "^4.1.0", + "pouchdb": "^7.1.1", + "sugar": "^1.4.1", + "d3": "^3.3.8", + "bootstrap": "3.1.1", + "jquery": "^3.4.1", + "jquery-flexdatalist": "^2.2.4", + "webextension-polyfill": "^0.6.0" + }, + "devDependencies": { + "@babel/core": "^7.1.2", + "@babel/plugin-proposal-optional-chaining": "^7.0.0", + "@babel/preset-env": "^7.1.0", + "@babel/runtime-corejs3": "^7.4.0", + "archiver": "^3.0.0", + "babel-eslint": "^10.0.1", + "core-js": "^3.0.1", + "cross-env": "^5.2.0", + "css-loader": "^2.1.1", + "ejs": "^2.6.1", + "eslint": "^5.16.0", + "eslint-config-airbnb-base": "^13.0.0", + "eslint-config-prettier": "^4.3.0", + "eslint-friendly-formatter": "^4.0.1", + "eslint-import-resolver-webpack": "^0.10.1", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-prettier": "^3.1.0", + "husky": "^2.4.0", + "prettier": "^1.17.1", + "pretty-quick": "^1.8.0", + "web-ext-types": "^2.1.0", + "webpack": "^4.20.2", + "copy-webpack-plugin": "^4.5.3", + "webpack-cli": "^3.1.2", + "webpack-extension-reloader": "^1.1.0", + "imports-loader": "^0.8.0", + "file-loader": "^1.1.11", + "sass-loader": "^7.1.0", + "mini-css-extract-plugin": "^0.4.4", + "node-sass": "^4.9.3", + "eslint-loader": "^2.1.2", + "babel-loader": "^8.0.2", + "val-loader": "^2.1.0" + } +} diff --git a/playgrounds/extension/tables.html b/playgrounds/extension/tables.html index d80f074d..4cfb46a3 100644 --- a/playgrounds/extension/tables.html +++ b/playgrounds/extension/tables.html @@ -1,291 +1,288 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - + + - - - -
+ var config = new Config(); + config.loadConfiguration(function() { + var store = new StorePouchDB(config); + new SitemapController({ + store: store, + templateDir: '../../extension/devtools/views/', + }); + }); + }); + + + +
+

Table in table

+ + + + + + + + + + + + + + + + + + + + + + + + + +
#First NameLast NameUsername
1MarkOtto@mdo
2 + + + + + + + + + +
header 1header 2
data 1data 2
+
Thornton@fat
3Larrythe Bird@twitter
-

Table in table

- - - - - - - - - - - - - - - - - - - - - - - - - -
#First NameLast NameUsername
1MarkOtto@mdo
2 - - - - - - - - - -
header 1header 2
data 1data 2
-
Thornton@fat
3Larrythe Bird@twitter
+
+
+
-
-
-
+

Table with thead and tbody

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#First NameLast NameUsername
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
+
+
+
-

Table with thead and tbody

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#First NameLast NameUsername
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
+

Table with vertical headers

+ + + + + + + + + + + + + + + + +
NamesBenBruno
FruitsCherryClementine
AnimalsCatCatfish
-
-
-
+
+
+
-

Table with vertical headers

- - - - - - - - - - - - - - - - -
NamesBenBruno
FruitsCherryClementine
AnimalsCatCatfish
+

Table with vertical headers but without th

+ + + + + + + + + + + + + + + + +
NameBenGena
FruitCherryBanana
AnimalCatCheburashka
-
-
-
+
+
+
-

Table with vertical headers but without th

- - - - - - - - - - - - - - - - -
NameBenGena
FruitCherryBanana
AnimalCatCheburashka
+

Table with horizontal headers but without th

+ + + + + + + + + + + + + + + + +
NamesFruitsAnimals
BenCherryCat
BrunoClementineCatfish
-
-
-
+
+
+
-

Table with horizontal headers but without th

- - - - - - - - - - - - - - - - -
NamesFruitsAnimals
BenCherryCat
BrunoClementineCatfish
+

Table without headers

+ + + + + + + + + + + + + + + + +
A1A2A3
B1B2B3
C1C2C3
-
-
-
- - -

Table without headers

- - - - - - - - - - - - - - - - -
A1A2A3
B1B2B3
C1C2C3
-
-
-
- - - - - - - - - - - - - - - - - - - - -
flowers
colorsize
rosered20
vanilawhite30
- -
- +
+
+
+ + + + + + + + + + + + + + + + + + + + +
flowers
colorsize
rosered20
vanilawhite30
+
+ diff --git a/scripts/build-zip.js b/scripts/build-zip.js new file mode 100644 index 00000000..482ea96e --- /dev/null +++ b/scripts/build-zip.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const archiver = require('archiver'); + +const DEST_DIR = path.join(__dirname, '../dist'); +const DEST_ZIP_DIR = path.join(__dirname, '../dist-zip'); + +const extractExtensionData = () => { + const extPackageJson = require('../package.json'); + + return { + name: extPackageJson.name, + version: extPackageJson.version, + }; +}; + +const makeDestZipDirIfNotExists = () => { + if (!fs.existsSync(DEST_ZIP_DIR)) { + fs.mkdirSync(DEST_ZIP_DIR); + } +}; + +const buildZip = (src, dist, zipFilename) => { + console.info(`Building ${zipFilename}...`); + + const archive = archiver('zip', { zlib: { level: 9 } }); + const stream = fs.createWriteStream(path.join(dist, zipFilename)); + + return new Promise((resolve, reject) => { + archive + .directory(src, false) + .on('error', err => reject(err)) + .pipe(stream); + + stream.on('close', () => resolve()); + archive.finalize(); + }); +}; + +const main = () => { + const { name, version } = extractExtensionData(); + const zipFilename = `${name}-v${version}.zip`; + + makeDestZipDirIfNotExists(); + + buildZip(DEST_DIR, DEST_ZIP_DIR, zipFilename) + .then(() => console.info('OK')) + .catch(console.err); +}; + +main(); diff --git a/src/background/background.js b/src/background/background.js new file mode 100644 index 00000000..6e3c680b --- /dev/null +++ b/src/background/background.js @@ -0,0 +1,128 @@ +import Config from '../scripts/Config'; +import StorePouchDB from '../scripts/StorePouchDB'; +import StoreRestApi from '../scripts/StoreRestApi'; +import Sitemap from '../scripts/Sitemap'; +import Queue from '../scripts/Queue'; +import ChromePopupBrowser from '../scripts/ChromePopupBrowser'; +import Scraper from '../scripts/Scraper'; +import getBackgroundScript from '../scripts/BackgroundScript'; +import * as browser from 'webextension-polyfill'; + +const config = new Config(); +let store; + +config.loadConfiguration().then(() => { + console.log('initial configuration', config); + if (config.storageType === 'rest') { + store = new StoreRestApi(config); + } else { + store = new StorePouchDB(config); + } +}); + +browser.storage.onChanged.addListener(function() { + config.loadConfiguration().then(() => { + console.log('configuration changed', config); + if (config.storageType === 'rest') { + store = new StoreRestApi(config); + } else { + store = new StorePouchDB(config); + } + }); +}); + +let sendToActiveTab = function(request, callback) { + browser.tabs + .query({ + active: true, + currentWindow: true, + }) + .then(function(tabs) { + if (tabs.length < 1) { + this.console.log("couldn't find active tab"); + } else { + let tab = tabs[0]; + browser.tabs.sendMessage(tab.id, request).then(callback); + } + }); +}; + +browser.runtime.onMessage.addListener((request, sender) => { + console.log('browser.runtime.onMessage', request); + + if (request.createSitemap) { + return store.createSitemap(request.sitemap); + } else if (request.saveSitemap) { + return store.saveSitemap(request.sitemap); + } else if (request.deleteSitemap) { + return store.deleteSitemap(request.sitemap); + } else if (request.getAllSitemaps) { + return store.getAllSitemaps(); + } else if (request.sitemapExists) { + return store.sitemapExists(request.sitemapId); + } else if (request.getSitemapData) { + return store.getSitemapData(new Sitemap(request.sitemap)); + } else if (request.scrapeSitemap) { + let sitemap = new Sitemap(request.sitemap); + let queue = new Queue(); + let browser_tab = new ChromePopupBrowser({ + pageLoadDelay: request.pageLoadDelay, + }); + + let scraper = new Scraper({ + queue: queue, + sitemap: sitemap, + browser: browser_tab, + store: store, + requestInterval: request.requestInterval, + requestIntervalRandomness: request.requestIntervalRandomness, + pageLoadDelay: request.pageLoadDelay, + }); + + return new Promise(resolve => { + try { + scraper.run(function() { + browser_tab.close(); + browser.notifications.create('scraping-finished', { + type: 'basic', + iconUrl: 'assets/images/icon128.png', + title: 'Scraping finished!', + message: 'Finished scraping ' + sitemap._id, + }); + // table selector can dynamically add columns (addMissingColumns Feature) + resolve(sitemap.selectors); + }); + } catch (e) { + console.log('Scraper execution cancelled', e); + } + }); + } else if (request.previewSelectorData) { + return new Promise(resolve => { + browser.tabs + .query({ + active: true, + currentWindow: true, + }) + .then(function(tabs) { + if (tabs.length < 1) { + this.console.log("couldn't find active tab"); + return resolve(); + } else { + let tab = tabs[0]; + browser.tabs.sendMessage(tab.id, request).then(extractedData => { + resolve(extractedData); + }); + } + }); + }); + } else if (request.backgroundScriptCall) { + return new Promise(resolve => { + let backgroundScript = getBackgroundScript('BackgroundScript'); + //TODO change to promises + let deferredResponse = backgroundScript[request.fn](request.request); + deferredResponse.done(function(resp) { + resolve(resp); + }); + }); + } +}); diff --git a/extension/content_script/content_script.css b/src/content_script/content_script.css similarity index 94% rename from extension/content_script/content_script.css rename to src/content_script/content_script.css index f7e0c22f..e809b96a 100644 --- a/extension/content_script/content_script.css +++ b/src/content_script/content_script.css @@ -1,38 +1,38 @@ .-sitemap-parent { - outline: 2px #FFCC33 solid !important; - background-color: rgba(255, 204, 51, 0.20) !important; - background: rgba(255, 204, 51, 0.20) !important; + outline: 2px #ffcc33 solid !important; + background-color: rgba(255, 204, 51, 0.2) !important; + background: rgba(255, 204, 51, 0.2) !important; } .-sitemap-parent * { - background-color: rgba(255, 204, 51, 0.20) !important; - background: rgba(255, 204, 51, 0.20) !important; + background-color: rgba(255, 204, 51, 0.2) !important; + background: rgba(255, 204, 51, 0.2) !important; } .-sitemap-select-item-hover { outline: 2px solid green !important; - background-color: rgba(0, 213, 0, 0.20) !important; - background: rgba(0, 213, 0, 0.20) !important; + background-color: rgba(0, 213, 0, 0.2) !important; + background: rgba(0, 213, 0, 0.2) !important; } .-sitemap-select-item-hover * { - background-color: rgba(0, 213, 0, 0.20) !important; - background: rgba(0, 213, 0, 0.20) !important; + background-color: rgba(0, 213, 0, 0.2) !important; + background: rgba(0, 213, 0, 0.2) !important; } .-sitemap-select-item-selected { - outline: 2px solid #C70000 !important; - background-color: rgba(213, 0, 0, 0.2) !important; + outline: 2px solid #c70000 !important; + background-color: rgba(213, 0, 0, 0.2) !important; background: rgba(213, 0, 0, 0.2) !important; } .-sitemap-select-item-selected * { - background-color: rgba(213, 0, 0, 0.2) !important; + background-color: rgba(213, 0, 0, 0.2) !important; background: rgba(213, 0, 0, 0.2) !important; } #-selector-toolbar { - outline:1px red solid; + outline: 1px red solid; } /** @@ -40,7 +40,8 @@ * http://jsfiddle.net/Gb89Y/2/ * after loading css with this script you need to fix width, height */ -#-selector-toolbar, #-selector-toolbar div { +#-selector-toolbar, +#-selector-toolbar div { align-content: stretch !important; align-items: stretch !important; align-self: stretch !important; @@ -122,7 +123,7 @@ float: none !important; flood-color: rgb(0, 0, 0) !important; flood-opacity: 1 !important; - font: normal normal normal 16px/normal 'Times New Roman' !important; + font: normal normal normal 16px / normal 'Times New Roman' !important; font-family: 'Times New Roman' !important; font-kerning: auto !important; font-size: 16px !important; @@ -360,8 +361,11 @@ zoom: 1 !important; } -#-selector-toolbar:after, #-selector-toolbar:before, #-selector-toolbar *:after, #-selector-toolbar *:before { - content: ""; +#-selector-toolbar:after, +#-selector-toolbar:before, +#-selector-toolbar *:after, +#-selector-toolbar *:before { + content: ''; display: none; box-sizing: border-box; } @@ -448,7 +452,7 @@ float: none !important; flood-color: rgb(0, 0, 0) !important; flood-opacity: 1 !important; - font: normal normal normal 13px/normal Arial !important; + font: normal normal normal 13px / normal Arial !important; font-family: Arial !important; font-kerning: auto !important; font-size: 13px !important; @@ -691,7 +695,7 @@ bottom: 20px !important; left: 10px !important; z-index: 99999 !important; - background-color: #FFF !important; + background-color: #fff !important; } #-selector-toolbar div.list-item { @@ -700,12 +704,12 @@ color: #333333 !important; font-size: 14px !important; border: 1px solid #285e8e !important; - border-right:none !important; + border-right: none !important; display: table-cell !important; text-align: right !important; height: 26px !important; - width:20px !important; - line-height:26px !important; + width: 20px !important; + line-height: 26px !important; text-align: center !important; } @@ -719,31 +723,31 @@ #-selector-toolbar div.done-selecting-button { color: #ffffff !important; - -webkit-text-fill-color: #FFF !important; + -webkit-text-fill-color: #fff !important; background-color: #3276b1 !important; cursor: pointer !important; - width:130px !important; + width: 130px !important; } #-selector-toolbar div.selector-container { width: 350px !important; overflow: hidden !important; - margin-bottom:-100px !important; + margin-bottom: -100px !important; } #-selector-toolbar div.selector { width: 10000px !important; - float:right !important; + float: right !important; color: #333333 !important; text-align: right !important; font: 100%/1em Verdana, Helvetica, sans-serif !important; - line-height:26px !important; + line-height: 26px !important; font-size: 14px !important; } #-selector-toolbar div.key-button { cursor: help !important; - background: #FFF !important; + background: #fff !important; } #-selector-toolbar div.key-button.clicked { @@ -752,7 +756,7 @@ #-selector-toolbar div.key-button.clicked-animation { transition: background 0.5s ease-in !important; - background: #FFF !important; + background: #fff !important; } #-selector-toolbar div.key-events { @@ -762,20 +766,20 @@ #-selector-toolbar div.key-events div { cursor: pointer !important; width: 83px !important; - float:right !important; + float: right !important; font: 100%/1em Verdana, Helvetica, sans-serif !important; - line-height:26px !important; + line-height: 26px !important; font-size: 9px !important; - margin-bottom:-100px !important; + margin-bottom: -100px !important; } #-selector-toolbar div.hide { - display:none !important; + display: none !important; } #-selector-toolbar div.input-group-addon { - background-color:#eeeeee !important; - position:relative !important; + background-color: #eeeeee !important; + position: relative !important; } #-selector-toolbar div.popover { @@ -793,9 +797,9 @@ white-space: normal !important; background-color: #fff !important; background-clip: padding-box !important; - border: 1px solid rgba(0,0,0,.2) !important; + border: 1px solid rgba(0, 0, 0, 0.2) !important; border-radius: 6px !important; - box-shadow: 0 5px 10px rgba(0,0,0,.2) !important; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2) !important; } #-selector-toolbar div.popover div.arrow { @@ -810,7 +814,7 @@ left: 50% !important; margin-left: -11px !important; border-top-color: #999 !important; - border-top-color: rgba(0,0,0,.25) !important; + border-top-color: rgba(0, 0, 0, 0.25) !important; border-bottom-width: 0 !important; } @@ -825,7 +829,7 @@ border-width: 10px !important; bottom: 1px !important; margin-left: -10px !important; - content: " " !important; + content: ' ' !important; border-top-color: #fff !important; border-bottom-width: 0 !important; visibility: visible !important; @@ -858,6 +862,6 @@ * Move images to top while selecting */ body.-web-scraper-selection-active img.-web-scraper-img-on-top { - z-index:2147483647 !important; /* max z-index */ - position:relative !important; /* will break images with position:absolute */ + z-index: 2147483647 !important; /* max z-index */ + position: relative !important; /* will break images with position:absolute */ } diff --git a/src/content_script/content_script.js b/src/content_script/content_script.js new file mode 100644 index 00000000..7778c25d --- /dev/null +++ b/src/content_script/content_script.js @@ -0,0 +1,44 @@ +import getContentScript from '../scripts/ContentScript'; +import DataExtractor from '../scripts/DataExtractor'; +import * as browser from 'webextension-polyfill'; +import './content_script.css'; + +browser.runtime.onMessage.addListener(request => { + console.log('browser.runtime.onMessage', request); + return new Promise(resolve => { + if (request.extractData) { + console.log('received data extraction request', request); + let extractor = new DataExtractor(request); + let deferredData = extractor.getData(); + deferredData.done(function(data) { + console.log('dataextractor data', data); + let selectors = extractor.sitemap.selectors; + resolve(data, selectors); + }); + return true; + } else if (request.previewSelectorData) { + console.log('received data-preview extraction request', request); + let extractor = new DataExtractor(request); + let deferredData = extractor.getSingleSelectorData(request.parentSelectorIds, request.selectorId); + deferredData.done(function(data) { + console.log('dataextractor data', data); + let selectors = extractor.sitemap.selectors; + resolve(data, selectors); + }); + return true; + } + // Universal ContentScript communication handler + else if (request.contentScriptCall) { + let contentScript = getContentScript('ContentScript'); + + console.log('received ContentScript request', request); + + let deferredResponse = contentScript[request.fn](request.request); + deferredResponse.done(function(response) { + resolve(response, null); + }); + + return true; + } + }); +}); diff --git a/src/devtools/devtools.html b/src/devtools/devtools.html new file mode 100644 index 00000000..378e9f7c --- /dev/null +++ b/src/devtools/devtools.html @@ -0,0 +1,9 @@ + + + + + Title + + + + diff --git a/src/devtools/devtools.js b/src/devtools/devtools.js new file mode 100644 index 00000000..a1f6dcb8 --- /dev/null +++ b/src/devtools/devtools.js @@ -0,0 +1,10 @@ +import * as browser from 'webextension-polyfill'; + +//Tip from https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser +let isFirefox = typeof InstallTrigger !== 'undefined'; + +if (isFirefox) { + browser.devtools.panels.create('Web Scraper', '../icons/icon48.png', './panel.html'); +} else { + browser.devtools.panels.create('Web Scraper', 'icons/icon48.png', 'devtools/panel.html'); +} diff --git a/src/devtools/panel.css b/src/devtools/panel.css new file mode 100644 index 00000000..0087c9e8 --- /dev/null +++ b/src/devtools/panel.css @@ -0,0 +1,102 @@ +/*body > form, body > div {*/ +/*display:none;*/ +/*}*/ + +a, +tbody tr { + cursor: pointer; +} + +.selector-list-tpl, +.sitemap-list-tpl { + display: none; +} + +/** + * Compact elements + */ +.navbar-nav > li > a { + padding-top: 3px; + padding-bottom: 3px; +} + +.navbar-text { + margin-top: 4px; + margin-bottom: 4px; + padding-right: 3px; +} + +.navbar { + min-height: 26px; + margin-bottom: 6px; +} + +.table-condensed tbody > tr > td { + padding: 1px 5px; +} + +body { + font-size: 12px; +} + +form .form-control { + font-size: 12px; + padding: 3px 12px; + height: 25px; +} + +textarea.form-control { + height: auto; +} + +form .btn { + font-size: 12px; + padding: 3px 12px; +} + +form .form-group { + margin-bottom: 5px; +} + +form select[multiple], +select[size] { + height: auto; +} + +#selector-graph .node circle { + cursor: pointer; + fill: #fff; + stroke: steelblue; + stroke-width: 1px; +} + +#selector-graph .node text { + font-size: 11px; +} + +#selector-graph path.link { + fill: none; + stroke: #ccc; + stroke-width: 1px; +} + +.data-preview-modal .modal-dialog { + width: auto; +} + +.data-preview-modal .modal-body { + overflow-y: scroll; +} + +.data-preview-modal tbody tr { + cursor: initial; +} + +.input-group[class*='col-'] { + padding-right: 15px; + padding-left: 15px; +} + +.form-inline .form-control { + width: 100%; +} diff --git a/src/devtools/panel.html b/src/devtools/panel.html new file mode 100644 index 00000000..f7d976e8 --- /dev/null +++ b/src/devtools/panel.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/extension/devtools/views/DataPreview.html b/src/devtools/views/DataPreview.html similarity index 73% rename from extension/devtools/views/DataPreview.html rename to src/devtools/views/DataPreview.html index 74c22f22..cabf85aa 100644 --- a/extension/devtools/views/DataPreview.html +++ b/src/devtools/views/DataPreview.html @@ -7,17 +7,16 @@
- \ No newline at end of file + diff --git a/src/devtools/views/SelectorEdit.html b/src/devtools/views/SelectorEdit.html new file mode 100644 index 00000000..a1f7a925 --- /dev/null +++ b/src/devtools/views/SelectorEdit.html @@ -0,0 +1,350 @@ +
+
+ +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+
+ + + + + + +
+
+
+ +
+ + +
+
+ + + + + +
+
+
+ + +
+ +
+
+ + + + + + +
+
+
+ + +
+ +
+
+ + + + + +
+
+
+ + +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ + +
+ + +
+ +
+
+ + +
+ + +
+ +
+
+ + +
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + +
+ +
+
+ +
+
+
+ + +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ + +
+ + +
+ +
+
+ + +
+ + +
+ +
+
+ + +
+ + +
+ +
+
+ +
+ +
+
+ + + Trim will be applied before regex. +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+
+ +
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+
+ +
+ + +
+ + + + + + + + + + {{#selector.columns}} + + + + + + {{/selector.columns}} + +
ColumnResult keyInclude into result
{{header}} + +
+
+
+ +
+
+ + +
+
+ +
+
+
+
diff --git a/extension/devtools/views/SelectorEditTableColumn.html b/src/devtools/views/SelectorEditTableColumn.html similarity index 73% rename from extension/devtools/views/SelectorEditTableColumn.html rename to src/devtools/views/SelectorEditTableColumn.html index 199359b3..72dab2a2 100644 --- a/extension/devtools/views/SelectorEditTableColumn.html +++ b/src/devtools/views/SelectorEditTableColumn.html @@ -1,5 +1,5 @@ - {{header}} - + {{header}} + - \ No newline at end of file + diff --git a/extension/devtools/views/SelectorList.html b/src/devtools/views/SelectorList.html similarity index 62% rename from extension/devtools/views/SelectorList.html rename to src/devtools/views/SelectorList.html index e1ad6a66..ec791365 100644 --- a/extension/devtools/views/SelectorList.html +++ b/src/devtools/views/SelectorList.html @@ -6,16 +6,16 @@ - - - - - - - - + + + + + + + +
IDSelectortypeMultipleParent selectorsActions
IDSelectortypeMultipleParent selectorsActions
- \ No newline at end of file + diff --git a/extension/devtools/views/SelectorListItem.html b/src/devtools/views/SelectorListItem.html similarity index 98% rename from extension/devtools/views/SelectorListItem.html rename to src/devtools/views/SelectorListItem.html index 349cecc5..1ec3632d 100644 --- a/extension/devtools/views/SelectorListItem.html +++ b/src/devtools/views/SelectorListItem.html @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/extension/devtools/views/SitemapBrowseData.html b/src/devtools/views/SitemapBrowseData.html similarity index 56% rename from extension/devtools/views/SitemapBrowseData.html rename to src/devtools/views/SitemapBrowseData.html index aec6a2d0..f0242284 100644 --- a/extension/devtools/views/SitemapBrowseData.html +++ b/src/devtools/views/SitemapBrowseData.html @@ -1,13 +1,12 @@
- - {{#columns}} - - {{/columns}} - + + {{#columns}} + + {{/columns}} + - - +
{{.}}
{{.}}
-
\ No newline at end of file + diff --git a/src/devtools/views/SitemapCreate.html b/src/devtools/views/SitemapCreate.html new file mode 100644 index 00000000..bed11463 --- /dev/null +++ b/src/devtools/views/SitemapCreate.html @@ -0,0 +1,95 @@ +
+
+ + +
+ +
+
+
+ +
+
+ +
+
+
+ Supported URL patterns:
+ 1. Numeric with optional step and zero padding – [START-END:STEP] – [001-010:10]
+ 2. Date interval – [date<PATTERN><START><END>] – [date<dd.MM.yyyy><01.01.2017><now>]
+
    + date placeholder may be + yesterday + / + now + / + tomorrow
    + other template components (in Java style) +
      + + + + + + + + + + + + + + + + + + + + + + + + +
      yyyyfull year (4 digits)
      yylast 2 digits of year
      MMM  Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
      MMmonth number (01-12)
      ddday of month
      +
    +
+
+
+
+ +
+
+ +
+

+ You can specify sitemap model as a list of json objects.
+ Example: [ { "entity": "EntityName", "field": "FieldName", "field_name": "Expected Field Id" } ] +

+
+
+
+
+ +
+
+
diff --git a/src/devtools/views/SitemapEditMetadata.html b/src/devtools/views/SitemapEditMetadata.html new file mode 100644 index 00000000..55b056cf --- /dev/null +++ b/src/devtools/views/SitemapEditMetadata.html @@ -0,0 +1,97 @@ +
+
+
+ + +
+ +
+
+
+ +
+
+ +
+
+
+ Supported URL patterns:
+ 1. Numeric with optional step and zero padding – [START-END:STEP] – [001-010:10]
+ 2. Date interval – [date<PATTERN><START><END>] – [date<dd.MM.yyyy><01.01.2017><now>]
+
    + date placeholder may be + yesterday + / + now + / + tomorrow
    + other template components (in Java style) +
      + + + + + + + + + + + + + + + + + + + + + + + + +
      yyyyfull year (4 digits)
      yylast 2 digits of year
      MMM  Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
      MMmonth number (01-12)
      ddday of month
      +
    +
+
+
+
+ +
+
+ +
+

+ You can specify sitemap model as a list of json objects.
+ Example: [ { "entity": "EntityName", "field": "FieldName", "field_name": "Expected Field Id" } ] +

+
+
+
+
+ +
+
+
+
diff --git a/extension/devtools/views/SitemapExport.html b/src/devtools/views/SitemapExport.html similarity index 96% rename from extension/devtools/views/SitemapExport.html rename to src/devtools/views/SitemapExport.html index d4392323..e66e2de4 100644 --- a/extension/devtools/views/SitemapExport.html +++ b/src/devtools/views/SitemapExport.html @@ -4,4 +4,4 @@ - \ No newline at end of file + diff --git a/src/devtools/views/SitemapExportDataCSV.html b/src/devtools/views/SitemapExportDataCSV.html new file mode 100644 index 00000000..bd8491a7 --- /dev/null +++ b/src/devtools/views/SitemapExportDataCSV.html @@ -0,0 +1,24 @@ +
Console
+ +

Export {{_id}} data as CSV

+
+ + + +
+ + + +
+ + + +
+ + +
+
+ +

+ Waiting for process to finish. > Download now! +

diff --git a/extension/devtools/views/SitemapImport.html b/src/devtools/views/SitemapImport.html similarity index 91% rename from extension/devtools/views/SitemapImport.html rename to src/devtools/views/SitemapImport.html index e737acd1..446b792e 100644 --- a/extension/devtools/views/SitemapImport.html +++ b/src/devtools/views/SitemapImport.html @@ -10,7 +10,7 @@
- +
@@ -18,4 +18,4 @@
- \ No newline at end of file + diff --git a/src/devtools/views/SitemapList.html b/src/devtools/views/SitemapList.html new file mode 100644 index 00000000..c0dd7ff4 --- /dev/null +++ b/src/devtools/views/SitemapList.html @@ -0,0 +1,12 @@ +
+ + + + + + + + + +
IDStart URLactions
+
diff --git a/extension/devtools/views/SitemapListItem.html b/src/devtools/views/SitemapListItem.html similarity index 87% rename from extension/devtools/views/SitemapListItem.html rename to src/devtools/views/SitemapListItem.html index de564654..4f155a9e 100644 --- a/extension/devtools/views/SitemapListItem.html +++ b/src/devtools/views/SitemapListItem.html @@ -1,13 +1,11 @@ {{_id}} - {{#startUrls}} - {{.}}, - {{/startUrls}} + {{#startUrls}} {{.}}, {{/startUrls}} - \ No newline at end of file + diff --git a/extension/devtools/views/SitemapScrapeConfig.html b/src/devtools/views/SitemapScrapeConfig.html similarity index 88% rename from extension/devtools/views/SitemapScrapeConfig.html rename to src/devtools/views/SitemapScrapeConfig.html index f04bd4b0..256e5b79 100644 --- a/extension/devtools/views/SitemapScrapeConfig.html +++ b/src/devtools/views/SitemapScrapeConfig.html @@ -3,23 +3,23 @@
- +
- +
- +
diff --git a/src/devtools/views/SitemapSelectorGraph.html b/src/devtools/views/SitemapSelectorGraph.html new file mode 100644 index 00000000..e5bcf79c --- /dev/null +++ b/src/devtools/views/SitemapSelectorGraph.html @@ -0,0 +1 @@ +
diff --git a/src/devtools/views/Viewport.html b/src/devtools/views/Viewport.html new file mode 100644 index 00000000..504b3df9 --- /dev/null +++ b/src/devtools/views/Viewport.html @@ -0,0 +1,33 @@ + + + + +
+
diff --git a/extension/assets/images/LICENSE b/src/icons/LICENSE similarity index 100% rename from extension/assets/images/LICENSE rename to src/icons/LICENSE diff --git a/extension/assets/images/icon128.png b/src/icons/icon128.png similarity index 100% rename from extension/assets/images/icon128.png rename to src/icons/icon128.png diff --git a/extension/assets/images/icon16.png b/src/icons/icon16.png similarity index 100% rename from extension/assets/images/icon16.png rename to src/icons/icon16.png diff --git a/extension/assets/images/icon19.png b/src/icons/icon19.png similarity index 100% rename from extension/assets/images/icon19.png rename to src/icons/icon19.png diff --git a/extension/assets/images/icon38.png b/src/icons/icon38.png similarity index 100% rename from extension/assets/images/icon38.png rename to src/icons/icon38.png diff --git a/extension/assets/images/icon48.png b/src/icons/icon48.png similarity index 100% rename from extension/assets/images/icon48.png rename to src/icons/icon48.png diff --git a/src/libs/css-selector/lib/CssSelector.js b/src/libs/css-selector/lib/CssSelector.js new file mode 100644 index 00000000..616262b8 --- /dev/null +++ b/src/libs/css-selector/lib/CssSelector.js @@ -0,0 +1,306 @@ +import ElementSelector from './ElementSelector'; +import ElementSelectorList from './ElementSelectorList'; + +export default class CssSelector { + constructor(options) { + var me = this; + + // defaults + this.ignoredTags = ['font', 'b', 'i', 's']; + this.parent = document; + this.ignoredClassBase = false; + this.enableResultStripping = true; + this.enableSmartTableSelector = false; + this.ignoredClasses = []; + this.query = function(selector) { + return this.parent.querySelectorAll(selector); + }; + + // overrides defaults with options + for (let i in options) { + this[i] = options[i]; + } + + // jquery parent selector fix + if (this.query === window.jQuery) { + this.query = function(selector) { + return jQuery(me.parent).find(selector); + }; + } + } + + mergeElementSelectors(newSelectors) { + if (newSelectors.length < 1) { + throw 'No selectors specified'; + } else if (newSelectors.length === 1) { + return newSelectors[0]; + } + + // check selector total count + let elementCountInSelector = newSelectors[0].length; + for (let i = 0; i < newSelectors.length; i++) { + let selector = newSelectors[i]; + if (selector.length !== elementCountInSelector) { + throw 'Invalid element count in selector'; + } + } + + // merge selectors + const resultingElements = newSelectors[0]; + for (let i = 1; i < newSelectors.length; i++) { + let mergeElements = newSelectors[i]; + + for (let j = 0; j < elementCountInSelector; j++) { + resultingElements[j].merge(mergeElements[j]); + } + } + return resultingElements; + } + + stripSelector(selectors) { + let cssSelector = selectors.getCssSelector(); + let baseSelectedElements = this.query(cssSelector); + + let compareElements = function(elements) { + if (baseSelectedElements.length !== elements.length) { + return false; + } + + for (let j = 0; j < baseSelectedElements.length; j++) { + if ([].indexOf.call(elements, baseSelectedElements[j]) === -1) { + return false; + } + } + return true; + }; + // strip indexes + for (let i = 0; i < selectors.length; i++) { + let selector = selectors[i]; + if (selector.index !== null) { + let index = selector.index; + selector.index = null; + let cssSelector1 = selectors.getCssSelector(); + let newSelectedElements = this.query(cssSelector1); + // if results doesn't match then undo changes + if (!compareElements(newSelectedElements)) { + selector.index = index; + } + } + } + + // strip isDirectChild + for (let i = 0; i < selectors.length; i++) { + let selector = selectors[i]; + if (selector.isDirectChild === true) { + selector.isDirectChild = false; + let cssSeletor2 = selectors.getCssSelector(); + let newSelectedElements = this.query(cssSeletor2); + // if results doesn't match then undo changes + if (!compareElements(newSelectedElements)) { + selector.isDirectChild = true; + } + } + } + + // strip ids + for (let i = 0; i < selectors.length; i++) { + let selector = selectors[i]; + if (selector.id !== null) { + let id = selector.id; + selector.id = null; + let cssSeletor3 = selectors.getCssSelector(); + let newSelectedElements = this.query(cssSeletor3); + // if results doesn't match then undo changes + if (!compareElements(newSelectedElements)) { + selector.id = id; + } + } + } + + // strip classes + for (let i = 0; i < selectors.length; i++) { + let selector = selectors[i]; + if (selector.classes.length !== 0) { + for (let j = selector.classes.length - 1; j > 0; j--) { + let cclass = selector.classes[j]; + selector.classes.splice(j, 1); + let cssSeletor4 = selectors.getCssSelector(); + let newSelectedElements = this.query(cssSeletor4); + // if results doesn't match then undo changes + if (!compareElements(newSelectedElements)) { + selector.classes.splice(j, 0, cclass); + } + } + } + } + + // strip tags + for (let i = selectors.length - 1; i > 0; i--) { + let selector = selectors[i]; + selectors.splice(i, 1); + let cssSeletor5 = selectors.getCssSelector(); + let newSelectedElements = this.query(cssSeletor5); + // if results doesn't match then undo changes + if (!compareElements(newSelectedElements)) { + selectors.splice(i, 0, selector); + } + } + + return selectors; + } + + getElementSelectors(elements, top) { + let elementSelectors = []; + + for (let i = 0; i < elements.length; i++) { + let element = elements[i]; + let elementSelector = this.getElementSelector(element, top); + elementSelectors.push(elementSelector); + } + + return elementSelectors; + } + + getElementSelector(element, top) { + let elementSelectorList = new ElementSelectorList(this); + while (true) { + if (element === this.parent) { + break; + } else if (element === undefined || element === this.parent) { + throw 'element is not a child of the given parent'; + } + if (this.isIgnoredTag(element.tagName)) { + element = element.parentNode; + continue; + } + if (top > 0) { + top--; + element = element.parentNode; + continue; + } + + let selector = new ElementSelector(element, this.ignoredClasses); + // document does not have a tagName + if (element.parentNode === this.parent || this.isIgnoredTag(element.parentNode.tagName)) { + selector.isDirectChild = false; + } + + elementSelectorList.push(selector); + element = element.parentNode; + } + + return elementSelectorList; + } + + /** + * Compares whether two elements are similar. Similar elements should + * have a common parrent and all parent elements should be the same type. + * @param element1 + * @param element2 + */ + checkSimilarElements(element1, element2) { + while (true) { + if (element1.tagName !== element2.tagName) { + return false; + } + if (element1 === element2) { + return true; + } + + // stop at body tag + if (element1 === undefined || element1.tagName === 'body' || element1.tagName === 'BODY') { + return false; + } + if (element2 === undefined || element2.tagName === 'body' || element2.tagName === 'BODY') { + return false; + } + + element1 = element1.parentNode; + element2 = element2.parentNode; + } + } + + /** + * Groups elements into groups if the emelents are not similar + * @param elements + */ + getElementGroups(elements) { + // first elment is in the first group + // @TODO maybe i dont need this? + let groups = [[elements[0]]]; + + for (let i = 1; i < elements.length; i++) { + let elementNew = elements[i]; + let addedToGroup = false; + for (let j = 0; j < groups.length; j++) { + let group = groups[j]; + let elementGroup = group[0]; + if (this.checkSimilarElements(elementNew, elementGroup)) { + group.push(elementNew); + addedToGroup = true; + break; + } + } + + // add new group + if (!addedToGroup) { + groups.push([elementNew]); + } + } + + return groups; + } + + getCssSelector(elements, top) { + top = top || 0; + + let enableSmartTableSelector = this.enableSmartTableSelector; + if (elements.length > 1) { + this.enableSmartTableSelector = false; + } + + // group elements into similarity groups + let elementGroups = this.getElementGroups(elements); + + let resultCSSSelector; + + if (this.allowMultipleSelectors) { + let groupSelectors = []; + + for (let i = 0; i < elementGroups.length; i++) { + let groupElements = elementGroups[i]; + + let elementSelectors = this.getElementSelectors(groupElements, top); + let resultSelector = this.mergeElementSelectors(elementSelectors); + if (this.enableResultStripping) { + resultSelector = this.stripSelector(resultSelector); + } + + groupSelectors.push(resultSelector.getCssSelector()); + } + + resultCSSSelector = groupSelectors.join(', '); + } else { + if (elementGroups.length !== 1) { + throw 'found multiple element groups, but allowMultipleSelectors disabled'; + } + + let elementSelectors = this.getElementSelectors(elements, top); + let resultSelector = this.mergeElementSelectors(elementSelectors); + if (this.enableResultStripping) { + resultSelector = this.stripSelector(resultSelector); + } + + resultCSSSelector = resultSelector.getCssSelector(); + } + + this.enableSmartTableSelector = enableSmartTableSelector; + + // strip down selector + return resultCSSSelector; + } + + isIgnoredTag(tag) { + return this.ignoredTags.indexOf(tag.toLowerCase()) !== -1; + } +} diff --git a/src/libs/css-selector/lib/ElementSelector.js b/src/libs/css-selector/lib/ElementSelector.js new file mode 100644 index 00000000..80dfc1ed --- /dev/null +++ b/src/libs/css-selector/lib/ElementSelector.js @@ -0,0 +1,126 @@ +export default class ElementSelector { + // TODO refactor element selector list into a ~ class + constructor(element, ignoredClasses) { + this.element = element; + this.isDirectChild = true; + this.tag = element.localName; + this.tag = this.tag.replace(/:/g, '\\:'); + + // nth-of-child(n+1) + this.indexn = null; + this.index = 1; + this.id = null; + this.classes = []; + + // do not add additinal info to html, body tags. + // html:nth-of-type(1) cannot be selected + if (this.tag === 'html' || this.tag === 'HTML' || this.tag === 'body' || this.tag === 'BODY') { + this.index = null; + return; + } + + if (element.parentNode !== undefined) { + // nth-child + //this.index = [].indexOf.call(element.parentNode.children, element)+1; + + // nth-of-type + for (let i = 0; i < element.parentNode.children.length; i++) { + let child = element.parentNode.children[i]; + if (child === element) { + break; + } + if (child.tagName === element.tagName) { + this.index++; + } + } + } + + if (element.id !== '') { + if (typeof element.id === 'string') { + this.id = element.id; + this.id = this.id.replace(/:/g, '\\:'); + } + } + + for (let i = 0; i < element.classList.length; i++) { + let cclass = element.classList[i]; + if (ignoredClasses.indexOf(cclass) === -1) { + cclass = cclass.replace(/:/g, '\\:'); + this.classes.push(cclass); + } + } + } + + getCssSelector(isFirstSelector) { + if (isFirstSelector === undefined) { + isFirstSelector = false; + } + + let selector = this.tag; + if (this.id !== null) { + selector += '#' + this.id; + } + if (this.classes.length) { + for (let i = 0; i < this.classes.length; i++) { + selector += '.' + this.classes[i]; + } + } + if (this.index !== null) { + selector += ':nth-of-type(' + this.index + ')'; + } + if (this.indexn !== null && this.indexn !== -1) { + selector += ':nth-of-type(n+' + this.indexn + ')'; + } + if (this.isDirectChild && isFirstSelector === false) { + selector = '> ' + selector; + } + + return selector; + } + + // merges this selector with another one. + merge(mergeSelector) { + if (this.tag !== mergeSelector.tag) { + throw 'different element selected (tag)'; + } + + if (this.index !== null) { + if (this.index !== mergeSelector.index) { + // use indexn only for two elements + if (this.indexn === null) { + let indexn = Math.min(mergeSelector.index, this.index); + if (indexn > 1) { + this.indexn = Math.min(mergeSelector.index, this.index); + } + } else { + this.indexn = -1; + } + + this.index = null; + } + } + + if (this.isDirectChild === true) { + this.isDirectChild = mergeSelector.isDirectChild; + } + + if (this.id !== null) { + if (this.id !== mergeSelector.id) { + this.id = null; + } + } + + if (this.classes.length !== 0) { + let classes = []; + + for (let i in this.classes) { + let cclass = this.classes[i]; + if (mergeSelector.classes.indexOf(cclass) !== -1) { + classes.push(cclass); + } + } + + this.classes = classes; + } + } +} diff --git a/src/libs/css-selector/lib/ElementSelectorList.js b/src/libs/css-selector/lib/ElementSelectorList.js new file mode 100644 index 00000000..85d97e6f --- /dev/null +++ b/src/libs/css-selector/lib/ElementSelectorList.js @@ -0,0 +1,40 @@ +export default class ElementSelectorList extends Array { + constructor(CssSelector) { + super(); + this.CssSelector = CssSelector; + } + + getCssSelector() { + let resultSelectors = []; + + // TDD + for (let i = 0; i < this.length; i++) { + let selector = this[i]; + + let isFirstSelector = i === this.length - 1; + let resultSelector = selector.getCssSelector(isFirstSelector); + + if (this.CssSelector.enableSmartTableSelector) { + if (selector.tag === 'tr') { + if (selector.element.children.length === 2) { + if (selector.element.children[0].tagName === 'TD' || selector.element.children[0].tagName === 'TH' || selector.element.children[0].tagName === 'TR') { + let text = selector.element.children[0].textContent; + text = text.trim(); + + // escape quotes + text.replace(/(\\*)(')/g, function(x) { + let l = x.length; + return l % 2 ? x : x.substring(0, l - 1) + "\\'"; + }); + resultSelector += ":contains('" + text + "')"; + } + } + } + } + + resultSelectors.push(resultSelector); + } + + return resultSelectors.reverse().join(' '); + } +} diff --git a/extension/assets/jquery.bootstrapvalidator/bootstrapValidator.css b/src/libs/jquery.bootstrapvalidator/bootstrapValidator.css similarity index 82% rename from extension/assets/jquery.bootstrapvalidator/bootstrapValidator.css rename to src/libs/jquery.bootstrapvalidator/bootstrapValidator.css index ebe9522f..57d1576a 100644 --- a/extension/assets/jquery.bootstrapvalidator/bootstrapValidator.css +++ b/src/libs/jquery.bootstrapvalidator/bootstrapValidator.css @@ -8,14 +8,14 @@ */ .bv-form .help-block { - margin-bottom: 0; + margin-bottom: 0; } .bv-form .tooltip-inner { - text-align: left; + text-align: left; } .nav-tabs li.bv-tab-success > a { - color: #3c763d; + color: #3c763d; } .nav-tabs li.bv-tab-error > a { - color: #a94442; + color: #a94442; } diff --git a/src/libs/jquery.bootstrapvalidator/bootstrapValidator.js b/src/libs/jquery.bootstrapvalidator/bootstrapValidator.js new file mode 100644 index 00000000..cb4123ad --- /dev/null +++ b/src/libs/jquery.bootstrapvalidator/bootstrapValidator.js @@ -0,0 +1,6738 @@ +/*! + * BootstrapValidator (http://bootstrapvalidator.com) + * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3 + * + * @version v0.5.0, built on 2014-07-14 4:31:02 PM + * @author https://twitter.com/nghuuphuoc + * @copyright (c) 2013 - 2014 Nguyen Huu Phuoc + * @license MIT + */ +(function($) { + var BootstrapValidator = function(form, options) { + this.$form = $(form); + this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options); + + this.$invalidFields = $([]); // Array of invalid fields + this.$submitButton = null; // The submit button which is clicked to submit form + + // Validating status + this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED'; + this.STATUS_VALIDATING = 'VALIDATING'; + this.STATUS_INVALID = 'INVALID'; + this.STATUS_VALID = 'VALID'; + + // Determine the event that is fired when user change the field value + // Most modern browsers supports input event except IE 7, 8. + // IE 9 supports input event but the event is still not fired if I press the backspace key. + // Get IE version + // https://gist.github.com/padolsey/527683/#comment-7595 + var ieVersion = (function() { + var v = 3, + div = document.createElement('div'), + a = div.all || []; + while (((div.innerHTML = ''), a[0])) {} + return v > 4 ? v : !v; + })(); + + var el = document.createElement('div'); + this._changeEvent = ieVersion === 9 || !('oninput' in el) ? 'keyup' : 'input'; + + // The flag to indicate that the form is ready to submit when a remote/callback validator returns + this._submitIfValid = null; + + // Field elements + this._cacheFields = {}; + + this._init(); + }; + + BootstrapValidator.prototype = { + constructor: BootstrapValidator, + + /** + * Init form + */ + _init: function() { + var that = this, + options = { + excluded: this.$form.attr('data-bv-excluded'), + trigger: this.$form.attr('data-bv-trigger'), + message: this.$form.attr('data-bv-message'), + container: this.$form.attr('data-bv-container'), + group: this.$form.attr('data-bv-group'), + submitButtons: this.$form.attr('data-bv-submitbuttons'), + threshold: this.$form.attr('data-bv-threshold'), + live: this.$form.attr('data-bv-live'), + onSuccess: this.$form.attr('data-bv-onsuccess'), + onError: this.$form.attr('data-bv-onerror'), + fields: {}, + feedbackIcons: { + valid: this.$form.attr('data-bv-feedbackicons-valid'), + invalid: this.$form.attr('data-bv-feedbackicons-invalid'), + validating: this.$form.attr('data-bv-feedbackicons-validating'), + }, + }; + + this.$form + // Disable client side validation in HTML 5 + .attr('novalidate', 'novalidate') + .addClass(this.options.elementClass) + // Disable the default submission first + .on('submit.bv', function(e) { + e.preventDefault(); + that.validate(); + }) + .on('click.bv', this.options.submitButtons, function() { + that.$submitButton = $(this); + // The user just click the submit button + that._submitIfValid = true; + }) + // Find all fields which have either "name" or "data-bv-field" attribute + .find('[name], [data-bv-field]') + .each(function() { + var $field = $(this), + field = $field.attr('name') || $field.attr('data-bv-field'), + opts = that._parseOptions($field); + if (opts) { + $field.attr('data-bv-field', field); + options.fields[field] = $.extend({}, opts, options.fields[field]); + } + }); + + this.options = $.extend(true, this.options, options); + for (var field in this.options.fields) { + this._initField(field); + } + + this.$form.trigger($.Event('init.form.bv'), { + bv: this, + options: this.options, + }); + + // Prepare the events + if (this.options.onSuccess) { + this.$form.on('success.form.bv', function(e) { + $.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]); + }); + } + if (this.options.onError) { + this.$form.on('error.form.bv', function(e) { + $.fn.bootstrapValidator.helpers.call(that.options.onError, [e]); + }); + } + }, + + /** + * Parse the validator options from HTML attributes + * + * @param {jQuery} $field The field element + * @returns {Object} + */ + _parseOptions: function($field) { + var field = $field.attr('name') || $field.attr('data-bv-field'), + validators = {}, + validator, + v, // Validator name + enabled, + optionName, + optionValue, + html5AttrName, + html5AttrMap; + + for (v in $.fn.bootstrapValidator.validators) { + validator = $.fn.bootstrapValidator.validators[v]; + enabled = $field.attr('data-bv-' + v.toLowerCase()) + ''; + html5AttrMap = 'function' === typeof validator.enableByHtml5 ? validator.enableByHtml5($field) : null; + + if ((html5AttrMap && enabled !== 'false') || (html5AttrMap !== true && ('' === enabled || 'true' === enabled))) { + // Try to parse the options via attributes + validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes); + validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]); + + for (html5AttrName in validator.html5Attributes) { + optionName = validator.html5Attributes[html5AttrName]; + optionValue = $field.attr('data-bv-' + v.toLowerCase() + '-' + html5AttrName); + if (optionValue) { + if ('true' === optionValue) { + optionValue = true; + } else if ('false' === optionValue) { + optionValue = false; + } + validators[v][optionName] = optionValue; + } + } + } + } + + var opts = { + excluded: $field.attr('data-bv-excluded'), + feedbackIcons: $field.attr('data-bv-feedbackicons'), + trigger: $field.attr('data-bv-trigger'), + message: $field.attr('data-bv-message'), + container: $field.attr('data-bv-container'), + group: $field.attr('data-bv-group'), + selector: $field.attr('data-bv-selector'), + threshold: $field.attr('data-bv-threshold'), + onStatus: $field.attr('data-bv-onstatus'), + onSuccess: $field.attr('data-bv-onsuccess'), + onError: $field.attr('data-bv-onerror'), + validators: validators, + }, + emptyOptions = $.isEmptyObject(opts), // Check if the field options are set using HTML attributes + emptyValidators = $.isEmptyObject(validators); // Check if the field validators are set using HTML attributes + + if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) { + opts.validators = validators; + return opts; + } else { + return null; + } + }, + + /** + * Init field + * + * @param {String|jQuery} field The field name or field element + */ + _initField: function(field) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + fields = this.getFieldElements(field); + fields.attr('data-bv-field', field); + break; + default: + break; + } + + if (this.options.fields[field] === null || this.options.fields[field].validators === null) { + return; + } + + // We don't need to validate non-existing fields + if (fields.length === 0) { + delete this.options.fields[field]; + return; + } + var validatorName; + for (validatorName in this.options.fields[field].validators) { + if (!$.fn.bootstrapValidator.validators[validatorName]) { + delete this.options.fields[field].validators[validatorName]; + } + } + if (this.options.fields[field].enabled === null) { + this.options.fields[field].enabled = true; + } + + var that = this, + total = fields.length, + type = fields.attr('type'), + updateAll = total === 1 || 'radio' === type || 'checkbox' === type, + event = 'radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName ? 'change' : this._changeEvent, + trigger = (this.options.fields[field].trigger || this.options.trigger || event).split(' '), + events = $.map(trigger, function(item) { + return item + '.update.bv'; + }).join(' '); + + for (var i = 0; i < total; i++) { + var $field = fields.eq(i), + group = this.options.fields[field].group || this.options.group, + $parent = $field.parents(group), + // Allow user to indicate where the error messages are shown + container = this.options.fields[field].container || this.options.container, + $message = container && container !== 'tooltip' && container !== 'popover' ? $(container) : this._getMessageContainer($field, group); + + if (container && container !== 'tooltip' && container !== 'popover') { + $message.addClass('has-error'); + } + + // Remove all error messages and feedback icons + $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove(); + $parent.find('i[data-bv-icon-for="' + field + '"]').remove(); + + // Whenever the user change the field value, mark it as not validated yet + $field.off(events).on(events, function() { + that.updateStatus($(this), that.STATUS_NOT_VALIDATED); + }); + + // Create help block elements for showing the error messages + $field.data('bv.messages', $message); + for (validatorName in this.options.fields[field].validators) { + $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED); + + if (!updateAll || i === total - 1) { + $('') + .css('display', 'none') + .addClass('help-block') + .attr('data-bv-validator', validatorName) + .attr('data-bv-for', field) + .attr('data-bv-result', this.STATUS_NOT_VALIDATED) + .html(this._getMessage(field, validatorName)) + .appendTo($message); + } + + // Prepare the validator events + if (this.options.fields[field].validators[validatorName].onSuccess) { + $field.on('success.validator.bv', function(e, data) { + $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onSuccess, [e, data]); + }); + } + if (this.options.fields[field].validators[validatorName].onError) { + $field.on('error.validator.bv', function(e, data) { + $.fn.bootstrapValidator.helpers.call(that.options.fields[field].validators[validatorName].onError, [e, data]); + }); + } + } + + // Prepare the feedback icons + // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation) + if ( + this.options.fields[field].feedbackIcons !== false && + this.options.fields[field].feedbackIcons !== 'false' && + this.options.feedbackIcons && + this.options.feedbackIcons.validating && + this.options.feedbackIcons.invalid && + this.options.feedbackIcons.valid && + (!updateAll || i === total - 1) + ) { + $parent + .removeClass('has-success') + .removeClass('has-error') + .addClass('has-feedback'); + var $icon = $('') + .css('display', 'none') + .addClass('form-control-feedback') + .attr('data-bv-icon-for', field) + // Place it after the label containing the checkbox/radio + // so when clicking the icon, it doesn't effect to the checkbox/radio element + .insertAfter('checkbox' === type || 'radio' === type ? $field.parent() : $field); + + // The feedback icon does not render correctly if there is no label + // https://github.com/twbs/bootstrap/issues/12873 + if ($parent.find('label').length === 0) { + $icon.css('top', 0); + } + // Fix feedback icons in input-group + if ($parent.find('.input-group').length !== 0) { + $icon + .css({ + top: 0, + 'z-index': 100, + }) + .insertAfter($parent.find('.input-group').eq(0)); + } + } + } + + // Prepare the events + if (this.options.fields[field].onSuccess) { + fields.on('success.field.bv', function(e, data) { + $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onSuccess, [e, data]); + }); + } + if (this.options.fields[field].onError) { + fields.on('error.field.bv', function(e, data) { + $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onError, [e, data]); + }); + } + if (this.options.fields[field].onStatus) { + fields.on('status.field.bv', function(e, data) { + $.fn.bootstrapValidator.helpers.call(that.options.fields[field].onStatus, [e, data]); + }); + } + + // Set live mode + events = $.map(trigger, function(item) { + return item + '.live.bv'; + }).join(' '); + switch (this.options.live) { + case 'submitted': + break; + case 'disabled': + fields.off(events); + break; + case 'enabled': + /* falls through */ + default: + fields.off(events).on(events, function() { + if (that._exceedThreshold($(this))) { + that.validateField($(this)); + } + }); + break; + } + + fields.trigger($.Event('init.field.bv'), { + bv: this, + field: field, + element: fields, + }); + }, + + /** + * Get the error message for given field and validator + * + * @param {String} field The field name + * @param {String} validatorName The validator name + * @returns {String} + */ + _getMessage: function(field, validatorName) { + if ( + !this.options.fields[field] || + !$.fn.bootstrapValidator.validators[validatorName] || + !this.options.fields[field].validators || + !this.options.fields[field].validators[validatorName] + ) { + return ''; + } + + var options = this.options.fields[field].validators[validatorName]; + switch (true) { + case !!options.message: + return options.message; + case !!this.options.fields[field].message: + return this.options.fields[field].message; + case !!$.fn.bootstrapValidator.i18n[validatorName]: + return $.fn.bootstrapValidator.i18n[validatorName]['default']; + default: + return this.options.message; + } + }, + + /** + * Get the element to place the error messages + * + * @param {jQuery} $field The field element + * @param {String} group + * @returns {jQuery} + */ + _getMessageContainer: function($field, group) { + var $parent = $field.parent(); + if ($parent.is(group)) { + return $parent; + } + + var cssClasses = $parent.attr('class'); + if (!cssClasses) { + return this._getMessageContainer($parent, group); + } + + cssClasses = cssClasses.split(' '); + var n = cssClasses.length; + for (var i = 0; i < n; i++) { + if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) { + return $parent; + } + } + + return this._getMessageContainer($parent, group); + }, + + /** + * Called when all validations are completed + */ + _submit: function() { + var isValid = this.isValid(), + eventType = isValid ? 'success.form.bv' : 'error.form.bv', + e = $.Event(eventType); + + this.$form.trigger(e); + + // Call default handler + // Check if whether the submit button is clicked + if (this.$submitButton) { + isValid ? this._onSuccess(e) : this._onError(e); + } + }, + + /** + * Check if the field is excluded. + * Returning true means that the field will not be validated + * + * @param {jQuery} $field The field element + * @returns {Boolean} + */ + _isExcluded: function($field) { + var excludedAttr = $field.attr('data-bv-excluded'), + // I still need to check the 'name' attribute while initializing the field + field = $field.attr('data-bv-field') || $field.attr('name'); + + switch (true) { + case !!field && + this.options.fields && + this.options.fields[field] && + (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true): + case excludedAttr === 'true': + case excludedAttr === '': + return true; + + case !!field && + this.options.fields && + this.options.fields[field] && + (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false): + case excludedAttr === 'false': + return false; + + default: + if (this.options.excluded) { + // Convert to array first + if ('string' === typeof this.options.excluded) { + this.options.excluded = $.map(this.options.excluded.split(','), function(item) { + // Trim the spaces + return $.trim(item); + }); + } + + var length = this.options.excluded.length; + for (var i = 0; i < length; i++) { + if ( + ('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i])) || + ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true) + ) { + return true; + } + } + } + return false; + } + }, + + /** + * Check if the number of characters of field value exceed the threshold or not + * + * @param {jQuery} $field The field element + * @returns {Boolean} + */ + _exceedThreshold: function($field) { + var field = $field.attr('data-bv-field'), + threshold = this.options.fields[field].threshold || this.options.threshold; + if (!threshold) { + return true; + } + var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1; + return cannotType || $field.val().length >= threshold; + }, + + // --- + // Events + // --- + + /** + * The default handler of error.form.bv event. + * It will be called when there is a invalid field + * + * @param {jQuery.Event} e The jQuery event object + */ + _onError: function(e) { + if (e.isDefaultPrevented()) { + return; + } + + if ('submitted' === this.options.live) { + // Enable live mode + this.options.live = 'enabled'; + var that = this; + for (var field in this.options.fields) { + (function(f) { + var fields = that.getFieldElements(f); + if (fields.length) { + var type = $(fields[0]).attr('type'), + event = 'radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName ? 'change' : that._changeEvent, + trigger = that.options.fields[field].trigger || that.options.trigger || event, + events = $.map(trigger.split(' '), function(item) { + return item + '.live.bv'; + }).join(' '); + + fields.off(events).on(events, function() { + if (that._exceedThreshold($(this))) { + that.validateField($(this)); + } + }); + } + })(field); + } + } + + var $invalidField = this.$invalidFields.eq(0); + if ($invalidField) { + // Activate the tab containing the invalid field if exists + var $tabPane = $invalidField.parents('.tab-pane'), + tabId; + if ($tabPane && (tabId = $tabPane.attr('id'))) { + $('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show'); + } + + // Focus to the first invalid field + $invalidField.focus(); + } + }, + + /** + * The default handler of success.form.bv event. + * It will be called when all the fields are valid + * + * @param {jQuery.Event} e The jQuery event object + */ + _onSuccess: function(e) { + if (e.isDefaultPrevented()) { + return; + } + + // Submit the form + this.disableSubmitButtons(true).defaultSubmit(); + }, + + /** + * Called after validating a field element + * + * @param {jQuery} $field The field element + * @param {String} [validatorName] The validator name + */ + _onFieldValidated: function($field, validatorName) { + var field = $field.attr('data-bv-field'), + validators = this.options.fields[field].validators, + counter = {}, + numValidators = 0, + data = { + bv: this, + field: field, + element: $field, + validator: validatorName, + }; + + // Trigger an event after given validator completes + if (validatorName) { + switch ($field.data('bv.result.' + validatorName)) { + case this.STATUS_INVALID: + $field.trigger($.Event('error.validator.bv'), data); + break; + case this.STATUS_VALID: + $field.trigger($.Event('success.validator.bv'), data); + break; + default: + break; + } + } + + counter[this.STATUS_NOT_VALIDATED] = 0; + counter[this.STATUS_VALIDATING] = 0; + counter[this.STATUS_INVALID] = 0; + counter[this.STATUS_VALID] = 0; + + for (var v in validators) { + if (validators[v].enabled === false) { + continue; + } + + numValidators++; + var result = $field.data('bv.result.' + v); + if (result) { + counter[result]++; + } + } + + if (counter[this.STATUS_VALID] === numValidators) { + // Remove from the list of invalid fields + this.$invalidFields = this.$invalidFields.not($field); + + $field.trigger($.Event('success.field.bv'), data); + } + // If all validators are completed and there is at least one validator which doesn't pass + else if (counter[this.STATUS_NOT_VALIDATED] === 0 && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) { + // Add to the list of invalid fields + this.$invalidFields = this.$invalidFields.add($field); + + $field.trigger($.Event('error.field.bv'), data); + } + }, + + // --- + // Public methods + // --- + + /** + * Retrieve the field elements by given name + * + * @param {String} field The field name + * @returns {null|jQuery[]} + */ + getFieldElements: function(field) { + if (!this._cacheFields[field]) { + this._cacheFields[field] = + this.options.fields[field] && this.options.fields[field].selector ? $(this.options.fields[field].selector) : this.$form.find('[name="' + field + '"]'); + } + + return this._cacheFields[field]; + }, + + /** + * Disable/enable submit buttons + * + * @param {Boolean} disabled Can be true or false + * @returns {BootstrapValidator} + */ + disableSubmitButtons: function(disabled) { + if (!disabled) { + this.$form.find(this.options.submitButtons).removeAttr('disabled'); + } else if (this.options.live !== 'disabled') { + // Don't disable if the live validating mode is disabled + this.$form.find(this.options.submitButtons).attr('disabled', 'disabled'); + } + + return this; + }, + + /** + * Validate the form + * + * @returns {BootstrapValidator} + */ + validate: function() { + if (!this.options.fields) { + return this; + } + this.disableSubmitButtons(true); + + for (var field in this.options.fields) { + this.validateField(field); + } + + this._submit(); + + return this; + }, + + /** + * Validate given field + * + * @param {String|jQuery} field The field name or field element + * @returns {BootstrapValidator} + */ + validateField: function(field) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + fields = this.getFieldElements(field); + break; + default: + break; + } + + if (this.options.fields[field] && this.options.fields[field].enabled === false) { + return this; + } + + var that = this, + type = fields.attr('type'), + total = 'radio' === type || 'checkbox' === type ? 1 : fields.length, + updateAll = 'radio' === type || 'checkbox' === type, + validators = this.options.fields[field].validators, + validatorName, + validateResult; + + for (var i = 0; i < total; i++) { + var $field = fields.eq(i); + if (this._isExcluded($field)) { + continue; + } + + for (validatorName in validators) { + if ($field.data('bv.dfs.' + validatorName)) { + $field.data('bv.dfs.' + validatorName).reject(); + } + + // Don't validate field if it is already done + var result = $field.data('bv.result.' + validatorName); + if (result === this.STATUS_VALID || result === this.STATUS_INVALID || validators[validatorName].enabled === false) { + this._onFieldValidated($field, validatorName); + continue; + } + + $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING); + validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]); + + // validateResult can be a $.Deferred object ... + if ('object' === typeof validateResult && validateResult.resolve) { + this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName); + $field.data('bv.dfs.' + validatorName, validateResult); + + validateResult.done(function($f, v, isValid, message) { + // v is validator name + $f.removeData('bv.dfs.' + v); + if (message) { + that.updateMessage($f, v, message); + } + + that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, isValid ? that.STATUS_VALID : that.STATUS_INVALID, v); + + if (isValid && that._submitIfValid === true) { + // If a remote validator returns true and the form is ready to submit, then do it + that._submit(); + } + }); + } + // ... or object { valid: true/false, message: 'dynamic message' } + else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) { + this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message); + this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName); + } + // ... or a boolean value + else if ('boolean' === typeof validateResult) { + this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName); + } + } + } + + return this; + }, + + /** + * Update the error message + * + * @param {String|jQuery} field The field name or field element + * @param {String} validator The validator name + * @param {String} message The message + * @returns {BootstrapValidator} + */ + updateMessage: function(field, validator, message) { + var $fields = $([]); + switch (typeof field) { + case 'object': + $fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + $fields = this.getFieldElements(field); + break; + default: + break; + } + + $fields.each(function() { + $(this) + .data('bv.messages') + .find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]') + .html(message); + }); + }, + + /** + * Update all validating results of field + * + * @param {String|jQuery} field The field name or field element + * @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID' + * @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators + * @returns {BootstrapValidator} + */ + updateStatus: function(field, status, validatorName) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + fields = this.getFieldElements(field); + break; + default: + break; + } + + if (status === this.STATUS_NOT_VALIDATED) { + // Reset the flag + this._submitIfValid = false; + } + + var that = this, + type = fields.attr('type'), + group = this.options.fields[field].group || this.options.group, + total = 'radio' === type || 'checkbox' === type ? 1 : fields.length; + + for (var i = 0; i < total; i++) { + var $field = fields.eq(i); + if (this._isExcluded($field)) { + continue; + } + + var $parent = $field.parents(group), + $message = $field.data('bv.messages'), + $allErrors = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'), + $errors = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors, + $icon = $parent.find('.form-control-feedback[data-bv-icon-for="' + field + '"]'), + container = this.options.fields[field].container || this.options.container, + isValidField = null; + + // Update status + if (validatorName) { + $field.data('bv.result.' + validatorName, status); + } else { + for (var v in this.options.fields[field].validators) { + $field.data('bv.result.' + v, status); + } + } + + // Show/hide error elements and feedback icons + $errors.attr('data-bv-result', status); + + // Determine the tab containing the element + var $tabPane = $field.parents('.tab-pane'), + tabId, + $tab; + if ($tabPane && (tabId = $tabPane.attr('id'))) { + $tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent(); + } + + switch (status) { + case this.STATUS_VALIDATING: + isValidField = null; + this.disableSubmitButtons(true); + $parent.removeClass('has-success').removeClass('has-error'); + if ($icon) { + $icon + .removeClass(this.options.feedbackIcons.valid) + .removeClass(this.options.feedbackIcons.invalid) + .addClass(this.options.feedbackIcons.validating) + .show(); + } + if ($tab) { + $tab.removeClass('bv-tab-success').removeClass('bv-tab-error'); + } + break; + + case this.STATUS_INVALID: + isValidField = false; + this.disableSubmitButtons(true); + $parent.removeClass('has-success').addClass('has-error'); + if ($icon) { + $icon + .removeClass(this.options.feedbackIcons.valid) + .removeClass(this.options.feedbackIcons.validating) + .addClass(this.options.feedbackIcons.invalid) + .show(); + } + if ($tab) { + $tab.removeClass('bv-tab-success').addClass('bv-tab-error'); + } + break; + + case this.STATUS_VALID: + // If the field is valid (passes all validators) + isValidField = + $allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED + '"]').length === 0 + ? $allErrors.filter('[data-bv-result="' + this.STATUS_VALID + '"]').length === $allErrors.length // All validators are completed + : null; // There are some validators that have not done + if (isValidField !== null) { + this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField); + if ($icon) { + $icon + .removeClass(this.options.feedbackIcons.invalid) + .removeClass(this.options.feedbackIcons.validating) + .removeClass(this.options.feedbackIcons.valid) + .addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid) + .show(); + } + } + + $parent.removeClass('has-error has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-error'); + if ($tab) { + $tab.removeClass('bv-tab-success') + .removeClass('bv-tab-error') + .addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error'); + } + break; + + case this.STATUS_NOT_VALIDATED: + /* falls through */ + default: + isValidField = null; + this.disableSubmitButtons(false); + $parent.removeClass('has-success').removeClass('has-error'); + if ($icon) { + $icon + .removeClass(this.options.feedbackIcons.valid) + .removeClass(this.options.feedbackIcons.invalid) + .removeClass(this.options.feedbackIcons.validating) + .hide(); + } + if ($tab) { + $tab.removeClass('bv-tab-success').removeClass('bv-tab-error'); + } + break; + } + + switch (true) { + // Only show the first error message if it is placed inside a tooltip ... + case $icon && 'tooltip' === container: + isValidField === false + ? $icon + .css('cursor', 'pointer') + .tooltip('destroy') + .tooltip({ + html: true, + placement: 'top', + title: $allErrors + .filter('[data-bv-result="' + that.STATUS_INVALID + '"]') + .eq(0) + .html(), + }) + : $icon.css('cursor', '').tooltip('destroy'); + break; + // ... or popover + case $icon && 'popover' === container: + isValidField === false + ? $icon + .css('cursor', 'pointer') + .popover('destroy') + .popover({ + content: $allErrors + .filter('[data-bv-result="' + that.STATUS_INVALID + '"]') + .eq(0) + .html(), + html: true, + placement: 'top', + trigger: 'hover click', + }) + : $icon.css('cursor', '').popover('destroy'); + break; + default: + status === this.STATUS_INVALID ? $errors.show() : $errors.hide(); + break; + } + + // Trigger an event + $field.trigger($.Event('status.field.bv'), { + bv: this, + field: field, + element: $field, + status: status, + }); + this._onFieldValidated($field, validatorName); + } + + return this; + }, + + /** + * Check the form validity + * + * @returns {Boolean} + */ + isValid: function() { + for (var field in this.options.fields) { + if (!this.isValidField(field)) { + return false; + } + } + + return true; + }, + + /** + * Check if the field is valid or not + * + * @param {String|jQuery} field The field name or field element + * @returns {Boolean} + */ + isValidField: function(field) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + fields = this.getFieldElements(field); + break; + default: + break; + } + if (fields.length === 0 || this.options.fields[field] === null || this.options.fields[field].enabled === false) { + return true; + } + + var type = fields.attr('type'), + total = 'radio' === type || 'checkbox' === type ? 1 : fields.length, + $field, + validatorName, + status; + for (var i = 0; i < total; i++) { + $field = fields.eq(i); + if (this._isExcluded($field)) { + continue; + } + + for (validatorName in this.options.fields[field].validators) { + if (this.options.fields[field].validators[validatorName].enabled === false) { + continue; + } + + status = $field.data('bv.result.' + validatorName); + if (status !== this.STATUS_VALID) { + return false; + } + } + } + + return true; + }, + + /** + * Check if all fields inside a given container are valid. + * It's useful when working with a wizard-like such as tab, collapse + * + * @param {String|jQuery} container The container selector or element + * @returns {Boolean} + */ + isValidContainer: function(container) { + var that = this, + map = {}, + $container = 'string' === typeof container ? $(container) : container; + if ($container.length === 0) { + return true; + } + + $container.find('[data-bv-field]').each(function() { + var $field = $(this), + field = $field.attr('data-bv-field'); + if (!that._isExcluded($field) && !map[field]) { + map[field] = $field; + } + }); + + for (var field in map) { + var $f = map[field]; + if ( + $f + .data('bv.messages') + .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]') + .filter(function() { + var v = $(this).attr('data-bv-validator'), + f = $(this).attr('data-bv-for'); + return that.options.fields[f].validators[v].enabled !== false && $f.data('bv.result.' + v) && $f.data('bv.result.' + v) !== that.STATUS_VALID; + }).length !== 0 + ) { + // The field is not valid + return false; + } + } + + return true; + }, + + /** + * Submit the form using default submission. + * It also does not perform any validations when submitting the form + */ + defaultSubmit: function() { + if (this.$submitButton) { + // Create hidden input to send the submit buttons + $('') + .attr('type', 'hidden') + .attr('data-bv-submit-hidden', '') + .attr('name', this.$submitButton.attr('name')) + .val(this.$submitButton.val()) + .appendTo(this.$form); + } + + // Submit form + this.$form.off('submit.bv').submit(); + }, + + // --- + // Useful APIs which aren't used internally + // --- + + /** + * Get the list of invalid fields + * + * @returns {jQuery[]} + */ + getInvalidFields: function() { + return this.$invalidFields; + }, + + /** + * Returns the clicked submit button + * + * @returns {jQuery} + */ + getSubmitButton: function() { + return this.$submitButton; + }, + + /** + * Get the error messages + * + * @param {String|jQuery} [field] The field name or field element + * If the field is not defined, the method returns all error messages of all fields + * @param {String} [validator] The name of validator + * If the validator is not defined, the method returns error messages of all validators + * @returns {String[]} + */ + getMessages: function(field, validator) { + var that = this, + messages = [], + $fields = $([]); + + switch (true) { + case field && 'object' === typeof field: + $fields = field; + break; + case field && 'string' === typeof field: + var f = this.getFieldElements(field); + if (f.length > 0) { + var type = f.attr('type'); + $fields = 'radio' === type || 'checkbox' === type ? f.eq(0) : f; + } + break; + default: + $fields = this.$invalidFields; + break; + } + + var filter = validator ? '[data-bv-validator="' + validator + '"]' : ''; + $fields.each(function() { + messages = messages.concat( + $(this) + .data('bv.messages') + .find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter) + .map(function() { + var v = $(this).attr('data-bv-validator'), + f = $(this).attr('data-bv-for'); + return that.options.fields[f].validators[v].enabled === false ? '' : $(this).html(); + }) + .get() + ); + }); + + return messages; + }, + + /** + * Get the field options + * + * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options + * @param {String} [validator] The name of validator. It null, the method returns form options + * @param {String} [option] The option name + * @return {String|Object} + */ + getOptions: function(field, validator, option) { + if (!field) { + return this.options; + } + if ('object' === typeof field) { + field = field.attr('data-bv-field'); + } + if (!this.options.fields[field]) { + return null; + } + + var options = this.options.fields[field]; + if (!validator) { + return options; + } + if (!options.validators || !options.validators[validator]) { + return null; + } + + return option ? options.validators[validator][option] : options.validators[validator]; + }, + + /** + * Update the option of a specific validator + * + * @param {String|jQuery} field The field name or field element + * @param {String} validator The validator name + * @param {String} option The option name + * @param {String} value The value to set + * @returns {BootstrapValidator} + */ + updateOption: function(field, validator, option, value) { + if ('object' === typeof field) { + field = field.attr('data-bv-field'); + } + if (this.options.fields[field] && this.options.fields[field].validators[validator]) { + this.options.fields[field].validators[validator][option] = value; + this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator); + } + + return this; + }, + + /** + * Add a new field + * + * @param {String|jQuery} field The field name or field element + * @param {Object} [options] The validator rules + * @returns {BootstrapValidator} + */ + addField: function(field, options) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field') || field.attr('name'); + break; + case 'string': + delete this._cacheFields[field]; + fields = this.getFieldElements(field); + break; + default: + break; + } + + fields.attr('data-bv-field', field); + + var type = fields.attr('type'), + total = 'radio' === type || 'checkbox' === type ? 1 : fields.length; + + for (var i = 0; i < total; i++) { + var $field = fields.eq(i); + + // Try to parse the options from HTML attributes + var opts = this._parseOptions($field); + opts = opts === null ? options : $.extend(true, options, opts); + + this.options.fields[field] = $.extend(true, this.options.fields[field], opts); + + // Update the cache + this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field; + + // Init the element + this._initField('checkbox' === type || 'radio' === type ? field : $field); + } + + this.disableSubmitButtons(false); + // Trigger an event + this.$form.trigger($.Event('added.field.bv'), { + field: field, + element: fields, + options: this.options.fields[field], + }); + + return this; + }, + + /** + * Remove a given field + * + * @param {String|jQuery} field The field name or field element + * @returns {BootstrapValidator} + */ + removeField: function(field) { + var fields = $([]); + switch (typeof field) { + case 'object': + fields = field; + field = field.attr('data-bv-field') || field.attr('name'); + fields.attr('data-bv-field', field); + break; + case 'string': + fields = this.getFieldElements(field); + break; + default: + break; + } + + if (fields.length === 0) { + return this; + } + + var type = fields.attr('type'), + total = 'radio' === type || 'checkbox' === type ? 1 : fields.length; + + for (var i = 0; i < total; i++) { + var $field = fields.eq(i); + + // Remove from the list of invalid fields + this.$invalidFields = this.$invalidFields.not($field); + + // Update the cache + this._cacheFields[field] = this._cacheFields[field].not($field); + } + + if (!this._cacheFields[field] || this._cacheFields[field].length === 0) { + delete this.options.fields[field]; + } + if ('checkbox' === type || 'radio' === type) { + this._initField(field); + } + + this.disableSubmitButtons(false); + // Trigger an event + this.$form.trigger($.Event('removed.field.bv'), { + field: field, + element: fields, + }); + + return this; + }, + + /** + * Reset given field + * + * @param {String|jQuery} field The field name or field element + * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox) + * @returns {BootstrapValidator} + */ + resetField: function(field, resetValue) { + var $fields = $([]); + switch (typeof field) { + case 'object': + $fields = field; + field = field.attr('data-bv-field'); + break; + case 'string': + $fields = this.getFieldElements(field); + break; + default: + break; + } + + var total = $fields.length; + if (this.options.fields[field]) { + for (var i = 0; i < total; i++) { + for (var validator in this.options.fields[field].validators) { + $fields.eq(i).removeData('bv.dfs.' + validator); + } + } + } + + // Mark field as not validated yet + this.updateStatus(field, this.STATUS_NOT_VALIDATED); + + if (resetValue) { + var type = $fields.attr('type'); + 'radio' === type || 'checkbox' === type ? $fields.removeAttr('checked').removeAttr('selected') : $fields.val(''); + } + + return this; + }, + + /** + * Reset the form + * + * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox) + * @returns {BootstrapValidator} + */ + resetForm: function(resetValue) { + for (var field in this.options.fields) { + this.resetField(field, resetValue); + } + + this.$invalidFields = $([]); + this.$submitButton = null; + + // Enable submit buttons + this.disableSubmitButtons(false); + + return this; + }, + + /** + * Revalidate given field + * It's used when you need to revalidate the field which its value is updated by other plugin + * + * @param {String|jQuery} field The field name of field element + * @returns {BootstrapValidator} + */ + revalidateField: function(field) { + this.updateStatus(field, this.STATUS_NOT_VALIDATED).validateField(field); + + return this; + }, + + /** + * Enable/Disable all validators to given field + * + * @param {String} field The field name + * @param {Boolean} enabled Enable/Disable field validators + * @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled + * @returns {BootstrapValidator} + */ + enableFieldValidators: function(field, enabled, validatorName) { + var validators = this.options.fields[field].validators; + + // Enable/disable particular validator + if (validatorName && validators && validators[validatorName] && validators[validatorName].enabled !== enabled) { + this.options.fields[field].validators[validatorName].enabled = enabled; + this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName); + } + // Enable/disable all validators + else if (!validatorName && this.options.fields[field].enabled !== enabled) { + this.options.fields[field].enabled = enabled; + for (var v in validators) { + this.enableFieldValidators(field, enabled, v); + } + } + + return this; + }, + + /** + * Some validators have option which its value is dynamic. + * For example, the zipCode validator has the country option which might be changed dynamically by a select element. + * + * @param {jQuery|String} field The field name or element + * @param {String|Function} option The option which can be determined by: + * - a string + * - name of field which defines the value + * - name of function which returns the value + * - a function returns the value + * + * The callback function has the format of + * callback: function(value, validator, $field) { + * // value is the value of field + * // validator is the BootstrapValidator instance + * // $field is the field element + * } + * + * @returns {String} + */ + getDynamicOption: function(field, option) { + var $field = 'string' === typeof field ? this.getFieldElements(field) : field, + value = $field.val(); + + // Option can be determined by + // ... a function + if ('function' === typeof option) { + return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]); + } + // ... value of other field + else if ('string' === typeof option) { + var $f = this.getFieldElements(option); + if ($f.length) { + return $f.val(); + } + // ... return value of callback + else { + return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]); + } + } + + return null; + }, + + /** + * Destroy the plugin + * It will remove all error messages, feedback icons and turn off the events + */ + destroy: function() { + var field, fields, $field, validator, $icon, container, group; + for (field in this.options.fields) { + fields = this.getFieldElements(field); + (container = this.options.fields[field].container || this.options.container), (group = this.options.fields[field].group || this.options.group); + for (var i = 0; i < fields.length; i++) { + $field = fields.eq(i); + $field + // Remove all error messages + .data('bv.messages') + .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]') + .remove() + .end() + .end() + .removeData('bv.messages') + // Remove feedback classes + .parents(group) + .removeClass('has-feedback has-error has-success') + .end() + // Turn off events + .off('.bv') + .removeAttr('data-bv-field'); + + // Remove feedback icons, tooltip/popover container + $icon = $field.parents(group).find('i[data-bv-icon-for="' + field + '"]'); + if ($icon) { + switch (container) { + case 'tooltip': + $icon.tooltip('destroy').remove(); + break; + case 'popover': + $icon.popover('destroy').remove(); + break; + default: + $icon.remove(); + break; + } + } + + for (validator in this.options.fields[field].validators) { + if ($field.data('bv.dfs.' + validator)) { + $field.data('bv.dfs.' + validator).reject(); + } + $field.removeData('bv.result.' + validator).removeData('bv.dfs.' + validator); + } + } + } + + // Enable submit buttons + this.disableSubmitButtons(false); + + this.$form + .removeClass(this.options.elementClass) + .off('.bv') + .removeData('bootstrapValidator') + // Remove generated hidden elements + .find('[data-bv-submit-hidden]') + .remove(); + }, + }; + + // Plugin definition + $.fn.bootstrapValidator = function(option) { + var params = arguments; + return this.each(function() { + var $this = $(this), + data = $this.data('bootstrapValidator'), + options = 'object' === typeof option && option; + if (!data) { + data = new BootstrapValidator(this, options); + $this.data('bootstrapValidator', data); + } + + // Allow to call plugin method + if ('string' === typeof option) { + data[option].apply(data, Array.prototype.slice.call(params, 1)); + } + }); + }; + + // The default options + $.fn.bootstrapValidator.DEFAULT_OPTIONS = { + // The form CSS class + elementClass: 'bv-form', + + // Default invalid message + message: 'This value is not valid', + + // The CSS selector for indicating the element consists the field + // By default, each field is placed inside the
+ // You should adjust this option if your form group consists of many fields which not all of them need to be validated + group: '.form-group', + + //The error messages container. It can be: + // - 'tooltip' if you want to use Bootstrap tooltip to show error messages + // - 'popover' if you want to use Bootstrap popover to show error messages + // - a CSS selector indicating the container + // In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message + // You also can define the message container for particular field + container: null, + + // The field will not be live validated if its length is less than this number of characters + threshold: null, + + // Indicate fields which won't be validated + // By default, the plugin will not validate the following kind of fields: + // - disabled + // - hidden + // - invisible + // + // The setting consists of jQuery filters. Accept 3 formats: + // - A string. Use a comma to separate filter + // - An array. Each element is a filter + // - An array. Each element can be a callback function + // function($field, validator) { + // $field is jQuery object representing the field element + // validator is the BootstrapValidator instance + // return true or false; + // } + // + // The 3 following settings are equivalent: + // + // 1) ':disabled, :hidden, :not(:visible)' + // 2) [':disabled', ':hidden', ':not(:visible)'] + // 3) [':disabled', ':hidden', function($field) { + // return !$field.is(':visible'); + // }] + excluded: [':disabled', ':hidden', ':not(:visible)'], + + // Shows ok/error/loading icons based on the field validity. + // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation). + // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically. + // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later. + // + // Examples: + // - Use Glyphicons icons: + // feedbackIcons: { + // valid: 'glyphicon glyphicon-ok', + // invalid: 'glyphicon glyphicon-remove', + // validating: 'glyphicon glyphicon-refresh' + // } + // - Use FontAwesome icons: + // feedbackIcons: { + // valid: 'fa fa-check', + // invalid: 'fa fa-times', + // validating: 'fa fa-refresh' + // } + feedbackIcons: { + valid: null, + invalid: null, + validating: null, + }, + + // The submit buttons selector + // These buttons will be disabled to prevent the valid form from multiple submissions + submitButtons: '[type="submit"]', + + // Live validating option + // Can be one of 3 values: + // - enabled: The plugin validates fields as soon as they are changed + // - disabled: Disable the live validating. The error messages are only shown after the form is submitted + // - submitted: The live validating is enabled after the form is submitted + live: 'enabled', + + // Map the field name with validator rules + fields: null, + }; + + // Available validators + $.fn.bootstrapValidator.validators = {}; + + // i18n + $.fn.bootstrapValidator.i18n = {}; + + $.fn.bootstrapValidator.Constructor = BootstrapValidator; + + // Helper methods, which can be used in validator class + $.fn.bootstrapValidator.helpers = { + /** + * Execute a callback function + * + * @param {String|Function} functionName Can be + * - name of global function + * - name of namespace function (such as A.B.C) + * - a function + * @param {Array} args The callback arguments + */ + call: function(functionName, args) { + if ('function' === typeof functionName) { + return functionName.apply(this, args); + } else if ('string' === typeof functionName) { + if ('()' === functionName.substring(functionName.length - 2)) { + functionName = functionName.substring(0, functionName.length - 2); + } + var ns = functionName.split('.'), + func = ns.pop(), + context = window; + for (var i = 0; i < ns.length; i++) { + context = context[ns[i]]; + } + return context[func].apply(this, args); + } + }, + + /** + * Format a string + * It's used to format the error message + * format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20' + * + * @param {String} message + * @param {Array} parameters + * @returns {String} + */ + format: function(message, parameters) { + if (!$.isArray(parameters)) { + parameters = [parameters]; + } + + for (var i in parameters) { + message = message.replace('%s', parameters[i]); + } + + return message; + }, + + /** + * Validate a date + * + * @param {Number} year The full year in 4 digits + * @param {Number} month The month number + * @param {Number} day The day number + * @param {Boolean} [notInFuture] If true, the date must not be in the future + * @returns {Boolean} + */ + date: function(year, month, day, notInFuture) { + if (isNaN(year) || isNaN(month) || isNaN(day)) { + return false; + } + + day = parseInt(day, 10); + month = parseInt(month, 10); + year = parseInt(year, 10); + + if (year < 1000 || year > 9999 || month <= 0 || month > 12) { + return false; + } + var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + // Update the number of days in Feb of leap year + if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) { + numDays[1] = 29; + } + + // Check the day + if (day <= 0 || day > numDays[month - 1]) { + return false; + } + + if (notInFuture === true) { + var currentDate = new Date(), + currentYear = currentDate.getFullYear(), + currentMonth = currentDate.getMonth(), + currentDay = currentDate.getDate(); + return year < currentYear || (year === currentYear && month - 1 < currentMonth) || (year === currentYear && month - 1 === currentMonth && day < currentDay); + } + + return true; + }, + + /** + * Implement Luhn validation algorithm + * Credit to https://gist.github.com/ShirtlessKirk/2134376 + * + * @see http://en.wikipedia.org/wiki/Luhn + * @param {String} value + * @returns {Boolean} + */ + luhn: function(value) { + var length = value.length, + mul = 0, + prodArr = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + [0, 2, 4, 6, 8, 1, 3, 5, 7, 9], + ], + sum = 0; + + while (length--) { + sum += prodArr[mul][parseInt(value.charAt(length), 10)]; + mul ^= 1; + } + + return sum % 10 === 0 && sum > 0; + }, + + /** + * Implement modulus 11, 10 (ISO 7064) algorithm + * + * @param {String} value + * @returns {Boolean} + */ + mod11And10: function(value) { + var check = 5, + length = value.length; + for (var i = 0; i < length; i++) { + check = ((((check || 10) * 2) % 11) + parseInt(value.charAt(i), 10)) % 10; + } + return check === 1; + }, + + /** + * Implements Mod 37, 36 (ISO 7064) algorithm + * Usages: + * mod37And36('A12425GABC1234002M') + * mod37And36('002006673085', '0123456789') + * + * @param {String} value + * @param {String} [alphabet] + * @returns {Boolean} + */ + mod37And36: function(value, alphabet) { + alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + var modulus = alphabet.length, + length = value.length, + check = Math.floor(modulus / 2); + for (var i = 0; i < length; i++) { + check = ((((check || modulus) * 2) % (modulus + 1)) + alphabet.indexOf(value.charAt(i))) % modulus; + } + return check === 1; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.base64 = $.extend($.fn.bootstrapValidator.i18n.base64 || {}, { + default: 'Please enter a valid base 64 encoded', + }); + + $.fn.bootstrapValidator.validators.base64 = { + /** + * Return true if the input value is a base 64 encoded string. + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.between = $.extend($.fn.bootstrapValidator.i18n.between || {}, { + default: 'Please enter a value between %s and %s', + notInclusive: 'Please enter a value between %s and %s strictly', + }); + + $.fn.bootstrapValidator.validators.between = { + html5Attributes: { + message: 'message', + min: 'min', + max: 'max', + inclusive: 'inclusive', + }, + + enableByHtml5: function($field) { + if ('range' === $field.attr('type')) { + return { + min: $field.attr('min'), + max: $field.attr('max'), + }; + } + + return false; + }, + + /** + * Return true if the input value is between (strictly or not) two given numbers + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - min + * - max + * + * The min, max keys define the number which the field value compares to. min, max can be + * - A number + * - Name of field which its value defines the number + * - Name of callback function that returns the number + * - A callback function that returns the number + * + * - inclusive [optional]: Can be true or false. Default is true + * - message: The invalid message + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var min = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min), + max = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max); + + value = parseFloat(value); + return options.inclusive === true || options.inclusive === undefined + ? { + valid: value >= min && value <= max, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between['default'], [min, max]), + } + : { + valid: value > min && value < max, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.between.notInclusive, [min, max]), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.callback = $.extend($.fn.bootstrapValidator.i18n.callback || {}, { + default: 'Please enter a valid value', + }); + + $.fn.bootstrapValidator.validators.callback = { + html5Attributes: { + message: 'message', + callback: 'callback', + }, + + /** + * Return result from the callback method + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - callback: The callback method that passes 2 parameters: + * callback: function(fieldValue, validator, $field) { + * // fieldValue is the value of field + * // validator is instance of BootstrapValidator + * // $field is the field element + * } + * - message: The invalid message + * @returns {Boolean|Deferred} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + + if (options.callback) { + var dfd = new $.Deferred(), + response = $.fn.bootstrapValidator.helpers.call(options.callback, [value, validator, $field]); + dfd.resolve( + $field, + 'callback', + 'boolean' === typeof response ? response : response.valid, + 'object' === typeof response && response.message ? response.message : null + ); + return dfd; + } + + return true; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.choice = $.extend($.fn.bootstrapValidator.i18n.choice || {}, { + default: 'Please enter a valid value', + less: 'Please choose %s options at minimum', + more: 'Please choose %s options at maximum', + between: 'Please choose %s - %s options', + }); + + $.fn.bootstrapValidator.validators.choice = { + html5Attributes: { + message: 'message', + min: 'min', + max: 'max', + }, + + /** + * Check if the number of checked boxes are less or more than a given number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consists of following keys: + * - min + * - max + * + * At least one of two keys is required + * The min, max keys define the number which the field value compares to. min, max can be + * - A number + * - Name of field which its value defines the number + * - Name of callback function that returns the number + * - A callback function that returns the number + * + * - message: The invalid message + * @returns {Object} + */ + validate: function(validator, $field, options) { + var numChoices = $field.is('select') + ? validator + .getFieldElements($field.attr('data-bv-field')) + .find('option') + .filter(':selected').length + : validator.getFieldElements($field.attr('data-bv-field')).filter(':checked').length, + min = options.min ? ($.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min)) : null, + max = options.max ? ($.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max)) : null, + isValid = true, + message = options.message || $.fn.bootstrapValidator.i18n.choice['default']; + + if ((min && numChoices < parseInt(min, 10)) || (max && numChoices > parseInt(max, 10))) { + isValid = false; + } + + switch (true) { + case !!min && !!max: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.between, [parseInt(min, 10), parseInt(max, 10)]); + break; + + case !!min: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.less, parseInt(min, 10)); + break; + + case !!max: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.choice.more, parseInt(max, 10)); + break; + + default: + break; + } + + return { valid: isValid, message: message }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.creditCard = $.extend($.fn.bootstrapValidator.i18n.creditCard || {}, { + default: 'Please enter a valid credit card number', + }); + + $.fn.bootstrapValidator.validators.creditCard = { + /** + * Return true if the input value is valid credit card number + * Based on https://gist.github.com/DiegoSalazar/4075533 + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} [options] Can consist of the following key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Accept only digits, dashes or spaces + if (/[^0-9-\s]+/.test(value)) { + return false; + } + value = value.replace(/\D/g, ''); + + if (!$.fn.bootstrapValidator.helpers.luhn(value)) { + return false; + } + + // Validate the card number based on prefix (IIN ranges) and length + var cards = { + AMERICAN_EXPRESS: { + length: [15], + prefix: ['34', '37'], + }, + DINERS_CLUB: { + length: [14], + prefix: ['300', '301', '302', '303', '304', '305', '36'], + }, + DINERS_CLUB_US: { + length: [16], + prefix: ['54', '55'], + }, + DISCOVER: { + length: [16], + prefix: [ + '6011', + '622126', + '622127', + '622128', + '622129', + '62213', + '62214', + '62215', + '62216', + '62217', + '62218', + '62219', + '6222', + '6223', + '6224', + '6225', + '6226', + '6227', + '6228', + '62290', + '62291', + '622920', + '622921', + '622922', + '622923', + '622924', + '622925', + '644', + '645', + '646', + '647', + '648', + '649', + '65', + ], + }, + JCB: { + length: [16], + prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358'], + }, + LASER: { + length: [16, 17, 18, 19], + prefix: ['6304', '6706', '6771', '6709'], + }, + MAESTRO: { + length: [12, 13, 14, 15, 16, 17, 18, 19], + prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766'], + }, + MASTERCARD: { + length: [16], + prefix: ['51', '52', '53', '54', '55'], + }, + SOLO: { + length: [16, 18, 19], + prefix: ['6334', '6767'], + }, + UNIONPAY: { + length: [16, 17, 18, 19], + prefix: [ + '622126', + '622127', + '622128', + '622129', + '62213', + '62214', + '62215', + '62216', + '62217', + '62218', + '62219', + '6222', + '6223', + '6224', + '6225', + '6226', + '6227', + '6228', + '62290', + '62291', + '622920', + '622921', + '622922', + '622923', + '622924', + '622925', + ], + }, + VISA: { + length: [16], + prefix: ['4'], + }, + }; + + var type, i; + for (type in cards) { + for (i in cards[type].prefix) { + if ( + value.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i] && // Check the prefix + $.inArray(value.length, cards[type].length) !== -1 + ) { + // and length + return true; + } + } + } + + return false; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.cusip = $.extend($.fn.bootstrapValidator.i18n.cusip || {}, { + default: 'Please enter a valid CUSIP number', + }); + + $.fn.bootstrapValidator.validators.cusip = { + /** + * Validate a CUSIP + * Examples: + * - Valid: 037833100, 931142103, 14149YAR8, 126650BG6 + * - Invalid: 31430F200, 022615AC2 + * + * @see http://en.wikipedia.org/wiki/CUSIP + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} [options] Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + value = value.toUpperCase(); + if (!/^[0-9A-Z]{9}$/.test(value)) { + return false; + } + + var converted = $.map(value.split(''), function(item) { + var code = item.charCodeAt(0); + return code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0) + ? // Replace A, B, C, ..., Z with 10, 11, ..., 35 + code - 'A'.charCodeAt(0) + 10 + : item; + }), + length = converted.length, + sum = 0; + for (var i = 0; i < length - 1; i++) { + var num = parseInt(converted[i], 10); + if (i % 2 !== 0) { + num *= 2; + } + if (num > 9) { + num -= 9; + } + sum += num; + } + + sum = (10 - (sum % 10)) % 10; + return sum === converted[length - 1]; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.cvv = $.extend($.fn.bootstrapValidator.i18n.cvv || {}, { + default: 'Please enter a valid CVV number', + }); + + $.fn.bootstrapValidator.validators.cvv = { + html5Attributes: { + message: 'message', + ccfield: 'creditCardField', + }, + + /** + * Return true if the input value is a valid CVV number. + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - creditCardField: The credit card number field. It can be null + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + if (!/^[0-9]{3,4}$/.test(value)) { + return false; + } + + if (!options.creditCardField) { + return true; + } + + // Get the credit card number + var creditCard = validator.getFieldElements(options.creditCardField).val(); + if (creditCard === '') { + return true; + } + + creditCard = creditCard.replace(/\D/g, ''); + + // Supported credit card types + var cards = { + AMERICAN_EXPRESS: { + length: [15], + prefix: ['34', '37'], + }, + DINERS_CLUB: { + length: [14], + prefix: ['300', '301', '302', '303', '304', '305', '36'], + }, + DINERS_CLUB_US: { + length: [16], + prefix: ['54', '55'], + }, + DISCOVER: { + length: [16], + prefix: [ + '6011', + '622126', + '622127', + '622128', + '622129', + '62213', + '62214', + '62215', + '62216', + '62217', + '62218', + '62219', + '6222', + '6223', + '6224', + '6225', + '6226', + '6227', + '6228', + '62290', + '62291', + '622920', + '622921', + '622922', + '622923', + '622924', + '622925', + '644', + '645', + '646', + '647', + '648', + '649', + '65', + ], + }, + JCB: { + length: [16], + prefix: ['3528', '3529', '353', '354', '355', '356', '357', '358'], + }, + LASER: { + length: [16, 17, 18, 19], + prefix: ['6304', '6706', '6771', '6709'], + }, + MAESTRO: { + length: [12, 13, 14, 15, 16, 17, 18, 19], + prefix: ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763', '6764', '6765', '6766'], + }, + MASTERCARD: { + length: [16], + prefix: ['51', '52', '53', '54', '55'], + }, + SOLO: { + length: [16, 18, 19], + prefix: ['6334', '6767'], + }, + UNIONPAY: { + length: [16, 17, 18, 19], + prefix: [ + '622126', + '622127', + '622128', + '622129', + '62213', + '62214', + '62215', + '62216', + '62217', + '62218', + '62219', + '6222', + '6223', + '6224', + '6225', + '6226', + '6227', + '6228', + '62290', + '62291', + '622920', + '622921', + '622922', + '622923', + '622924', + '622925', + ], + }, + VISA: { + length: [16], + prefix: ['4'], + }, + }; + var type, + i, + creditCardType = null; + for (type in cards) { + for (i in cards[type].prefix) { + if ( + creditCard.substr(0, cards[type].prefix[i].length) === cards[type].prefix[i] && // Check the prefix + $.inArray(creditCard.length, cards[type].length) !== -1 + ) { + // and length + creditCardType = type; + break; + } + } + } + + return creditCardType === null ? false : 'AMERICAN_EXPRESS' === creditCardType ? value.length === 4 : value.length === 3; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.date = $.extend($.fn.bootstrapValidator.i18n.date || {}, { + default: 'Please enter a valid date', + }); + + $.fn.bootstrapValidator.validators.date = { + html5Attributes: { + message: 'message', + format: 'format', + separator: 'separator', + }, + + /** + * Return true if the input value is valid date + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * - separator: Use to separate the date, month, and year. + * By default, it is / + * - format: The date format. Default is MM/DD/YYYY + * The format can be: + * + * i) date: Consist of DD, MM, YYYY parts which are separated by the separator option + * ii) date and time: + * The time can consist of h, m, s parts which are separated by : + * ii) date, time and A (indicating AM or PM) + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + options.format = options.format || 'MM/DD/YYYY'; + + var formats = options.format.split(' '), + dateFormat = formats[0], + timeFormat = formats.length > 1 ? formats[1] : null, + amOrPm = formats.length > 2 ? formats[2] : null, + sections = value.split(' '), + date = sections[0], + time = sections.length > 1 ? sections[1] : null; + + if (formats.length !== sections.length) { + return false; + } + + // Determine the separator + var separator = options.separator; + if (!separator) { + separator = date.indexOf('/') !== -1 ? '/' : date.indexOf('-') !== -1 ? '-' : null; + } + if (separator === null || date.indexOf(separator) === -1) { + return false; + } + + // Determine the date + date = date.split(separator); + dateFormat = dateFormat.split(separator); + if (date.length !== dateFormat.length) { + return false; + } + + var year = date[$.inArray('YYYY', dateFormat)], + month = date[$.inArray('MM', dateFormat)], + day = date[$.inArray('DD', dateFormat)]; + + if (!year || !month || !day) { + return false; + } + + // Determine the time + var minutes = null, + hours = null, + seconds = null; + if (timeFormat) { + timeFormat = timeFormat.split(':'); + time = time.split(':'); + + if (timeFormat.length !== time.length) { + return false; + } + + hours = time.length > 0 ? time[0] : null; + minutes = time.length > 1 ? time[1] : null; + seconds = time.length > 2 ? time[2] : null; + + // Validate seconds + if (seconds) { + seconds = parseInt(seconds, 10); + if (isNaN(seconds) || seconds < 0 || seconds > 60) { + return false; + } + } + + // Validate hours + if (hours) { + hours = parseInt(hours, 10); + if (isNaN(hours) || hours < 0 || hours >= 24 || (amOrPm && hours > 12)) { + return false; + } + } + + // Validate minutes + if (minutes) { + minutes = parseInt(minutes, 10); + if (isNaN(minutes) || minutes < 0 || minutes > 59) { + return false; + } + } + } + + // Validate day, month, and year + return $.fn.bootstrapValidator.helpers.date(year, month, day); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.different = $.extend($.fn.bootstrapValidator.i18n.different || {}, { + default: 'Please enter a different value', + }); + + $.fn.bootstrapValidator.validators.different = { + html5Attributes: { + message: 'message', + field: 'field', + }, + + /** + * Return true if the input value is different with given field's value + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consists of the following key: + * - field: The name of field that will be used to compare with current one + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var compareWith = validator.getFieldElements(options.field); + if (compareWith === null) { + return true; + } + + if (value !== compareWith.val()) { + validator.updateStatus(options.field, validator.STATUS_VALID, 'different'); + return true; + } else { + return false; + } + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.digits = $.extend($.fn.bootstrapValidator.i18n.digits || {}, { + default: 'Please enter only digits', + }); + + $.fn.bootstrapValidator.validators.digits = { + /** + * Return true if the input value contains digits only + * + * @param {BootstrapValidator} validator Validate plugin instance + * @param {jQuery} $field Field element + * @param {Object} [options] + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + return /^\d+$/.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.ean = $.extend($.fn.bootstrapValidator.i18n.ean || {}, { + default: 'Please enter a valid EAN number', + }); + + $.fn.bootstrapValidator.validators.ean = { + /** + * Validate EAN (International Article Number) + * Examples: + * - Valid: 73513537, 9780471117094, 4006381333931 + * - Invalid: 73513536 + * + * @see http://en.wikipedia.org/wiki/European_Article_Number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + if (!/^(\d{8}|\d{12}|\d{13})$/.test(value)) { + return false; + } + + var length = value.length, + sum = 0, + weight = length === 8 ? [3, 1] : [1, 3]; + for (var i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i % 2]; + } + sum = (10 - (sum % 10)) % 10; + return sum + '' === value.charAt(length - 1); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.emailAddress = $.extend($.fn.bootstrapValidator.i18n.emailAddress || {}, { + default: 'Please enter a valid email address', + }); + + $.fn.bootstrapValidator.validators.emailAddress = { + enableByHtml5: function($field) { + return 'email' === $field.attr('type'); + }, + + /** + * Return true if and only if the input value is a valid email address + * + * @param {BootstrapValidator} validator Validate plugin instance + * @param {jQuery} $field Field element + * @param {Object} [options] + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Email address regular expression + // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript + var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return emailRegExp.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.file = $.extend($.fn.bootstrapValidator.i18n.file || {}, { + default: 'Please choose a valid file', + }); + + $.fn.bootstrapValidator.validators.file = { + html5Attributes: { + extension: 'extension', + maxsize: 'maxSize', + message: 'message', + type: 'type', + }, + + /** + * Validate upload file. Use HTML 5 API if the browser supports + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - extension: The allowed extensions, separated by a comma + * - maxSize: The maximum size in bytes + * - message: The invalid message + * - type: The allowed MIME type, separated by a comma + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var ext, + extensions = options.extension ? options.extension.toLowerCase().split(',') : null, + types = options.type ? options.type.toLowerCase().split(',') : null, + html5 = window.File && window.FileList && window.FileReader; + + if (html5) { + // Get FileList instance + var files = $field.get(0).files, + total = files.length; + for (var i = 0; i < total; i++) { + // Check file size + if (options.maxSize && files[i].size > parseInt(options.maxSize, 10)) { + return false; + } + + // Check file extension + ext = files[i].name.substr(files[i].name.lastIndexOf('.') + 1); + if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) { + return false; + } + + // Check file type + if (types && $.inArray(files[i].type.toLowerCase(), types) === -1) { + return false; + } + } + } else { + // Check file extension + ext = value.substr(value.lastIndexOf('.') + 1); + if (extensions && $.inArray(ext.toLowerCase(), extensions) === -1) { + return false; + } + } + + return true; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.greaterThan = $.extend($.fn.bootstrapValidator.i18n.greaterThan || {}, { + default: 'Please enter a value greater than or equal to %s', + notInclusive: 'Please enter a value greater than %s', + }); + + $.fn.bootstrapValidator.validators.greaterThan = { + html5Attributes: { + message: 'message', + value: 'value', + inclusive: 'inclusive', + }, + + enableByHtml5: function($field) { + var min = $field.attr('min'); + if (min) { + return { + value: min, + }; + } + + return false; + }, + + /** + * Return true if the input value is greater than or equals to given number + * + * @param {BootstrapValidator} validator Validate plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - value: Define the number to compare with. It can be + * - A number + * - Name of field which its value defines the number + * - Name of callback function that returns the number + * - A callback function that returns the number + * + * - inclusive [optional]: Can be true or false. Default is true + * - message: The invalid message + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value); + + value = parseFloat(value); + return options.inclusive === true || options.inclusive === undefined + ? { + valid: value >= compareTo, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan['default'], compareTo), + } + : { + valid: value > compareTo, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.greaterThan.notInclusive, compareTo), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.grid = $.extend($.fn.bootstrapValidator.i18n.grid || {}, { + default: 'Please enter a valid GRId number', + }); + + $.fn.bootstrapValidator.validators.grid = { + /** + * Validate GRId (Global Release Identifier) + * Examples: + * - Valid: A12425GABC1234002M, A1-2425G-ABC1234002-M, A1 2425G ABC1234002 M, Grid:A1-2425G-ABC1234002-M + * - Invalid: A1-2425G-ABC1234002-Q + * + * @see http://en.wikipedia.org/wiki/Global_Release_Identifier + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + value = value.toUpperCase(); + if (!/^[GRID:]*([0-9A-Z]{2})[-\s]*([0-9A-Z]{5})[-\s]*([0-9A-Z]{10})[-\s]*([0-9A-Z]{1})$/g.test(value)) { + return false; + } + value = value.replace(/\s/g, '').replace(/-/g, ''); + if ('GRID:' === value.substr(0, 5)) { + value = value.substr(5); + } + return $.fn.bootstrapValidator.helpers.mod37And36(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.hex = $.extend($.fn.bootstrapValidator.i18n.hex || {}, { + default: 'Please enter a valid hexadecimal number', + }); + + $.fn.bootstrapValidator.validators.hex = { + /** + * Return true if and only if the input value is a valid hexadecimal number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + return /^[0-9a-fA-F]+$/.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.hexColor = $.extend($.fn.bootstrapValidator.i18n.hexColor || {}, { + default: 'Please enter a valid hex color', + }); + + $.fn.bootstrapValidator.validators.hexColor = { + enableByHtml5: function($field) { + return 'color' === $field.attr('type'); + }, + + /** + * Return true if the input value is a valid hex color + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.iban = $.extend($.fn.bootstrapValidator.i18n.iban || {}, { + default: 'Please enter a valid IBAN number', + countryNotSupported: 'The country code %s is not supported', + country: 'Please enter a valid IBAN number in %s', + countries: { + AD: 'Andorra', + AE: 'United Arab Emirates', + AL: 'Albania', + AO: 'Angola', + AT: 'Austria', + AZ: 'Azerbaijan', + BA: 'Bosnia and Herzegovina', + BE: 'Belgium', + BF: 'Burkina Faso', + BG: 'Bulgaria', + BH: 'Bahrain', + BI: 'Burundi', + BJ: 'Benin', + BR: 'Brazil', + CH: 'Switzerland', + CI: 'Ivory Coast', + CM: 'Cameroon', + CR: 'Costa Rica', + CV: 'Cape Verde', + CY: 'Cyprus', + CZ: 'Czech Republic', + DE: 'Germany', + DK: 'Denmark', + DO: 'Dominican Republic', + DZ: 'Algeria', + EE: 'Estonia', + ES: 'Spain', + FI: 'Finland', + FO: 'Faroe Islands', + FR: 'France', + GB: 'United Kingdom', + GE: 'Georgia', + GI: 'Gibraltar', + GL: 'Greenland', + GR: 'Greece', + GT: 'Guatemala', + HR: 'Croatia', + HU: 'Hungary', + IE: 'Ireland', + IL: 'Israel', + IR: 'Iran', + IS: 'Iceland', + IT: 'Italy', + JO: 'Jordan', + KW: 'Kuwait', + KZ: 'Kazakhstan', + LB: 'Lebanon', + LI: 'Liechtenstein', + LT: 'Lithuania', + LU: 'Luxembourg', + LV: 'Latvia', + MC: 'Monaco', + MD: 'Moldova', + ME: 'Montenegro', + MG: 'Madagascar', + MK: 'Macedonia', + ML: 'Mali', + MR: 'Mauritania', + MT: 'Malta', + MU: 'Mauritius', + MZ: 'Mozambique', + NL: 'Netherlands', + NO: 'Norway', + PK: 'Pakistan', + PL: 'Poland', + PS: 'Palestinian', + PT: 'Portugal', + QA: 'Qatar', + RO: 'Romania', + RS: 'Serbia', + SA: 'Saudi Arabia', + SE: 'Sweden', + SI: 'Slovenia', + SK: 'Slovakia', + SM: 'San Marino', + SN: 'Senegal', + TN: 'Tunisia', + TR: 'Turkey', + VG: 'Virgin Islands, British', + }, + }); + + $.fn.bootstrapValidator.validators.iban = { + html5Attributes: { + message: 'message', + country: 'country', + }, + + // http://www.swift.com/dsp/resources/documents/IBAN_Registry.pdf + // http://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country + REGEX: { + AD: 'AD[0-9]{2}[0-9]{4}[0-9]{4}[A-Z0-9]{12}', // Andorra + AE: 'AE[0-9]{2}[0-9]{3}[0-9]{16}', // United Arab Emirates + AL: 'AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}', // Albania + AO: 'AO[0-9]{2}[0-9]{21}', // Angola + AT: 'AT[0-9]{2}[0-9]{5}[0-9]{11}', // Austria + AZ: 'AZ[0-9]{2}[A-Z]{4}[A-Z0-9]{20}', // Azerbaijan + BA: 'BA[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{8}[0-9]{2}', // Bosnia and Herzegovina + BE: 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}', // Belgium + BF: 'BF[0-9]{2}[0-9]{23}', // Burkina Faso + BG: 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}', // Bulgaria + BH: 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}', // Bahrain + BI: 'BI[0-9]{2}[0-9]{12}', // Burundi + BJ: 'BJ[0-9]{2}[A-Z]{1}[0-9]{23}', // Benin + BR: 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]', // Brazil + CH: 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}', // Switzerland + CI: 'CI[0-9]{2}[A-Z]{1}[0-9]{23}', // Ivory Coast + CM: 'CM[0-9]{2}[0-9]{23}', // Cameroon + CR: 'CR[0-9]{2}[0-9]{3}[0-9]{14}', // Costa Rica + CV: 'CV[0-9]{2}[0-9]{21}', // Cape Verde + CY: 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}', // Cyprus + CZ: 'CZ[0-9]{2}[0-9]{20}', // Czech Republic + DE: 'DE[0-9]{2}[0-9]{8}[0-9]{10}', // Germany + DK: 'DK[0-9]{2}[0-9]{14}', // Denmark + DO: 'DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}', // Dominican Republic + DZ: 'DZ[0-9]{2}[0-9]{20}', // Algeria + EE: 'EE[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{11}[0-9]{1}', // Estonia + ES: 'ES[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{1}[0-9]{1}[0-9]{10}', // Spain + FI: 'FI[0-9]{2}[0-9]{6}[0-9]{7}[0-9]{1}', // Finland + FO: 'FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}', // Faroe Islands + FR: 'FR[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}', // France + GB: 'GB[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}', // United Kingdom + GE: 'GE[0-9]{2}[A-Z]{2}[0-9]{16}', // Georgia + GI: 'GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}', // Gibraltar + GL: 'GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}', // Greenland + GR: 'GR[0-9]{2}[0-9]{3}[0-9]{4}[A-Z0-9]{16}', // Greece + GT: 'GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}', // Guatemala + HR: 'HR[0-9]{2}[0-9]{7}[0-9]{10}', // Croatia + HU: 'HU[0-9]{2}[0-9]{3}[0-9]{4}[0-9]{1}[0-9]{15}[0-9]{1}', // Hungary + IE: 'IE[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}', // Ireland + IL: 'IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}', // Israel + IR: 'IR[0-9]{2}[0-9]{22}', // Iran + IS: 'IS[0-9]{2}[0-9]{4}[0-9]{2}[0-9]{6}[0-9]{10}', // Iceland + IT: 'IT[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}', // Italy + JO: 'JO[0-9]{2}[A-Z]{4}[0-9]{4}[0]{8}[A-Z0-9]{10}', // Jordan + KW: 'KW[0-9]{2}[A-Z]{4}[0-9]{22}', // Kuwait + KZ: 'KZ[0-9]{2}[0-9]{3}[A-Z0-9]{13}', // Kazakhstan + LB: 'LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}', // Lebanon + LI: 'LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}', // Liechtenstein + LT: 'LT[0-9]{2}[0-9]{5}[0-9]{11}', // Lithuania + LU: 'LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}', // Luxembourg + LV: 'LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}', // Latvia + MC: 'MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}', // Monaco + MD: 'MD[0-9]{2}[A-Z0-9]{20}', // Moldova + ME: 'ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}', // Montenegro + MG: 'MG[0-9]{2}[0-9]{23}', // Madagascar + MK: 'MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}', // Macedonia + ML: 'ML[0-9]{2}[A-Z]{1}[0-9]{23}', // Mali + MR: 'MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}', // Mauritania + MT: 'MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}', // Malta + MU: 'MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{3}', // Mauritius + MZ: 'MZ[0-9]{2}[0-9]{21}', // Mozambique + NL: 'NL[0-9]{2}[A-Z]{4}[0-9]{10}', // Netherlands + NO: 'NO[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{1}', // Norway + PK: 'PK[0-9]{2}[A-Z]{4}[A-Z0-9]{16}', // Pakistan + PL: 'PL[0-9]{2}[0-9]{8}[0-9]{16}', // Poland + PS: 'PS[0-9]{2}[A-Z]{4}[A-Z0-9]{21}', // Palestinian + PT: 'PT[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{11}[0-9]{2}', // Portugal + QA: 'QA[0-9]{2}[A-Z]{4}[A-Z0-9]{21}', // Qatar + RO: 'RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}', // Romania + RS: 'RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}', // Serbia + SA: 'SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}', // Saudi Arabia + SE: 'SE[0-9]{2}[0-9]{3}[0-9]{16}[0-9]{1}', // Sweden + SI: 'SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}', // Slovenia + SK: 'SK[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{10}', // Slovakia + SM: 'SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}', // San Marino + SN: 'SN[0-9]{2}[A-Z]{1}[0-9]{23}', // Senegal + TN: 'TN59[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}', // Tunisia + TR: 'TR[0-9]{2}[0-9]{5}[A-Z0-9]{1}[A-Z0-9]{16}', // Turkey + VG: 'VG[0-9]{2}[A-Z]{4}[0-9]{16}', // Virgin Islands, British + }, + + /** + * Validate an International Bank Account Number (IBAN) + * To test it, take the sample IBAN from + * http://www.nordea.com/Our+services/International+products+and+services/Cash+Management/IBAN+countries/908462.html + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * - country: The ISO 3166-1 country code. It can be + * - A country code + * - Name of field which its value defines the country code + * - Name of callback function that returns the country code + * - A callback function that returns the country code + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + value = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase(); + var country = options.country; + if (!country) { + country = value.substr(0, 2); + } else if (typeof country !== 'string' || !this.REGEX[country]) { + // Determine the country code + country = validator.getDynamicOption($field, country); + } + + if (!this.REGEX[country]) { + return { + valid: false, + message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.iban.countryNotSupported, country), + }; + } + + if (!new RegExp('^' + this.REGEX[country] + '$').test(value)) { + return { + valid: false, + message: $.fn.bootstrapValidator.helpers.format( + options.message || $.fn.bootstrapValidator.i18n.iban.country, + $.fn.bootstrapValidator.i18n.iban.countries[country] + ), + }; + } + + value = value.substr(4) + value.substr(0, 4); + value = $.map(value.split(''), function(n) { + var code = n.charCodeAt(0); + return code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0) + ? // Replace A, B, C, ..., Z with 10, 11, ..., 35 + code - 'A'.charCodeAt(0) + 10 + : n; + }); + value = value.join(''); + + var temp = parseInt(value.substr(0, 1), 10), + length = value.length; + for (var i = 1; i < length; ++i) { + temp = (temp * 10 + parseInt(value.substr(i, 1), 10)) % 97; + } + + return { + valid: temp === 1, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.iban.country, $.fn.bootstrapValidator.i18n.iban.countries[country]), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.id = $.extend($.fn.bootstrapValidator.i18n.id || {}, { + default: 'Please enter a valid identification number', + countryNotSupported: 'The country code %s is not supported', + country: 'Please enter a valid %s identification number', + countries: { + BA: 'Bosnia and Herzegovina', + BG: 'Bulgarian', + BR: 'Brazilian', + CH: 'Swiss', + CL: 'Chilean', + CZ: 'Czech', + DK: 'Danish', + EE: 'Estonian', + ES: 'Spanish', + FI: 'Finnish', + HR: 'Croatian', + IE: 'Irish', + IS: 'Iceland', + LT: 'Lithuanian', + LV: 'Latvian', + ME: 'Montenegro', + MK: 'Macedonian', + NL: 'Dutch', + RO: 'Romanian', + RS: 'Serbian', + SE: 'Swedish', + SI: 'Slovenian', + SK: 'Slovak', + SM: 'San Marino', + ZA: 'South African', + }, + }); + + $.fn.bootstrapValidator.validators.id = { + html5Attributes: { + message: 'message', + country: 'country', + }, + + // Supported country codes + COUNTRY_CODES: ['BA', 'BG', 'BR', 'CH', 'CL', 'CZ', 'DK', 'EE', 'ES', 'FI', 'HR', 'IE', 'IS', 'LT', 'LV', 'ME', 'MK', 'NL', 'RO', 'RS', 'SE', 'SI', 'SK', 'SM', 'ZA'], + + /** + * Validate identification number in different countries + * + * @see http://en.wikipedia.org/wiki/National_identification_number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - country: The ISO 3166-1 country code. It can be + * - One of country code defined in COUNTRY_CODES + * - Name of field which its value defines the country code + * - Name of callback function that returns the country code + * - A callback function that returns the country code + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var country = options.country; + if (!country) { + country = value.substr(0, 2); + } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) { + // Determine the country code + country = validator.getDynamicOption($field, country); + } + + if ($.inArray(country, this.COUNTRY_CODES) === -1) { + return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.id.countryNotSupported, country) }; + } + + var method = ['_', country.toLowerCase()].join(''); + return this[method](value) + ? true + : { + valid: false, + message: $.fn.bootstrapValidator.helpers.format( + options.message || $.fn.bootstrapValidator.i18n.id.country, + $.fn.bootstrapValidator.i18n.id.countries[country.toUpperCase()] + ), + }; + }, + + /** + * Validate Unique Master Citizen Number which uses in + * - Bosnia and Herzegovina (country code: BA) + * - Macedonia (MK) + * - Montenegro (ME) + * - Serbia (RS) + * - Slovenia (SI) + * + * @see http://en.wikipedia.org/wiki/Unique_Master_Citizen_Number + * @param {String} value The ID + * @param {String} countryCode The ISO country code, can be BA, MK, ME, RS, SI + * @returns {Boolean} + */ + _validateJMBG: function(value, countryCode) { + if (!/^\d{13}$/.test(value)) { + return false; + } + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 3), 10), + rr = parseInt(value.substr(7, 2), 10), + k = parseInt(value.substr(12, 1), 10); + + // Validate date of birth + // FIXME: Validate the year of birth + if (day > 31 || month > 12) { + return false; + } + + // Validate checksum + var sum = 0; + for (var i = 0; i < 6; i++) { + sum += (7 - i) * (parseInt(value.charAt(i), 10) + parseInt(value.charAt(i + 6), 10)); + } + sum = 11 - (sum % 11); + if (sum === 10 || sum === 11) { + sum = 0; + } + if (sum !== k) { + return false; + } + + // Validate political region + // rr is the political region of birth, which can be in ranges: + // 10-19: Bosnia and Herzegovina + // 20-29: Montenegro + // 30-39: Croatia (not used anymore) + // 41-49: Macedonia + // 50-59: Slovenia (only 50 is used) + // 70-79: Central Serbia + // 80-89: Serbian province of Vojvodina + // 90-99: Kosovo + switch (countryCode.toUpperCase()) { + case 'BA': + return 10 <= rr && rr <= 19; + case 'MK': + return 41 <= rr && rr <= 49; + case 'ME': + return 20 <= rr && rr <= 29; + case 'RS': + return 70 <= rr && rr <= 99; + case 'SI': + return 50 <= rr && rr <= 59; + default: + return true; + } + }, + + _ba: function(value) { + return this._validateJMBG(value, 'BA'); + }, + _mk: function(value) { + return this._validateJMBG(value, 'MK'); + }, + _me: function(value) { + return this._validateJMBG(value, 'ME'); + }, + _rs: function(value) { + return this._validateJMBG(value, 'RS'); + }, + + /** + * Examples: 0101006500006 + */ + _si: function(value) { + return this._validateJMBG(value, 'SI'); + }, + + /** + * Validate Bulgarian national identification number (EGN) + * Examples: + * - Valid: 7523169263, 8032056031, 803205 603 1, 8001010008, 7501020018, 7552010005, 7542011030 + * - Invalid: 8019010008 + * + * @see http://en.wikipedia.org/wiki/Uniform_civil_number + * @param {String} value The ID + * @returns {Boolean} + */ + _bg: function(value) { + if (!/^\d{10}$/.test(value) && !/^\d{6}\s\d{3}\s\d{1}$/.test(value)) { + return false; + } + value = value.replace(/\s/g, ''); + // Check the birth date + var year = parseInt(value.substr(0, 2), 10) + 1900, + month = parseInt(value.substr(2, 2), 10), + day = parseInt(value.substr(4, 2), 10); + if (month > 40) { + year += 100; + month -= 40; + } else if (month > 20) { + year -= 100; + month -= 20; + } + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + var sum = 0, + weight = [2, 4, 8, 5, 10, 9, 7, 3, 6]; + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = (sum % 11) % 10; + return sum + '' === value.substr(9, 1); + }, + + /** + * Validate Brazilian national identification number (CPF) + * Examples: + * - Valid: 39053344705, 390.533.447-05, 111.444.777-35 + * - Invalid: 231.002.999-00 + * + * @see http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas + * @param {String} value The ID + * @returns {Boolean} + */ + _br: function(value) { + if (/^1{11}|2{11}|3{11}|4{11}|5{11}|6{11}|7{11}|8{11}|9{11}|0{11}$/.test(value)) { + return false; + } + if (!/^\d{11}$/.test(value) && !/^\d{3}\.\d{3}\.\d{3}-\d{2}$/.test(value)) { + return false; + } + value = value.replace(/\./g, '').replace(/-/g, ''); + + var d1 = 0; + for (var i = 0; i < 9; i++) { + d1 += (10 - i) * parseInt(value.charAt(i), 10); + } + d1 = 11 - (d1 % 11); + if (d1 === 10 || d1 === 11) { + d1 = 0; + } + if (d1 + '' !== value.charAt(9)) { + return false; + } + + var d2 = 0; + for (i = 0; i < 10; i++) { + d2 += (11 - i) * parseInt(value.charAt(i), 10); + } + d2 = 11 - (d2 % 11); + if (d2 === 10 || d2 === 11) { + d2 = 0; + } + + return d2 + '' === value.charAt(10); + }, + + /** + * Validate Swiss Social Security Number (AHV-Nr/No AVS) + * Examples: + * - Valid: 756.1234.5678.95, 7561234567895 + * + * @see http://en.wikipedia.org/wiki/National_identification_number#Switzerland + * @see http://www.bsv.admin.ch/themen/ahv/00011/02185/index.html?lang=de + * @param {String} value The ID + * @returns {Boolean} + */ + _ch: function(value) { + if (!/^756[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{4}[\.]{0,1}[0-9]{2}$/.test(value)) { + return false; + } + value = value.replace(/\D/g, '').substr(3); + var length = value.length, + sum = 0, + weight = length === 8 ? [3, 1] : [1, 3]; + for (var i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i % 2]; + } + sum = 10 - (sum % 10); + return sum + '' === value.charAt(length - 1); + }, + + /** + * Validate Chilean national identification number (RUN/RUT) + * Examples: + * - Valid: 76086428-5, 22060449-7, 12531909-2 + * + * @see http://en.wikipedia.org/wiki/National_identification_number#Chile + * @see https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html for samples + * @param {String} value The ID + * @returns {Boolean} + */ + _cl: function(value) { + if (!/^\d{7,8}[-]{0,1}[0-9K]$/i.test(value)) { + return false; + } + value = value.replace(/\-/g, ''); + while (value.length < 9) { + value = '0' + value; + } + var sum = 0, + weight = [3, 2, 7, 6, 5, 4, 3, 2]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = 11 - (sum % 11); + if (sum === 11) { + sum = 0; + } else if (sum === 10) { + sum = 'K'; + } + return sum + '' === value.charAt(8).toUpperCase(); + }, + + /** + * Validate Czech national identification number (RC) + * Examples: + * - Valid: 7103192745, 991231123 + * - Invalid: 1103492745, 590312123 + * + * @param {String} value The ID + * @returns {Boolean} + */ + _cz: function(value) { + if (!/^\d{9,10}$/.test(value)) { + return false; + } + var year = 1900 + parseInt(value.substr(0, 2), 10), + month = (parseInt(value.substr(2, 2), 10) % 50) % 20, + day = parseInt(value.substr(4, 2), 10); + if (value.length === 9) { + if (year >= 1980) { + year -= 100; + } + if (year > 1953) { + return false; + } + } else if (year < 1954) { + year += 100; + } + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + // Check that the birth date is not in the future + if (value.length === 10) { + var check = parseInt(value.substr(0, 9), 10) % 11; + if (year < 1985) { + check = check % 10; + } + return check + '' === value.substr(9, 1); + } + + return true; + }, + + /** + * Validate Danish Personal Identification number (CPR) + * Examples: + * - Valid: 2110625629, 211062-5629 + * - Invalid: 511062-5629 + * + * @see https://en.wikipedia.org/wiki/Personal_identification_number_(Denmark) + * @param {String} value The ID + * @returns {Boolean} + */ + _dk: function(value) { + if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) { + return false; + } + value = value.replace(/-/g, ''); + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 2), 10); + + switch (true) { + case '5678'.indexOf(value.charAt(6)) !== -1 && year >= 58: + year += 1800; + break; + case '0123'.indexOf(value.charAt(6)) !== -1: + case '49'.indexOf(value.charAt(6)) !== -1 && year >= 37: + year += 1900; + break; + default: + year += 2000; + break; + } + + return $.fn.bootstrapValidator.helpers.date(year, month, day); + }, + + /** + * Validate Estonian Personal Identification Code (isikukood) + * Examples: + * - Valid: 37605030299 + * + * @see http://et.wikipedia.org/wiki/Isikukood + * @param {String} value The ID + * @returns {Boolean} + */ + _ee: function(value) { + // Use the same format as Lithuanian Personal Code + return this._lt(value); + }, + + /** + * Validate Spanish personal identity code (DNI) + * Support i) DNI (for Spanish citizens) and ii) NIE (for foreign people) + * + * Examples: + * - Valid: i) 54362315K, 54362315-K; ii) X2482300W, X-2482300W, X-2482300-W + * - Invalid: i) 54362315Z; ii) X-2482300A + * + * @see https://en.wikipedia.org/wiki/National_identification_number#Spain + * @param {String} value The ID + * @returns {Boolean} + */ + _es: function(value) { + if ( + !/^[0-9A-Z]{8}[-]{0,1}[0-9A-Z]$/.test(value) && // DNI + !/^[XYZ][-]{0,1}[0-9]{7}[-]{0,1}[0-9A-Z]$/.test(value) + ) { + // NIE + return false; + } + + value = value.replace(/-/g, ''); + var index = 'XYZ'.indexOf(value.charAt(0)); + if (index !== -1) { + // It is NIE number + value = index + value.substr(1) + ''; + } + + var check = parseInt(value.substr(0, 8), 10); + check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23]; + return check === value.substr(8, 1); + }, + + /** + * Validate Finnish Personal Identity Code (HETU) + * Examples: + * - Valid: 311280-888Y, 131052-308T + * - Invalid: 131052-308U, 310252-308Y + * + * @param {String} value The ID + * @returns {Boolean} + */ + _fi: function(value) { + if (!/^[0-9]{6}[-+A][0-9]{3}[0-9ABCDEFHJKLMNPRSTUVWXY]$/.test(value)) { + return false; + } + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 2), 10), + centuries = { + '+': 1800, + '-': 1900, + A: 2000, + }; + year = centuries[value.charAt(6)] + year; + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + var individual = parseInt(value.substr(7, 3), 10); + if (individual < 2) { + return false; + } + var n = value.substr(0, 6) + value.substr(7, 3) + ''; + n = parseInt(n, 10); + return '0123456789ABCDEFHJKLMNPRSTUVWXY'.charAt(n % 31) === value.charAt(10); + }, + + /** + * Validate Croatian personal identification number (OIB) + * Examples: + * - Valid: 33392005961 + * - Invalid: 33392005962 + * + * @param {String} value The ID + * @returns {Boolean} + */ + _hr: function(value) { + if (!/^[0-9]{11}$/.test(value)) { + return false; + } + return $.fn.bootstrapValidator.helpers.mod11And10(value); + }, + + /** + * Validate Irish Personal Public Service Number (PPS) + * Examples: + * - Valid: 6433435F, 6433435FT, 6433435FW, 6433435OA, 6433435IH, 1234567TW, 1234567FA + * - Invalid: 6433435E, 6433435VH + * + * @see https://en.wikipedia.org/wiki/Personal_Public_Service_Number + * @param {String} value The ID + * @returns {Boolean} + */ + _ie: function(value) { + if (!/^\d{7}[A-W][AHWTX]?$/.test(value)) { + return false; + } + + var getCheckDigit = function(value) { + while (value.length < 7) { + value = '0' + value; + } + var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV', + sum = 0; + for (var i = 0; i < 7; i++) { + sum += parseInt(value.charAt(i), 10) * (8 - i); + } + sum += 9 * alphabet.indexOf(value.substr(7)); + return alphabet[sum % 23]; + }; + + // 2013 format + if (value.length === 9 && ('A' === value.charAt(8) || 'H' === value.charAt(8))) { + return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + ''); + } + // The old format + else { + return value.charAt(7) === getCheckDigit(value.substr(0, 7)); + } + }, + + /** + * Validate Iceland national identification number (Kennitala) + * Examples: + * - Valid: 120174-3399, 1201743399, 0902862349 + * + * @see http://en.wikipedia.org/wiki/Kennitala + * @param {String} value The ID + * @returns {Boolean} + */ + _is: function(value) { + if (!/^[0-9]{6}[-]{0,1}[0-9]{4}$/.test(value)) { + return false; + } + value = value.replace(/-/g, ''); + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 2), 10), + century = parseInt(value.charAt(9), 10); + + year = century === 9 ? 1900 + year : (20 + century) * 100 + year; + if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) { + return false; + } + // Validate the check digit + var sum = 0, + weight = [3, 2, 7, 6, 5, 4, 3, 2]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = 11 - (sum % 11); + return sum + '' === value.charAt(8); + }, + + /** + * Validate Lithuanian Personal Code (Asmens kodas) + * Examples: + * - Valid: 38703181745 + * - Invalid: 38703181746, 78703181745, 38703421745 + * + * @see http://en.wikipedia.org/wiki/National_identification_number#Lithuania + * @see http://www.adomas.org/midi2007/pcode.html + * @param {String} value The ID + * @returns {Boolean} + */ + _lt: function(value) { + if (!/^[0-9]{11}$/.test(value)) { + return false; + } + var gender = parseInt(value.charAt(0), 10), + year = parseInt(value.substr(1, 2), 10), + month = parseInt(value.substr(3, 2), 10), + day = parseInt(value.substr(5, 2), 10), + century = gender % 2 === 0 ? 17 + gender / 2 : 17 + (gender + 1) / 2; + year = century * 100 + year; + if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) { + return false; + } + + // Validate the check digit + var sum = 0, + weight = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]; + for (var i = 0; i < 10; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 11; + if (sum !== 10) { + return sum + '' === value.charAt(10); + } + + // Re-calculate the check digit + sum = 0; + weight = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]; + for (i = 0; i < 10; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 11; + if (sum === 10) { + sum = 0; + } + return sum + '' === value.charAt(10); + }, + + /** + * Validate Latvian Personal Code (Personas kods) + * Examples: + * - Valid: 161175-19997, 16117519997 + * - Invalid: 161375-19997 + * + * @see http://laacz.lv/2006/11/25/pk-parbaudes-algoritms/ + * @param {String} value The ID + * @returns {Boolean} + */ + _lv: function(value) { + if (!/^[0-9]{6}[-]{0,1}[0-9]{5}$/.test(value)) { + return false; + } + value = value.replace(/\D/g, ''); + // Check birth date + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 2), 10); + year = year + 1800 + parseInt(value.charAt(6), 10) * 100; + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day, true)) { + return false; + } + + // Check personal code + var sum = 0, + weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9]; + for (var i = 0; i < 10; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = ((sum + 1) % 11) % 10; + return sum + '' === value.charAt(10); + }, + + /** + * Validate Dutch national identification number (BSN) + * Examples: + * - Valid: 111222333, 941331490, 9413.31.490 + * - Invalid: 111252333 + * + * @see https://nl.wikipedia.org/wiki/Burgerservicenummer + * @param {String} value The ID + * @returns {Boolean} + */ + _nl: function(value) { + while (value.length < 9) { + value = '0' + value; + } + if (!/^[0-9]{4}[.]{0,1}[0-9]{2}[.]{0,1}[0-9]{3}$/.test(value)) { + return false; + } + value = value.replace(/\./g, ''); + if (parseInt(value, 10) === 0) { + return false; + } + var sum = 0, + length = value.length; + for (var i = 0; i < length - 1; i++) { + sum += (9 - i) * parseInt(value.charAt(i), 10); + } + sum = sum % 11; + if (sum === 10) { + sum = 0; + } + return sum + '' === value.charAt(length - 1); + }, + + /** + * Validate Romanian numerical personal code (CNP) + * Examples: + * - Valid: 1630615123457, 1800101221144 + * - Invalid: 8800101221144, 1632215123457, 1630615123458 + * + * @see http://en.wikipedia.org/wiki/National_identification_number#Romania + * @param {String} value The ID + * @returns {Boolean} + */ + _ro: function(value) { + if (!/^[0-9]{13}$/.test(value)) { + return false; + } + var gender = parseInt(value.charAt(0), 10); + if (gender === 0 || gender === 7 || gender === 8) { + return false; + } + + // Determine the date of birth + var year = parseInt(value.substr(1, 2), 10), + month = parseInt(value.substr(3, 2), 10), + day = parseInt(value.substr(5, 2), 10), + // The year of date is determined base on the gender + centuries = { + '1': 1900, // Male born between 1900 and 1999 + '2': 1900, // Female born between 1900 and 1999 + '3': 1800, // Male born between 1800 and 1899 + '4': 1800, // Female born between 1800 and 1899 + '5': 2000, // Male born after 2000 + '6': 2000, // Female born after 2000 + }; + if (day > 31 && month > 12) { + return false; + } + if (gender !== 9) { + year = centuries[gender + ''] + year; + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + } + + // Validate the check digit + var sum = 0, + weight = [2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9], + length = value.length; + for (var i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 11; + if (sum === 10) { + sum = 1; + } + return sum + '' === value.charAt(length - 1); + }, + + /** + * Validate Swedish personal identity number (personnummer) + * Examples: + * - Valid: 8112289874, 811228-9874, 811228+9874 + * - Invalid: 811228-9873 + * + * @see http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden) + * @param {String} value The ID + * @returns {Boolean} + */ + _se: function(value) { + if (!/^[0-9]{10}$/.test(value) && !/^[0-9]{6}[-|+][0-9]{4}$/.test(value)) { + return false; + } + value = value.replace(/[^0-9]/g, ''); + + var year = parseInt(value.substr(0, 2), 10) + 1900, + month = parseInt(value.substr(2, 2), 10), + day = parseInt(value.substr(4, 2), 10); + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + // Validate the last check digit + return $.fn.bootstrapValidator.helpers.luhn(value); + }, + + /** + * Validate Slovak national identifier number (RC) + * Examples: + * - Valid: 7103192745, 991231123 + * - Invalid: 7103192746, 1103492745 + * + * @param {String} value The ID + * @returns {Boolean} + */ + _sk: function(value) { + // Slovakia uses the same format as Czech Republic + return this._cz(value); + }, + + /** + * Validate San Marino citizen number + * + * @see http://en.wikipedia.org/wiki/National_identification_number#San_Marino + * @param {String} value The ID + * @returns {Boolean} + */ + _sm: function(value) { + return /^\d{5}$/.test(value); + }, + + /** + * Validate South African ID + * Example: + * - Valid: 8001015009087 + * - Invalid: 8001015009287, 8001015009086 + * + * @see http://en.wikipedia.org/wiki/National_identification_number#South_Africa + * @param {String} value The ID + * @returns {Boolean} + */ + _za: function(value) { + if (!/^[0-9]{10}[0|1][8|9][0-9]$/.test(value)) { + return false; + } + var year = parseInt(value.substr(0, 2), 10), + currentYear = new Date().getFullYear() % 100, + month = parseInt(value.substr(2, 2), 10), + day = parseInt(value.substr(4, 2), 10); + year = year >= currentYear ? year + 1900 : year + 2000; + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + // Validate the last check digit + return $.fn.bootstrapValidator.helpers.luhn(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.identical = $.extend($.fn.bootstrapValidator.i18n.identical || {}, { + default: 'Please enter the same value', + }); + + $.fn.bootstrapValidator.validators.identical = { + html5Attributes: { + message: 'message', + field: 'field', + }, + + /** + * Check if input value equals to value of particular one + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consists of the following key: + * - field: The name of field that will be used to compare with current one + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var compareWith = validator.getFieldElements(options.field); + if (compareWith === null) { + return true; + } + + if (value === compareWith.val()) { + validator.updateStatus(options.field, validator.STATUS_VALID, 'identical'); + return true; + } else { + return false; + } + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.imei = $.extend($.fn.bootstrapValidator.i18n.imei || {}, { + default: 'Please enter a valid IMEI number', + }); + + $.fn.bootstrapValidator.validators.imei = { + /** + * Validate IMEI (International Mobile Station Equipment Identity) + * Examples: + * - Valid: 35-209900-176148-1, 35-209900-176148-23, 3568680000414120, 490154203237518 + * - Invalid: 490154203237517 + * + * @see http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + switch (true) { + case /^\d{15}$/.test(value): + case /^\d{2}-\d{6}-\d{6}-\d{1}$/.test(value): + case /^\d{2}\s\d{6}\s\d{6}\s\d{1}$/.test(value): + value = value.replace(/[^0-9]/g, ''); + return $.fn.bootstrapValidator.helpers.luhn(value); + + case /^\d{14}$/.test(value): + case /^\d{16}$/.test(value): + case /^\d{2}-\d{6}-\d{6}(|-\d{2})$/.test(value): + case /^\d{2}\s\d{6}\s\d{6}(|\s\d{2})$/.test(value): + return true; + + default: + return false; + } + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.integer = $.extend($.fn.bootstrapValidator.i18n.integer || {}, { + default: 'Please enter a valid number', + }); + + $.fn.bootstrapValidator.validators.integer = { + enableByHtml5: function($field) { + return 'number' === $field.attr('type') && ($field.attr('step') === undefined || $field.attr('step') % 1 === 0); + }, + + /** + * Return true if the input value is an integer + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + return /^(?:-?(?:0|[1-9][0-9]*))$/.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.ip = $.extend($.fn.bootstrapValidator.i18n.ip || {}, { + default: 'Please enter a valid IP address', + ipv4: 'Please enter a valid IPv4 address', + ipv6: 'Please enter a valid IPv6 address', + }); + + $.fn.bootstrapValidator.validators.ip = { + html5Attributes: { + message: 'message', + ipv4: 'ipv4', + ipv6: 'ipv6', + }, + + /** + * Return true if the input value is a IP address. + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - ipv4: Enable IPv4 validator, default to true + * - ipv6: Enable IPv6 validator, default to true + * - message: The invalid message + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + options = $.extend({}, { ipv4: true, ipv6: true }, options); + + if (options.ipv4) { + return { + valid: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value), + message: options.message || $.fn.bootstrapValidator.i18n.ip.ipv4, + }; + } else if (options.ipv6) { + return { + valid: /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test( + value + ), + message: options.message || $.fn.bootstrapValidator.i18n.ip.ipv6, + }; + } + + return false; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.isbn = $.extend($.fn.bootstrapValidator.i18n.isbn || {}, { + default: 'Please enter a valid ISBN number', + }); + + $.fn.bootstrapValidator.validators.isbn = { + /** + * Return true if the input value is a valid ISBN 10 or ISBN 13 number + * Examples: + * - Valid: + * ISBN 10: 99921-58-10-7, 9971-5-0210-0, 960-425-059-0, 80-902734-1-6, 85-359-0277-5, 1-84356-028-3, 0-684-84328-5, 0-8044-2957-X, 0-85131-041-9, 0-943396-04-2, 0-9752298-0-X + * ISBN 13: 978-0-306-40615-7 + * - Invalid: + * ISBN 10: 99921-58-10-6 + * ISBN 13: 978-0-306-40615-6 + * + * @see http://en.wikipedia.org/wiki/International_Standard_Book_Number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} [options] Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // http://en.wikipedia.org/wiki/International_Standard_Book_Number#Overview + // Groups are separated by a hyphen or a space + var type; + switch (true) { + case /^\d{9}[\dX]$/.test(value): + case value.length === 13 && /^(\d+)-(\d+)-(\d+)-([\dX])$/.test(value): + case value.length === 13 && /^(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value): + type = 'ISBN10'; + break; + case /^(978|979)\d{9}[\dX]$/.test(value): + case value.length === 17 && /^(978|979)-(\d+)-(\d+)-(\d+)-([\dX])$/.test(value): + case value.length === 17 && /^(978|979)\s(\d+)\s(\d+)\s(\d+)\s([\dX])$/.test(value): + type = 'ISBN13'; + break; + default: + return false; + } + + // Replace all special characters except digits and X + value = value.replace(/[^0-9X]/gi, ''); + var chars = value.split(''), + length = chars.length, + sum = 0, + i, + checksum; + + switch (type) { + case 'ISBN10': + sum = 0; + for (i = 0; i < length - 1; i++) { + sum += parseInt(chars[i], 10) * (10 - i); + } + checksum = 11 - (sum % 11); + if (checksum === 11) { + checksum = 0; + } else if (checksum === 10) { + checksum = 'X'; + } + return checksum + '' === chars[length - 1]; + + case 'ISBN13': + sum = 0; + for (i = 0; i < length - 1; i++) { + sum += i % 2 === 0 ? parseInt(chars[i], 10) : parseInt(chars[i], 10) * 3; + } + checksum = 10 - (sum % 10); + if (checksum === 10) { + checksum = '0'; + } + return checksum + '' === chars[length - 1]; + + default: + return false; + } + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.isin = $.extend($.fn.bootstrapValidator.i18n.isin || {}, { + default: 'Please enter a valid ISIN number', + }); + + $.fn.bootstrapValidator.validators.isin = { + // Available country codes + // See http://isin.net/country-codes/ + COUNTRY_CODES: + 'AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW', + + /** + * Validate an ISIN (International Securities Identification Number) + * Examples: + * - Valid: US0378331005, AU0000XVGZA3, GB0002634946 + * - Invalid: US0378331004, AA0000XVGZA3 + * + * @see http://en.wikipedia.org/wiki/International_Securities_Identifying_Number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + value = value.toUpperCase(); + var regex = new RegExp('^(' + this.COUNTRY_CODES + ')[0-9A-Z]{10}$'); + if (!regex.test(value)) { + return false; + } + + var converted = '', + length = value.length; + // Convert letters to number + for (var i = 0; i < length - 1; i++) { + var c = value.charCodeAt(i); + converted += c > 57 ? (c - 55).toString() : value.charAt(i); + } + + var digits = '', + n = converted.length, + group = n % 2 !== 0 ? 0 : 1; + for (i = 0; i < n; i++) { + digits += parseInt(converted[i], 10) * (i % 2 === group ? 2 : 1) + ''; + } + + var sum = 0; + for (i = 0; i < digits.length; i++) { + sum += parseInt(digits.charAt(i), 10); + } + sum = (10 - (sum % 10)) % 10; + return sum + '' === value.charAt(length - 1); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.ismn = $.extend($.fn.bootstrapValidator.i18n.ismn || {}, { + default: 'Please enter a valid ISMN number', + }); + + $.fn.bootstrapValidator.validators.ismn = { + /** + * Validate ISMN (International Standard Music Number) + * Examples: + * - Valid: M230671187, 979-0-0601-1561-5, 979 0 3452 4680 5, 9790060115615 + * - Invalid: 9790060115614 + * + * @see http://en.wikipedia.org/wiki/International_Standard_Music_Number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Groups are separated by a hyphen or a space + var type; + switch (true) { + case /^M\d{9}$/.test(value): + case /^M-\d{4}-\d{4}-\d{1}$/.test(value): + case /^M\s\d{4}\s\d{4}\s\d{1}$/.test(value): + type = 'ISMN10'; + break; + case /^9790\d{9}$/.test(value): + case /^979-0-\d{4}-\d{4}-\d{1}$/.test(value): + case /^979\s0\s\d{4}\s\d{4}\s\d{1}$/.test(value): + type = 'ISMN13'; + break; + default: + return false; + } + + if ('ISMN10' === type) { + value = '9790' + value.substr(1); + } + + // Replace all special characters except digits + value = value.replace(/[^0-9]/gi, ''); + var length = value.length, + sum = 0, + weight = [1, 3]; + for (var i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i % 2]; + } + sum = 10 - (sum % 10); + return sum + '' === value.charAt(length - 1); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.issn = $.extend($.fn.bootstrapValidator.i18n.issn || {}, { + default: 'Please enter a valid ISSN number', + }); + + $.fn.bootstrapValidator.validators.issn = { + /** + * Validate ISSN (International Standard Serial Number) + * Examples: + * - Valid: 0378-5955, 0024-9319, 0032-1478 + * - Invalid: 0032-147X + * + * @see http://en.wikipedia.org/wiki/International_Standard_Serial_Number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Groups are separated by a hyphen or a space + if (!/^\d{4}\-\d{3}[\dX]$/.test(value)) { + return false; + } + + // Replace all special characters except digits and X + value = value.replace(/[^0-9X]/gi, ''); + var chars = value.split(''), + length = chars.length, + sum = 0; + + if (chars[7] === 'X') { + chars[7] = 10; + } + for (var i = 0; i < length; i++) { + sum += parseInt(chars[i], 10) * (8 - i); + } + return sum % 11 === 0; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.lessThan = $.extend($.fn.bootstrapValidator.i18n.lessThan || {}, { + default: 'Please enter a value less than or equal to %s', + notInclusive: 'Please enter a value less than %s', + }); + + $.fn.bootstrapValidator.validators.lessThan = { + html5Attributes: { + message: 'message', + value: 'value', + inclusive: 'inclusive', + }, + + enableByHtml5: function($field) { + var max = $field.attr('max'); + if (max) { + return { + value: max, + }; + } + + return false; + }, + + /** + * Return true if the input value is less than or equal to given number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - value: The number used to compare to. It can be + * - A number + * - Name of field which its value defines the number + * - Name of callback function that returns the number + * - A callback function that returns the number + * + * - inclusive [optional]: Can be true or false. Default is true + * - message: The invalid message + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var compareTo = $.isNumeric(options.value) ? options.value : validator.getDynamicOption($field, options.value); + + value = parseFloat(value); + return options.inclusive === true || options.inclusive === undefined + ? { + valid: value <= compareTo, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan['default'], compareTo), + } + : { + valid: value < compareTo, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.lessThan.notInclusive, compareTo), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.mac = $.extend($.fn.bootstrapValidator.i18n.mac || {}, { + default: 'Please enter a valid MAC address', + }); + + $.fn.bootstrapValidator.validators.mac = { + /** + * Return true if the input value is a MAC address. + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + return /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.notEmpty = $.extend($.fn.bootstrapValidator.i18n.notEmpty || {}, { + default: 'Please enter a value', + }); + + $.fn.bootstrapValidator.validators.notEmpty = { + enableByHtml5: function($field) { + var required = $field.attr('required') + ''; + return 'required' === required || 'true' === required; + }, + + /** + * Check if input value is empty or not + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var type = $field.attr('type'); + if ('radio' === type || 'checkbox' === type) { + return validator.getFieldElements($field.attr('data-bv-field')).filter(':checked').length > 0; + } + + return $.trim($field.val()) !== ''; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.numeric = $.extend($.fn.bootstrapValidator.i18n.numeric || {}, { + default: 'Please enter a valid float number', + }); + + $.fn.bootstrapValidator.validators.numeric = { + html5Attributes: { + message: 'message', + separator: 'separator', + }, + + enableByHtml5: function($field) { + return 'number' === $field.attr('type') && $field.attr('step') !== undefined && $field.attr('step') % 1 !== 0; + }, + + /** + * Validate decimal number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - separator: The decimal separator. Can be "." (default), "," + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + var separator = options.separator || '.'; + if (separator !== '.') { + value = value.replace(separator, '.'); + } + + return !isNaN(parseFloat(value)) && isFinite(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.phone = $.extend($.fn.bootstrapValidator.i18n.phone || {}, { + default: 'Please enter a valid phone number', + countryNotSupported: 'The country code %s is not supported', + country: 'Please enter a valid phone number in %s', + countries: { + GB: 'United Kingdom', + US: 'USA', + }, + }); + + $.fn.bootstrapValidator.validators.phone = { + html5Attributes: { + message: 'message', + country: 'country', + }, + + // The supported countries + COUNTRY_CODES: ['GB', 'US'], + + /** + * Return true if the input value contains a valid phone number for the country + * selected in the options + * + * @param {BootstrapValidator} validator Validate plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - country: The ISO-3166 country code. It can be + * - A country code + * - Name of field which its value defines the country code + * - Name of callback function that returns the country code + * - A callback function that returns the country code + * + * Currently it only supports United State (US) or United Kingdom (GB) countries + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var country = options.country; + if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) { + // Try to determine the country + country = validator.getDynamicOption($field, country); + } + + if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) { + return { + valid: false, + message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.phone.countryNotSupported, country), + }; + } + + var isValid = true; + switch (country.toUpperCase()) { + case 'GB': + // http://aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers#Match_GB_telephone_number_in_any_format + // Test: http://regexr.com/38uhv + value = $.trim(value); + isValid = /^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)(?:\d{2}\)?[\s-]?\d{4}[\s-]?\d{4}|\d{3}\)?[\s-]?\d{3}[\s-]?\d{3,4}|\d{4}\)?[\s-]?(?:\d{5}|\d{3}[\s-]?\d{3})|\d{5}\)?[\s-]?\d{4,5}|8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d))(?:(?:[\s-]?(?:x|ext\.?\s?|\#)\d+)?)$/.test( + value + ); + break; + + case 'US': + /* falls through */ + default: + // Make sure US phone numbers have 10 digits + // May start with 1, +1, or 1-; should discard + // Area code may be delimited with (), & sections may be delimited with . or - + // Test: http://regexr.com/38mqi + value = value.replace(/\D/g, ''); + isValid = /^(?:(1\-?)|(\+1 ?))?\(?(\d{3})[\)\-\.]?(\d{3})[\-\.]?(\d{4})$/.test(value) && value.length === 10; + break; + } + + return { + valid: isValid, + message: $.fn.bootstrapValidator.helpers.format( + options.message || $.fn.bootstrapValidator.i18n.phone.country, + $.fn.bootstrapValidator.i18n.phone.countries[country] + ), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.regexp = $.extend($.fn.bootstrapValidator.i18n.regexp || {}, { + default: 'Please enter a value matching the pattern', + }); + + $.fn.bootstrapValidator.validators.regexp = { + html5Attributes: { + message: 'message', + regexp: 'regexp', + }, + + enableByHtml5: function($field) { + var pattern = $field.attr('pattern'); + if (pattern) { + return { + regexp: pattern, + }; + } + + return false; + }, + + /** + * Check if the element value matches given regular expression + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consists of the following key: + * - regexp: The regular expression you need to check + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var regexp = 'string' === typeof options.regexp ? new RegExp(options.regexp) : options.regexp; + return regexp.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.remote = $.extend($.fn.bootstrapValidator.i18n.remote || {}, { + default: 'Please enter a valid value', + }); + + $.fn.bootstrapValidator.validators.remote = { + html5Attributes: { + message: 'message', + url: 'url', + name: 'name', + }, + + /** + * Request a remote server to check the input value + * + * @param {BootstrapValidator} validator Plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - url {String|Function} + * - type {String} [optional] Can be GET or POST (default) + * - data {Object|Function} [optional]: By default, it will take the value + * { + * : + * } + * - name {String} [optional]: Override the field name for the request. + * - message: The invalid message + * @returns {Boolean|Deferred} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var name = $field.attr('data-bv-field'), + data = options.data || {}, + url = options.url, + type = options.type || 'POST'; + + // Support dynamic data + if ('function' === typeof data) { + data = data.call(this, validator); + } + + // Support dynamic url + if ('function' === typeof url) { + url = url.call(this, validator); + } + + data[options.name || name] = value; + + var dfd = new $.Deferred(); + var xhr = $.ajax({ + type: type, + url: url, + dataType: 'json', + data: data, + }); + xhr.then(function(response) { + dfd.resolve($field, 'remote', response.valid === true || response.valid === 'true', response.message ? response.message : null); + }); + + dfd.fail(function() { + xhr.abort(); + }); + + return dfd; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.rtn = $.extend($.fn.bootstrapValidator.i18n.rtn || {}, { + default: 'Please enter a valid RTN number', + }); + + $.fn.bootstrapValidator.validators.rtn = { + /** + * Validate a RTN (Routing transit number) + * Examples: + * - Valid: 021200025, 789456124 + * + * @see http://en.wikipedia.org/wiki/Routing_transit_number + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + if (!/^\d{9}$/.test(value)) { + return false; + } + + var sum = 0; + for (var i = 0; i < value.length; i += 3) { + sum += parseInt(value.charAt(i), 10) * 3 + parseInt(value.charAt(i + 1), 10) * 7 + parseInt(value.charAt(i + 2), 10); + } + return sum !== 0 && sum % 10 === 0; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.sedol = $.extend($.fn.bootstrapValidator.i18n.sedol || {}, { + default: 'Please enter a valid SEDOL number', + }); + + $.fn.bootstrapValidator.validators.sedol = { + /** + * Validate a SEDOL (Stock Exchange Daily Official List) + * Examples: + * - Valid: 0263494, B0WNLY7 + * + * @see http://en.wikipedia.org/wiki/SEDOL + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + value = value.toUpperCase(); + if (!/^[0-9A-Z]{7}$/.test(value)) { + return false; + } + + var sum = 0, + weight = [1, 3, 1, 7, 3, 9, 1], + length = value.length; + for (var i = 0; i < length - 1; i++) { + sum += weight[i] * parseInt(value.charAt(i), 36); + } + sum = (10 - (sum % 10)) % 10; + return sum + '' === value.charAt(length - 1); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.siren = $.extend($.fn.bootstrapValidator.i18n.siren || {}, { + default: 'Please enter a valid SIREN number', + }); + + $.fn.bootstrapValidator.validators.siren = { + /** + * Check if a string is a siren number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + if (!/^\d{9}$/.test(value)) { + return false; + } + return $.fn.bootstrapValidator.helpers.luhn(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.siret = $.extend($.fn.bootstrapValidator.i18n.siret || {}, { + default: 'Please enter a valid SIRET number', + }); + + $.fn.bootstrapValidator.validators.siret = { + /** + * Check if a string is a siret number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var sum = 0, + length = value.length, + tmp; + for (var i = 0; i < length; i++) { + tmp = parseInt(value.charAt(i), 10); + if (i % 2 === 0) { + tmp = tmp * 2; + if (tmp > 9) { + tmp -= 9; + } + } + sum += tmp; + } + return sum % 10 === 0; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.step = $.extend($.fn.bootstrapValidator.i18n.step || {}, { + default: 'Please enter a valid step of %s', + }); + + $.fn.bootstrapValidator.validators.step = { + html5Attributes: { + message: 'message', + base: 'baseValue', + step: 'step', + }, + + /** + * Return true if the input value is valid step one + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Can consist of the following keys: + * - baseValue: The base value + * - step: The step + * - message: The invalid message + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + options = $.extend({}, { baseValue: 0, step: 1 }, options); + value = parseFloat(value); + if (!$.isNumeric(value)) { + return false; + } + + var round = function(x, precision) { + var m = Math.pow(10, precision); + x = x * m; + var sign = (x > 0) | -(x < 0), + isHalf = x % 1 === 0.5 * sign; + if (isHalf) { + return (Math.floor(x) + (sign > 0)) / m; + } else { + return Math.round(x) / m; + } + }, + floatMod = function(x, y) { + if (y === 0.0) { + return 1.0; + } + var dotX = (x + '').split('.'), + dotY = (y + '').split('.'), + precision = (dotX.length === 1 ? 0 : dotX[1].length) + (dotY.length === 1 ? 0 : dotY[1].length); + return round(x - y * Math.floor(x / y), precision); + }; + + var mod = floatMod(value - options.baseValue, options.step); + return { + valid: mod === 0.0 || mod === options.step, + message: $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.step['default'], [options.step]), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.stringCase = $.extend($.fn.bootstrapValidator.i18n.stringCase || {}, { + default: 'Please enter only lowercase characters', + upper: 'Please enter only uppercase characters', + }); + + $.fn.bootstrapValidator.validators.stringCase = { + html5Attributes: { + message: 'message', + case: 'case', + }, + + /** + * Check if a string is a lower or upper case one + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - case: Can be 'lower' (default) or 'upper' + * @returns {Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var stringCase = (options['case'] || 'lower').toLowerCase(); + return { + valid: 'upper' === stringCase ? value === value.toUpperCase() : value === value.toLowerCase(), + message: options.message || ('upper' === stringCase ? $.fn.bootstrapValidator.i18n.stringCase.upper : $.fn.bootstrapValidator.i18n.stringCase['default']), + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.stringLength = $.extend($.fn.bootstrapValidator.i18n.stringLength || {}, { + default: 'Please enter a value with valid length', + less: 'Please enter less than %s characters', + more: 'Please enter more than %s characters', + between: 'Please enter value between %s and %s characters long', + }); + + $.fn.bootstrapValidator.validators.stringLength = { + html5Attributes: { + message: 'message', + min: 'min', + max: 'max', + }, + + enableByHtml5: function($field) { + var maxLength = $field.attr('maxlength'); + if (maxLength) { + return { + max: parseInt(maxLength, 10), + }; + } + + return false; + }, + + /** + * Check if the length of element value is less or more than given number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consists of following keys: + * - min + * - max + * At least one of two keys is required + * The min, max keys define the number which the field value compares to. min, max can be + * - A number + * - Name of field which its value defines the number + * - Name of callback function that returns the number + * - A callback function that returns the number + * + * - message: The invalid message + * @returns {Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var min = $.isNumeric(options.min) ? options.min : validator.getDynamicOption($field, options.min), + max = $.isNumeric(options.max) ? options.max : validator.getDynamicOption($field, options.max), + length = value.length, + isValid = true, + message = options.message || $.fn.bootstrapValidator.i18n.stringLength['default']; + + if ((min && length < parseInt(min, 10)) || (max && length > parseInt(max, 10))) { + isValid = false; + } + + switch (true) { + case !!min && !!max: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.between, [parseInt(min, 10), parseInt(max, 10)]); + break; + + case !!min: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.more, parseInt(min, 10)); + break; + + case !!max: + message = $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.stringLength.less, parseInt(max, 10)); + break; + + default: + break; + } + + return { valid: isValid, message: message }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.uri = $.extend($.fn.bootstrapValidator.i18n.uri || {}, { + default: 'Please enter a valid URI', + }); + + $.fn.bootstrapValidator.validators.uri = { + html5Attributes: { + message: 'message', + allowlocal: 'allowLocal', + }, + + enableByHtml5: function($field) { + return 'url' === $field.attr('type'); + }, + + /** + * Return true if the input value is a valid URL + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options + * - message: The error message + * - allowLocal: Allow the private and local network IP. Default to false + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Credit to https://gist.github.com/dperini/729294 + // + // Regular Expression for URL validation + // + // Author: Diego Perini + // Updated: 2010/12/05 + // + // the regular expression composed & commented + // could be easily tweaked for RFC compliance, + // it was expressly modified to fit & satisfy + // these test for an URL shortener: + // + // http://mathiasbynens.be/demo/url-regex + // + // Notes on possible differences from a standard/generic validation: + // + // - utf-8 char class take in consideration the full Unicode range + // - TLDs have been made mandatory so single names like "localhost" fails + // - protocols have been restricted to ftp, http and https only as requested + // + // Changes: + // + // - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255 + // first and last IP address of each class is considered invalid + // (since they are broadcast/network addresses) + // + // - Added exclusion of private, reserved and/or local networks ranges + // + var allowLocal = options.allowLocal === true || options.allowLocal === 'true', + urlExp = new RegExp( + '^' + + // protocol identifier + '(?:(?:https?|ftp)://)' + + // user:pass authentication + '(?:\\S+(?::\\S*)?@)?' + + '(?:' + + // IP address exclusion + // private & local networks + (allowLocal + ? '' + : '(?!(?:10|127)(?:\\.\\d{1,3}){3})' + '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})' + '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})') + + // IP address dotted notation octets + // excludes loopback network 0.0.0.0 + // excludes reserved space >= 224.0.0.0 + // excludes network & broadcast addresses + // (first & last IP address of each class) + '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])' + + '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}' + + '(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))' + + '|' + + // host name + '(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)' + + // domain name + '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*' + + // TLD identifier + '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' + + ')' + + // port number + '(?::\\d{2,5})?' + + // resource path + '(?:/[^\\s]*)?' + + '$', + 'i' + ); + + return urlExp.test(value); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.uuid = $.extend($.fn.bootstrapValidator.i18n.uuid || {}, { + default: 'Please enter a valid UUID number', + version: 'Please enter a valid UUID version %s number', + }); + + $.fn.bootstrapValidator.validators.uuid = { + html5Attributes: { + message: 'message', + version: 'version', + }, + + /** + * Return true if and only if the input value is a valid UUID string + * + * @see http://en.wikipedia.org/wiki/Universally_unique_identifier + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - version: Can be 3, 4, 5, null + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // See the format at http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions + var patterns = { + '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + }, + version = options.version ? options.version + '' : 'all'; + return { + valid: null === patterns[version] ? true : patterns[version].test(value), + message: options.version + ? $.fn.bootstrapValidator.helpers.format(options.message || $.fn.bootstrapValidator.i18n.uuid.version, options.version) + : options.message || $.fn.bootstrapValidator.i18n.uuid['default'], + }; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.vat = $.extend($.fn.bootstrapValidator.i18n.vat || {}, { + default: 'Please enter a valid VAT number', + countryNotSupported: 'The country code %s is not supported', + country: 'Please enter a valid %s VAT number', + countries: { + AT: 'Austrian', + BE: 'Belgian', + BG: 'Bulgarian', + CH: 'Swiss', + CY: 'Cypriot', + CZ: 'Czech', + DE: 'German', + DK: 'Danish', + EE: 'Estonian', + ES: 'Spanish', + FI: 'Finnish', + FR: 'French', + GB: 'United Kingdom', + GR: 'Greek', + EL: 'Greek', + HU: 'Hungarian', + HR: 'Croatian', + IE: 'Irish', + IT: 'Italian', + LT: 'Lithuanian', + LU: 'Luxembourg', + LV: 'Latvian', + MT: 'Maltese', + NL: 'Dutch', + NO: 'Norwegian', + PL: 'Polish', + PT: 'Portuguese', + RO: 'Romanian', + RU: 'Russian', + RS: 'Serbian', + SE: 'Swedish', + SI: 'Slovenian', + SK: 'Slovak', + }, + }); + + $.fn.bootstrapValidator.validators.vat = { + html5Attributes: { + message: 'message', + country: 'country', + }, + + // Supported country codes + COUNTRY_CODES: [ + 'AT', + 'BE', + 'BG', + 'HR', + 'CY', + 'CZ', + 'DK', + 'EE', + 'FI', + 'FR', + 'DE', + 'GR', + 'EL', + 'HU', + 'IE', + 'IT', + 'LV', + 'LT', + 'LU', + 'MT', + 'NL', + 'NO', + 'PL', + 'PT', + 'RO', + 'RU', + 'RS', + 'SK', + 'SI', + 'ES', + 'SE', + 'CH', + 'GB', + ], + + /** + * Validate an European VAT number + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - country: The ISO 3166-1 country code. It can be + * - One of country code defined in COUNTRY_CODES + * - Name of field which its value defines the country code + * - Name of callback function that returns the country code + * - A callback function that returns the country code + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + var country = options.country; + if (!country) { + country = value.substr(0, 2); + } else if (typeof country !== 'string' || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) { + // Determine the country code + country = validator.getDynamicOption($field, country); + } + + if ($.inArray(country, this.COUNTRY_CODES) === -1) { + return { + valid: false, + message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.vat.countryNotSupported, country), + }; + } + + var method = ['_', country.toLowerCase()].join(''); + return this[method](value) + ? true + : { + valid: false, + message: $.fn.bootstrapValidator.helpers.format( + options.message || $.fn.bootstrapValidator.i18n.vat.country, + $.fn.bootstrapValidator.i18n.vat.countries[country.toUpperCase()] + ), + }; + }, + + // VAT validators + + /** + * Validate Austrian VAT number + * Example: + * - Valid: ATU13585627 + * - Invalid: ATU13585626 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _at: function(value) { + if (!/^ATU[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(3); + var sum = 0, + weight = [1, 2, 1, 2, 1, 2, 1], + temp = 0; + + for (var i = 0; i < 7; i++) { + temp = parseInt(value.charAt(i), 10) * weight[i]; + if (temp > 9) { + temp = Math.floor(temp / 10) + (temp % 10); + } + sum += temp; + } + + sum = 10 - ((sum + 4) % 10); + if (sum === 10) { + sum = 0; + } + + return sum + '' === value.substr(7, 1); + }, + + /** + * Validate Belgian VAT number + * Example: + * - Valid: BE0428759497 + * - Invalid: BE431150351 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _be: function(value) { + if (!/^BE[0]{0,1}[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + if (value.length === 9) { + value = '0' + value; + } + + if (value.substr(1, 1) === '0') { + return false; + } + + var sum = parseInt(value.substr(0, 8), 10) + parseInt(value.substr(8, 2), 10); + return sum % 97 === 0; + }, + + /** + * Validate Bulgarian VAT number + * Example: + * - Valid: BG175074752, + * BG7523169263, BG8032056031, + * BG7542011030, + * BG7111042925 + * - Invalid: BG175074753, BG7552A10004, BG7111042922 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _bg: function(value) { + if (!/^BG[0-9]{9,10}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + i = 0; + + // Legal entities + if (value.length === 9) { + for (i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * (i + 1); + } + sum = sum % 11; + if (sum === 10) { + sum = 0; + for (i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * (i + 3); + } + } + sum = sum % 10; + return sum + '' === value.substr(8); + } + // Physical persons, foreigners and others + else if (value.length === 10) { + // Validate Bulgarian national identification numbers + var egn = function(value) { + // Check the birth date + var year = parseInt(value.substr(0, 2), 10) + 1900, + month = parseInt(value.substr(2, 2), 10), + day = parseInt(value.substr(4, 2), 10); + if (month > 40) { + year += 100; + month -= 40; + } else if (month > 20) { + year -= 100; + month -= 20; + } + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + var sum = 0, + weight = [2, 4, 8, 5, 10, 9, 7, 3, 6]; + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = (sum % 11) % 10; + return sum + '' === value.substr(9, 1); + }, + // Validate Bulgarian personal number of a foreigner + pnf = function(value) { + var sum = 0, + weight = [21, 19, 17, 13, 11, 9, 7, 3, 1]; + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 10; + return sum + '' === value.substr(9, 1); + }, + // Finally, consider it as a VAT number + vat = function(value) { + var sum = 0, + weight = [4, 3, 2, 7, 6, 5, 4, 3, 2]; + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = 11 - (sum % 11); + if (sum === 10) { + return false; + } + if (sum === 11) { + sum = 0; + } + return sum + '' === value.substr(9, 1); + }; + return egn(value) || pnf(value) || vat(value); + } + + return false; + }, + + /** + * Validate Swiss VAT number + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _ch: function(value) { + if (!/^CHE[0-9]{9}(MWST)?$/.test(value)) { + return false; + } + + value = value.substr(3); + var sum = 0, + weight = [5, 4, 3, 2, 7, 6, 5, 4]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + sum = 11 - (sum % 11); + if (sum === 10) { + return false; + } + if (sum === 11) { + sum = 0; + } + + return sum + '' === value.substr(8, 1); + }, + + /** + * Validate Cypriot VAT number + * Examples: + * - Valid: CY10259033P + * - Invalid: CY10259033Z + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _cy: function(value) { + if (!/^CY[0-5|9]{1}[0-9]{7}[A-Z]{1}$/.test(value)) { + return false; + } + + value = value.substr(2); + + // Do not allow to start with "12" + if (value.substr(0, 2) === '12') { + return false; + } + + // Extract the next digit and multiply by the counter. + var sum = 0, + translation = { + '0': 1, + '1': 0, + '2': 5, + '3': 7, + '4': 9, + '5': 13, + '6': 15, + '7': 17, + '8': 19, + '9': 21, + }; + for (var i = 0; i < 8; i++) { + var temp = parseInt(value.charAt(i), 10); + if (i % 2 === 0) { + temp = translation[temp + '']; + } + sum += temp; + } + + sum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[sum % 26]; + return sum + '' === value.substr(8, 1); + }, + + /** + * Validate Czech Republic VAT number + * Can be: + * i) Legal entities (8 digit numbers) + * ii) Individuals with a RC (the 9 or 10 digit Czech birth number) + * iii) Individuals without a RC (9 digit numbers beginning with 6) + * + * Examples: + * - Valid: i) CZ25123891; ii) CZ7103192745, CZ991231123; iii) CZ640903926 + * - Invalid: i) CZ25123890; ii) CZ1103492745, CZ590312123 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _cz: function(value) { + if (!/^CZ[0-9]{8,10}$/.test(value)) { + return false; + } + + value = value.substr(2); + + var sum = 0, + i = 0; + if (value.length === 8) { + // Do not allow to start with '9' + if (value.charAt(0) + '' === '9') { + return false; + } + + sum = 0; + for (i = 0; i < 7; i++) { + sum += parseInt(value.charAt(i), 10) * (8 - i); + } + sum = 11 - (sum % 11); + if (sum === 10) { + sum = 0; + } + if (sum === 11) { + sum = 1; + } + + return sum + '' === value.substr(7, 1); + } else if (value.length === 9 && value.charAt(0) + '' === '6') { + sum = 0; + // Skip the first (which is 6) + for (i = 0; i < 7; i++) { + sum += parseInt(value.charAt(i + 1), 10) * (8 - i); + } + sum = 11 - (sum % 11); + if (sum === 10) { + sum = 0; + } + if (sum === 11) { + sum = 1; + } + sum = [8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 10][sum - 1]; + return sum + '' === value.substr(8, 1); + } else if (value.length === 9 || value.length === 10) { + // Validate Czech birth number (Rodné číslo), which is also national identifier + var year = 1900 + parseInt(value.substr(0, 2), 10), + month = (parseInt(value.substr(2, 2), 10) % 50) % 20, + day = parseInt(value.substr(4, 2), 10); + if (value.length === 9) { + if (year >= 1980) { + year -= 100; + } + if (year > 1953) { + return false; + } + } else if (year < 1954) { + year += 100; + } + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + // Check that the birth date is not in the future + if (value.length === 10) { + var check = parseInt(value.substr(0, 9), 10) % 11; + if (year < 1985) { + check = check % 10; + } + return check + '' === value.substr(9, 1); + } + + return true; + } + + return false; + }, + + /** + * Validate German VAT number + * Examples: + * - Valid: DE136695976 + * - Invalid: DE136695978 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _de: function(value) { + if (!/^DE[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + return $.fn.bootstrapValidator.helpers.mod11And10(value); + }, + + /** + * Validate Danish VAT number + * Example: + * - Valid: DK13585628 + * - Invalid: DK13585627 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _dk: function(value) { + if (!/^DK[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [2, 7, 6, 5, 4, 3, 2, 1]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 11 === 0; + }, + + /** + * Validate Estonian VAT number + * Examples: + * - Valid: EE100931558, EE100594102 + * - Invalid: EE100594103 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _ee: function(value) { + if (!/^EE[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [3, 7, 1, 3, 7, 1, 3, 7, 1]; + + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 10 === 0; + }, + + /** + * Validate Spanish VAT number (NIF - Número de Identificación Fiscal) + * Can be: + * i) DNI (Documento nacional de identidad), for Spaniards + * ii) NIE (Número de Identificación de Extranjeros), for foreigners + * iii) CIF (Certificado de Identificación Fiscal), for legal entities and others + * + * Examples: + * - Valid: i) ES54362315K; ii) ESX2482300W, ESX5253868R; iii) ESM1234567L, ESJ99216582, ESB58378431, ESB64717838 + * - Invalid: i) ES54362315Z; ii) ESX2482300A; iii) ESJ99216583 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _es: function(value) { + if (!/^ES[0-9A-Z][0-9]{7}[0-9A-Z]$/.test(value)) { + return false; + } + + value = value.substr(2); + var dni = function(value) { + var check = parseInt(value.substr(0, 8), 10); + check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23]; + return check + '' === value.substr(8, 1); + }, + nie = function(value) { + var check = ['XYZ'.indexOf(value.charAt(0)), value.substr(1)].join(''); + check = parseInt(check, 10); + check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23]; + return check + '' === value.substr(8, 1); + }, + cif = function(value) { + var first = value.charAt(0), + check; + if ('KLM'.indexOf(first) !== -1) { + // K: Spanish younger than 14 year old + // L: Spanish living outside Spain without DNI + // M: Granted the tax to foreigners who have no NIE + check = parseInt(value.substr(1, 8), 10); + check = 'TRWAGMYFPDXBNJZSQVHLCKE'[check % 23]; + return check + '' === value.substr(8, 1); + } else if ('ABCDEFGHJNPQRSUVW'.indexOf(first) !== -1) { + var sum = 0, + weight = [2, 1, 2, 1, 2, 1, 2], + temp = 0; + + for (var i = 0; i < 7; i++) { + temp = parseInt(value.charAt(i + 1), 10) * weight[i]; + if (temp > 9) { + temp = Math.floor(temp / 10) + (temp % 10); + } + sum += temp; + } + sum = 10 - (sum % 10); + return sum + '' === value.substr(8, 1) || 'JABCDEFGHI'[sum] === value.substr(8, 1); + } + + return false; + }; + + var first = value.charAt(0); + if (/^[0-9]$/.test(first)) { + return dni(value); + } else if (/^[XYZ]$/.test(first)) { + return nie(value); + } else { + return cif(value); + } + }, + + /** + * Validate Finnish VAT number + * Examples: + * - Valid: FI20774740 + * - Invalid: FI20774741 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _fi: function(value) { + if (!/^FI[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [7, 9, 10, 5, 8, 4, 2, 1]; + + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 11 === 0; + }, + + /** + * Validate French VAT number (TVA - taxe sur la valeur ajoutée) + * It's constructed by a SIREN number, prefixed by two characters. + * + * Examples: + * - Valid: FR40303265045, FR23334175221, FRK7399859412, FR4Z123456782 + * - Invalid: FR84323140391 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _fr: function(value) { + if (!/^FR[0-9A-Z]{2}[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + + if (!$.fn.bootstrapValidator.helpers.luhn(value.substr(2))) { + return false; + } + + if (/^[0-9]{2}$/.test(value.substr(0, 2))) { + // First two characters are digits + return value.substr(0, 2) === (parseInt(value.substr(2) + '12', 10) % 97) + ''; + } else { + // The first characters cann't be O and I + var alphabet = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ', + check; + // First one is digit + if (/^[0-9]{1}$/.test(value.charAt(0))) { + check = alphabet.indexOf(value.charAt(0)) * 24 + alphabet.indexOf(value.charAt(1)) - 10; + } else { + check = alphabet.indexOf(value.charAt(0)) * 34 + alphabet.indexOf(value.charAt(1)) - 100; + } + return (parseInt(value.substr(2), 10) + 1 + Math.floor(check / 11)) % 11 === check % 11; + } + }, + + /** + * Validate United Kingdom VAT number + * Example: + * - Valid: GB980780684 + * - Invalid: GB802311781 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _gb: function(value) { + if ( + !/^GB[0-9]{9}$/.test(value) /* Standard */ && + !/^GB[0-9]{12}$/.test(value) /* Branches */ && + !/^GBGD[0-9]{3}$/.test(value) /* Government department */ && + !/^GBHA[0-9]{3}$/.test(value) /* Health authority */ && + !/^GB(GD|HA)8888[0-9]{5}$/.test(value) + ) { + return false; + } + + value = value.substr(2); + var length = value.length; + if (length === 5) { + var firstTwo = value.substr(0, 2), + lastThree = parseInt(value.substr(2), 10); + return ('GD' === firstTwo && lastThree < 500) || ('HA' === firstTwo && lastThree >= 500); + } else if (length === 11 && ('GD8888' === value.substr(0, 6) || 'HA8888' === value.substr(0, 6))) { + if (('GD' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) >= 500) || ('HA' === value.substr(0, 2) && parseInt(value.substr(6, 3), 10) < 500)) { + return false; + } + return parseInt(value.substr(6, 3), 10) % 97 === parseInt(value.substr(9, 2), 10); + } else if (length === 9 || length === 12) { + var sum = 0, + weight = [8, 7, 6, 5, 4, 3, 2, 10, 1]; + for (var i = 0; i < 9; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 97; + + if (parseInt(value.substr(0, 3), 10) >= 100) { + return sum === 0 || sum === 42 || sum === 55; + } else { + return sum === 0; + } + } + + return true; + }, + + /** + * Validate Greek VAT number + * Examples: + * - Valid: GR023456780, EL094259216 + * - Invalid: EL123456781 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _gr: function(value) { + if (!/^GR[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + if (value.length === 8) { + value = '0' + value; + } + + var sum = 0, + weight = [256, 128, 64, 32, 16, 8, 4, 2]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = (sum % 11) % 10; + + return sum + '' === value.substr(8, 1); + }, + + // EL is traditionally prefix of Greek VAT numbers + _el: function(value) { + if (!/^EL[0-9]{9}$/.test(value)) { + return false; + } + + value = 'GR' + value.substr(2); + return this._gr(value); + }, + + /** + * Validate Hungarian VAT number + * Examples: + * - Valid: HU12892312 + * - Invalid: HU12892313 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _hu: function(value) { + if (!/^HU[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [9, 7, 3, 1, 9, 7, 3, 1]; + + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 10 === 0; + }, + + /** + * Validate Croatian VAT number + * Examples: + * - Valid: HR33392005961 + * - Invalid: HR33392005962 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _hr: function(value) { + if (!/^HR[0-9]{11}$/.test(value)) { + return false; + } + + value = value.substr(2); + return $.fn.bootstrapValidator.helpers.mod11And10(value); + }, + + /** + * Validate Irish VAT number + * Examples: + * - Valid: IE6433435F, IE6433435OA, IE8D79739I + * - Invalid: IE8D79738J + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _ie: function(value) { + if (!/^IE[0-9]{1}[0-9A-Z\*\+]{1}[0-9]{5}[A-Z]{1,2}$/.test(value)) { + return false; + } + + value = value.substr(2); + var getCheckDigit = function(value) { + while (value.length < 7) { + value = '0' + value; + } + var alphabet = 'WABCDEFGHIJKLMNOPQRSTUV', + sum = 0; + for (var i = 0; i < 7; i++) { + sum += parseInt(value.charAt(i), 10) * (8 - i); + } + sum += 9 * alphabet.indexOf(value.substr(7)); + return alphabet[sum % 23]; + }; + + // The first 7 characters are digits + if (/^[0-9]+$/.test(value.substr(0, 7))) { + // New system + return value.charAt(7) === getCheckDigit(value.substr(0, 7) + value.substr(8) + ''); + } else if ('ABCDEFGHIJKLMNOPQRSTUVWXYZ+*'.indexOf(value.charAt(1)) !== -1) { + // Old system + return value.charAt(7) === getCheckDigit(value.substr(2, 5) + value.substr(0, 1) + ''); + } + + return true; + }, + + /** + * Validate Italian VAT number, which consists of 11 digits. + * - First 7 digits are a company identifier + * - Next 3 are the province of residence + * - The last one is a check digit + * + * Examples: + * - Valid: IT00743110157 + * - Invalid: IT00743110158 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _it: function(value) { + if (!/^IT[0-9]{11}$/.test(value)) { + return false; + } + + value = value.substr(2); + if (parseInt(value.substr(0, 7), 10) === 0) { + return false; + } + + var lastThree = parseInt(value.substr(7, 3), 10); + if (lastThree < 1 || (lastThree > 201 && lastThree !== 999 && lastThree !== 888)) { + return false; + } + + return $.fn.bootstrapValidator.helpers.luhn(value); + }, + + /** + * Validate Lithuanian VAT number + * It can be: + * - 9 digits, for legal entities + * - 12 digits, for temporarily registered taxpayers + * + * Examples: + * - Valid: LT119511515, LT100001919017, LT100004801610 + * - Invalid: LT100001919018 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _lt: function(value) { + if (!/^LT([0-9]{7}1[0-9]{1}|[0-9]{10}1[0-9]{1})$/.test(value)) { + return false; + } + + value = value.substr(2); + var length = value.length, + sum = 0, + i; + for (i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * (1 + (i % 9)); + } + var check = sum % 11; + if (check === 10) { + sum = 0; + for (i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * (1 + ((i + 2) % 9)); + } + } + check = (check % 11) % 10; + return check + '' === value.charAt(length - 1); + }, + + /** + * Validate Luxembourg VAT number + * Examples: + * - Valid: LU15027442 + * - Invalid: LU15027443 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _lu: function(value) { + if (!/^LU[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + return (parseInt(value.substr(0, 6), 10) % 89) + '' === value.substr(6, 2); + }, + + /** + * Validate Latvian VAT number + * Examples: + * - Valid: LV40003521600, LV16117519997 + * - Invalid: LV40003521601, LV16137519997 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _lv: function(value) { + if (!/^LV[0-9]{11}$/.test(value)) { + return false; + } + + value = value.substr(2); + var first = parseInt(value.charAt(0), 10), + sum = 0, + weight = [], + i, + length = value.length; + if (first > 3) { + // Legal entity + sum = 0; + weight = [9, 1, 4, 8, 3, 10, 2, 5, 7, 6, 1]; + for (i = 0; i < length; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 11; + return sum === 3; + } else { + // Check birth date + var day = parseInt(value.substr(0, 2), 10), + month = parseInt(value.substr(2, 2), 10), + year = parseInt(value.substr(4, 2), 10); + year = year + 1800 + parseInt(value.charAt(6), 10) * 100; + + if (!$.fn.bootstrapValidator.helpers.date(year, month, day)) { + return false; + } + + // Check personal code + sum = 0; + weight = [10, 5, 8, 4, 2, 1, 6, 3, 7, 9]; + for (i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = ((sum + 1) % 11) % 10; + return sum + '' === value.charAt(length - 1); + } + }, + + /** + * Validate Maltese VAT number + * Examples: + * - Valid: MT11679112 + * - Invalid: MT11679113 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _mt: function(value) { + if (!/^MT[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [3, 4, 6, 7, 8, 9, 10, 1]; + + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 37 === 0; + }, + + /** + * Validate Dutch VAT number + * Examples: + * - Valid: NL004495445B01 + * - Invalid: NL123456789B90 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _nl: function(value) { + if (!/^NL[0-9]{9}B[0-9]{2}$/.test(value)) { + return false; + } + value = value.substr(2); + var sum = 0, + weight = [9, 8, 7, 6, 5, 4, 3, 2]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + sum = sum % 11; + if (sum > 9) { + sum = 0; + } + return sum + '' === value.substr(8, 1); + }, + + /** + * Validate Norwegian VAT number + * + * @see http://www.brreg.no/english/coordination/number.html + * @param {String} value VAT number + * @returns {Boolean} + */ + _no: function(value) { + if (!/^NO[0-9]{9}$/.test(value)) { + return false; + } + value = value.substr(2); + var sum = 0, + weight = [3, 2, 7, 6, 5, 4, 3, 2]; + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + sum = 11 - (sum % 11); + if (sum === 11) { + sum = 0; + } + return sum + '' === value.substr(8, 1); + }, + + /** + * Validate Polish VAT number + * Examples: + * - Valid: PL8567346215 + * - Invalid: PL8567346216 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _pl: function(value) { + if (!/^PL[0-9]{10}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [6, 5, 7, 2, 3, 4, 5, 6, 7, -1]; + + for (var i = 0; i < 10; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + return sum % 11 === 0; + }, + + /** + * Validate Portuguese VAT number + * Examples: + * - Valid: PT501964843 + * - Invalid: PT501964842 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _pt: function(value) { + if (!/^PT[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [9, 8, 7, 6, 5, 4, 3, 2]; + + for (var i = 0; i < 8; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = 11 - (sum % 11); + if (sum > 9) { + sum = 0; + } + return sum + '' === value.substr(8, 1); + }, + + /** + * Validate Romanian VAT number + * Examples: + * - Valid: RO18547290 + * - Invalid: RO18547291 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _ro: function(value) { + if (!/^RO[1-9][0-9]{1,9}$/.test(value)) { + return false; + } + value = value.substr(2); + + var length = value.length, + weight = [7, 5, 3, 2, 1, 7, 5, 3, 2].slice(10 - length), + sum = 0; + for (var i = 0; i < length - 1; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + + sum = ((10 * sum) % 11) % 10; + return sum + '' === value.substr(length - 1, 1); + }, + + /** + * Validate Russian VAT number (Taxpayer Identification Number - INN) + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _ru: function(value) { + if (!/^RU([0-9]{9}|[0-9]{12})$/.test(value)) { + return false; + } + + value = value.substr(2); + var i = 0; + if (value.length === 10) { + var sum = 0, + weight = [2, 4, 10, 3, 5, 9, 4, 6, 8, 0]; + for (i = 0; i < 10; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = sum % 11; + if (sum > 9) { + sum = sum % 10; + } + + return sum + '' === value.substr(9, 1); + } else if (value.length === 12) { + var sum1 = 0, + weight1 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0], + sum2 = 0, + weight2 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8, 0]; + + for (i = 0; i < 11; i++) { + sum1 += parseInt(value.charAt(i), 10) * weight1[i]; + sum2 += parseInt(value.charAt(i), 10) * weight2[i]; + } + sum1 = sum1 % 11; + if (sum1 > 9) { + sum1 = sum1 % 10; + } + sum2 = sum2 % 11; + if (sum2 > 9) { + sum2 = sum2 % 10; + } + + return sum1 + '' === value.substr(10, 1) && sum2 + '' === value.substr(11, 1); + } + + return false; + }, + + /** + * Validate Serbian VAT number + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _rs: function(value) { + if (!/^RS[0-9]{9}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 10, + temp = 0; + for (var i = 0; i < 8; i++) { + temp = (parseInt(value.charAt(i), 10) + sum) % 10; + if (temp === 0) { + temp = 10; + } + sum = (2 * temp) % 11; + } + + return (sum + parseInt(value.substr(8, 1), 10)) % 10 === 1; + }, + + /** + * Validate Swedish VAT number + * Examples: + * - Valid: SE123456789701 + * - Invalid: SE123456789101 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _se: function(value) { + if (!/^SE[0-9]{10}01$/.test(value)) { + return false; + } + + value = value.substr(2, 10); + return $.fn.bootstrapValidator.helpers.luhn(value); + }, + + /** + * Validate Slovenian VAT number + * Examples: + * - Valid: SI50223054 + * - Invalid: SI50223055 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _si: function(value) { + if (!/^SI[0-9]{8}$/.test(value)) { + return false; + } + + value = value.substr(2); + var sum = 0, + weight = [8, 7, 6, 5, 4, 3, 2]; + + for (var i = 0; i < 7; i++) { + sum += parseInt(value.charAt(i), 10) * weight[i]; + } + sum = 11 - (sum % 11); + if (sum === 10) { + sum = 0; + } + return sum + '' === value.substr(7, 1); + }, + + /** + * Validate Slovak VAT number + * Examples: + * - Valid: SK2022749619 + * - Invalid: SK2022749618 + * + * @param {String} value VAT number + * @returns {Boolean} + */ + _sk: function(value) { + if (!/^SK[1-9][0-9][(2-4)|(6-9)][0-9]{7}$/.test(value)) { + return false; + } + + return parseInt(value.substr(2), 10) % 11 === 0; + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.vin = $.extend($.fn.bootstrapValidator.i18n.vin || {}, { + default: 'Please enter a valid VIN number', + }); + + $.fn.bootstrapValidator.validators.vin = { + /** + * Validate an US VIN (Vehicle Identification Number) + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * @returns {Boolean} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '') { + return true; + } + + // Don't accept I, O, Q characters + if (!/^[a-hj-npr-z0-9]{8}[0-9xX][a-hj-npr-z0-9]{8}$/i.test(value)) { + return false; + } + + value = value.toUpperCase(); + var chars = { + A: 1, + B: 2, + C: 3, + D: 4, + E: 5, + F: 6, + G: 7, + H: 8, + J: 1, + K: 2, + L: 3, + M: 4, + N: 5, + P: 7, + R: 9, + S: 2, + T: 3, + U: 4, + V: 5, + W: 6, + X: 7, + Y: 8, + Z: 9, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + '0': 0, + }, + weights = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2], + sum = 0, + length = value.length; + for (var i = 0; i < length; i++) { + sum += chars[value.charAt(i) + ''] * weights[i]; + } + + var reminder = sum % 11; + if (reminder === 10) { + reminder = 'X'; + } + + return reminder + '' === value.charAt(8); + }, + }; +})(window.jQuery); +(function($) { + $.fn.bootstrapValidator.i18n.zipCode = $.extend($.fn.bootstrapValidator.i18n.zipCode || {}, { + default: 'Please enter a valid zip code', + countryNotSupported: 'The country code %s is not supported', + country: 'Please enter a valid %s', + countries: { + CA: 'Canadian postal code', + DK: 'Danish postal code', + GB: 'United Kingdom postal code', + IT: 'Italian postal code', + NL: 'Dutch postal code', + SE: 'Swiss postal code', + SG: 'Singapore postal code', + US: 'US zip code', + }, + }); + + $.fn.bootstrapValidator.validators.zipCode = { + html5Attributes: { + message: 'message', + country: 'country', + }, + + COUNTRY_CODES: ['CA', 'DK', 'GB', 'IT', 'NL', 'SE', 'SG', 'US'], + + /** + * Return true if and only if the input value is a valid country zip code + * + * @param {BootstrapValidator} validator The validator plugin instance + * @param {jQuery} $field Field element + * @param {Object} options Consist of key: + * - message: The invalid message + * - country: The country + * + * The country can be defined by: + * - An ISO 3166 country code + * Currently it supports the following countries: + * - US (United States) + * - CA (Canada) + * - DK (Denmark) + * - GB (United Kingdom) + * - IT (Italy) + * - NL (Netherlands) + * - SE (Sweden) + * - SG (Singapore) + * + * - Name of field which its value defines the country code + * - Name of callback function that returns the country code + * - A callback function that returns the country code + * + * callback: function(value, validator, $field) { + * // value is the value of field + * // validator is the BootstrapValidator instance + * // $field is jQuery element representing the field + * } + * + * @returns {Boolean|Object} + */ + validate: function(validator, $field, options) { + var value = $field.val(); + if (value === '' || !options.country) { + return true; + } + + var country = options.country; + if (typeof country !== 'string' || $.inArray(country, this.COUNTRY_CODES) === -1) { + // Try to determine the country + country = validator.getDynamicOption($field, country); + } + + if (!country || $.inArray(country.toUpperCase(), this.COUNTRY_CODES) === -1) { + return { valid: false, message: $.fn.bootstrapValidator.helpers.format($.fn.bootstrapValidator.i18n.zipCode.countryNotSupported, country) }; + } + + var isValid = false; + country = country.toUpperCase(); + switch (country) { + case 'CA': + isValid = /^(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|X|Y){1}[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}\s?[0-9]{1}(?:A|B|C|E|G|H|J|K|L|M|N|P|R|S|T|V|W|X|Y|Z){1}[0-9]{1}$/i.test( + value + ); + break; + + case 'DK': + isValid = /^(DK(-|\s)?)?\d{4}$/i.test(value); + break; + + case 'GB': + isValid = this._gb(value); + break; + + // http://en.wikipedia.org/wiki/List_of_postal_codes_in_Italy + case 'IT': + isValid = /^(I-|IT-)?\d{5}$/i.test(value); + break; + + // http://en.wikipedia.org/wiki/Postal_codes_in_the_Netherlands + case 'NL': + isValid = /^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i.test(value); + break; + + case 'SE': + isValid = /^(S-)?\d{3}\s?\d{2}$/i.test(value); + break; + + case 'SG': + isValid = /^([0][1-9]|[1-6][0-9]|[7]([0-3]|[5-9])|[8][0-2])(\d{4})$/i.test(value); + break; + + case 'US': + /* falls through */ + default: + isValid = /^\d{4,5}([\-]?\d{4})?$/.test(value); + break; + } + + return { + valid: isValid, + message: $.fn.bootstrapValidator.helpers.format( + options.message || $.fn.bootstrapValidator.i18n.zipCode.country, + $.fn.bootstrapValidator.i18n.zipCode.countries[country] + ), + }; + }, + + /** + * Validate United Kingdom postcode + * Examples: + * - Standard: EC1A 1BB, W1A 1HQ, M1 1AA, B33 8TH, CR2 6XH, DN55 1PT + * - Special cases: + * AI-2640, ASCN 1ZZ, GIR 0AA + * + * @see http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom + * @param {String} value The postcode + * @returns {Boolean} + */ + _gb: function(value) { + var firstChar = '[ABCDEFGHIJKLMNOPRSTUWYZ]', // Does not accept QVX + secondChar = '[ABCDEFGHKLMNOPQRSTUVWXY]', // Does not accept IJZ + thirdChar = '[ABCDEFGHJKPMNRSTUVWXY]', + fourthChar = '[ABEHMNPRVWXY]', + fifthChar = '[ABDEFGHJLNPQRSTUWXYZ]', + regexps = [ + // AN NAA, ANN NAA, AAN NAA, AANN NAA format + new RegExp('^(' + firstChar + '{1}' + secondChar + '?[0-9]{1,2})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'), + // ANA NAA + new RegExp('^(' + firstChar + '{1}[0-9]{1}' + thirdChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'), + // AANA NAA + new RegExp('^(' + firstChar + '{1}' + secondChar + '{1}?[0-9]{1}' + fourthChar + '{1})(\\s*)([0-9]{1}' + fifthChar + '{2})$', 'i'), + + new RegExp('^(BF1)(\\s*)([0-6]{1}[ABDEFGHJLNPQRST]{1}[ABDEFGHJLNPQRSTUWZYZ]{1})$', 'i'), // BFPO postcodes + /^(GIR)(\s*)(0AA)$/i, // Special postcode GIR 0AA + /^(BFPO)(\s*)([0-9]{1,4})$/i, // Standard BFPO numbers + /^(BFPO)(\s*)(c\/o\s*[0-9]{1,3})$/i, // c/o BFPO numbers + /^([A-Z]{4})(\s*)(1ZZ)$/i, // Overseas Territories + /^(AI-2640)$/i, // Anguilla + ]; + for (var i = 0; i < regexps.length; i++) { + if (regexps[i].test(value)) { + return true; + } + } + + return false; + }, + }; +})(window.jQuery); diff --git a/extension/assets/jquery.whencallsequentially.js b/src/libs/jquery.whencallsequentially.js similarity index 85% rename from extension/assets/jquery.whencallsequentially.js rename to src/libs/jquery.whencallsequentially.js index eee94369..e235eefc 100644 --- a/extension/assets/jquery.whencallsequentially.js +++ b/src/libs/jquery.whencallsequentially.js @@ -6,8 +6,7 @@ * * @returns $.Deferred().promise() */ -$.whenCallSequentially = function (functionCalls) { - +$.whenCallSequentially = function(functionCalls) { var deferredResonse = $.Deferred(); var resultData = new Array(); @@ -19,7 +18,7 @@ $.whenCallSequentially = function (functionCalls) { var currentDeferred = functionCalls.shift()(); // execute synchronous calls synchronously while (currentDeferred.state() === 'resolved') { - currentDeferred.done(function (data) { + currentDeferred.done(function(data) { resultData.push(data); }); if (functionCalls.length === 0) { @@ -29,10 +28,10 @@ $.whenCallSequentially = function (functionCalls) { } // handle async calls - var interval = setInterval(function () { + var interval = setInterval(function() { // handle mixed sync calls while (currentDeferred.state() === 'resolved') { - currentDeferred.done(function (data) { + currentDeferred.done(function(data) { resultData.push(data); }); if (functionCalls.length === 0) { diff --git a/src/manifest.json b/src/manifest.json new file mode 100644 index 00000000..443af0b0 --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,45 @@ +{ + "manifest_version": 2, + "version": "0.3.5.00", + "name": "Web Scraper Webpack", + "short_name": "Web Scraper Webpack", + "description": "Tool for data extraction from websites", + "permissions": ["", "tabs", "notifications", "storage", "unlimitedStorage", "downloads"], + "icons": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + }, + "browser_action": { + "default_icon": { + "19": "icons/icon19.png", + "38": "icons/icon38.png" + }, + "default_title": "Web Scraper", + "default_popup": "popup/popup.html" + }, + "options_ui": { + "page": "options/options.html", + "open_in_tab": true, + "browser_style": false + }, + "devtools_page": "devtools/devtools.html", + "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", + "background": { + "scripts": ["background/background.js"] + }, + "web_accessible_resources": ["icons/icon16.png", "icons/icon19.png", "icons/icon38.png", "icons/icon48.png", "icons/icon128.png"], + "content_scripts": [ + { + "matches": ["*://*/*"], + "js": ["content_script/content_script.js"], + "css": ["content_script/content_script.css"] + } + ], + "browser_specific_settings": { + "gecko": { + "id": "web_scraper@extension.com", + "strict_min_version": "42.0" + } + } +} diff --git a/extension/options_page/options.html b/src/options/options.html similarity index 59% rename from extension/options_page/options.html rename to src/options/options.html index 85e1bc0d..0eb96132 100644 --- a/extension/options_page/options.html +++ b/src/options/options.html @@ -1,13 +1,10 @@ + Web Scraper - - - - - - + + @@ -31,26 +28,25 @@

Web Scraper

Options page


-
Storage settings -
- -
- + + - -
-
+ + +
- +
@@ -58,20 +54,18 @@

Web Scraper

- +
-
- +
-
@@ -80,8 +74,6 @@

Web Scraper

- - diff --git a/src/options/options.js b/src/options/options.js new file mode 100644 index 00000000..c0d92b66 --- /dev/null +++ b/src/options/options.js @@ -0,0 +1,102 @@ +import 'bootstrap/dist/css/bootstrap.css'; +import 'bootstrap/dist/js/bootstrap'; +import Config from '../scripts/Config'; + +$(function() { + // popups for Storage setting input fields + $('#sitemapDb') + .popover({ + title: 'Database for sitemap storage', + html: true, + content: 'CouchDB database url
http://example.com/scraper-sitemaps/', + placement: 'bottom', + }) + .blur(function() { + $(this).popover('hide'); + }); + + $('#dataDb') + .popover({ + title: 'Database for scraped data', + html: true, + content: 'CouchDB database url. For each sitemap a new DB will be created.
http://example.com/', + placement: 'bottom', + }) + .blur(function() { + $(this).popover('hide'); + }); + + $('#restUrl') + .popover({ + title: 'Url to push your sitemaps.', + html: true, + content: 'Rest api url.', + placement: 'bottom', + }) + .blur(function() { + $(this).popover('hide'); + }); + + // switch between configuration types + $('select[name=storageType]').change(function() { + var type = $(this).val(); + + if (type === 'couchdb') { + $('.form-group.couchdb').show(); + $('.form-group.rest').hide(); + } else if (type === 'rest') { + $('.form-group.rest').show(); + $('.form-group.couchdb').hide(); + } else { + $('.form-group.rest').hide(); + $('.form-group.couchdb').hide(); + } + }); + + // Extension configuration + var config = new Config(); + + // load previously synced data + config.loadConfiguration().then(() => { + $('#storageType').val(config.storageType); + $('#sitemapDb').val(config.sitemapDb); + $('#dataDb').val(config.dataDb); + $('#restUrl').val(config.restUrl); + + $('select[name=storageType]').change(); + }); + + // Sync storage settings + $('form#storage_configuration').submit(function() { + const storageType = $('#storageType').val(); + const newConfig = { + storageType: storageType, + sitemapDb: '', + dataDb: '', + restUrl: '', + }; + + if (storageType === 'couchdb') { + newConfig.sitemapDb = $('#sitemapDb').val(); + newConfig.dataDb = $('#dataDb').val(); + } else if (storageType === 'rest') { + newConfig.restUrl = $('#restUrl').val(); + } + + config + .updateConfiguration(newConfig) + .then(() => { + $('.alert') + .attr('id', 'success') + .text('Options successfully updated.') + .show(); + }) + .catch(() => { + $('.alert') + .attr('id', 'error') + .text('Failed to save options ' + chrome.runtime.lastError.message) + .show(); + }); + return false; + }); +}); diff --git a/src/popup/popup.html b/src/popup/popup.html new file mode 100644 index 00000000..b021dc2e --- /dev/null +++ b/src/popup/popup.html @@ -0,0 +1,29 @@ + + + + + + + +

+ Open Developer tools where you will find Web Scraper tab: +

+
    +
  • + Windows, Linux: Ctrl+Shift+I or F12 +
  • +
  • + Mac: Cmd+Opt+I +
  • +
  • + Any OS: open Tools / Developer tools +
  • +
+

Documentation is available on webscraper.io

+ + diff --git a/src/scripts/App.js b/src/scripts/App.js new file mode 100644 index 00000000..434a04f7 --- /dev/null +++ b/src/scripts/App.js @@ -0,0 +1,14 @@ +import 'bootstrap/dist/css/bootstrap.css'; +import 'jquery-flexdatalist/jquery.flexdatalist.css'; +import '../libs/jquery.bootstrapvalidator/bootstrapValidator.css'; +import '../devtools/panel.css'; +import 'bootstrap/dist/js/bootstrap'; +import StoreDevtools from './StoreDevtools'; +import SitemapController from './Controller'; + +$(function() { + // init bootstrap alerts + $('.alert').alert(); + + new SitemapController(new StoreDevtools(), 'views/'); +}); diff --git a/extension/scripts/BackgroundScript.js b/src/scripts/BackgroundScript.js similarity index 56% rename from extension/scripts/BackgroundScript.js rename to src/scripts/BackgroundScript.js index 08514355..17ed070a 100644 --- a/extension/scripts/BackgroundScript.js +++ b/src/scripts/BackgroundScript.js @@ -1,11 +1,13 @@ +import * as browser from 'webextension-polyfill'; + /** * ContentScript that can be called from anywhere within the extension */ -var BackgroundScript = { - +let BackgroundScript = { dummy: function() { - - return $.Deferred().resolve("dummy").promise(); + return $.Deferred() + .resolve('dummy') + .promise(); }, /** @@ -13,24 +15,22 @@ var BackgroundScript = { * @returns $.Deferred() integer */ getActiveTabId: function() { - - var deferredResponse = $.Deferred(); - - chrome.tabs.query({ - active: true, - currentWindow: true - }, function (tabs) { - - if (tabs.length < 1) { - // @TODO must be running within popup. maybe find another active window? - deferredResponse.reject("couldn't find the active tab"); - } - else { - var tabId = tabs[0].id; - deferredResponse.resolve(tabId); - } + return new Promise((resolve, reject) => { + browser.tabs + .query({ + active: true, + currentWindow: true, + }) + .then(function(tabs) { + if (tabs.length < 1) { + // @TODO must be running within popup. maybe find another active window? + reject("couldn't find the active tab"); + } else { + let tabId = tabs[0].id; + resolve(tabId); + } + }); }); - return deferredResponse.promise(); }, /** @@ -39,66 +39,58 @@ var BackgroundScript = { * @param request.request request that will be passed to the function */ executeContentScript: function(request) { - var reqToContentScript = { contentScriptCall: true, fn: request.fn, - request: request.request + request: request.request, }; var deferredResponse = $.Deferred(); - var deferredActiveTabId = this.getActiveTabId(); - deferredActiveTabId.done(function(tabId) { - chrome.tabs.sendMessage(tabId, reqToContentScript, function(response) { + this.getActiveTabId().then(function(tabId) { + browser.tabs.sendMessage(tabId, reqToContentScript).then(function(response) { deferredResponse.resolve(response); }); }); return deferredResponse; - } + }, }; /** * @param location configure from where the content script is being accessed (ContentScript, BackgroundPage, DevTools) * @returns BackgroundScript */ -var getBackgroundScript = function(location) { - +export default function getBackgroundScript(location) { // Handle calls from different places - if(location === "BackgroundScript") { + if (location === 'BackgroundScript') { return BackgroundScript; - } - else if(location === "DevTools" || location === "ContentScript") { - + } else if (location === 'DevTools' || location === 'ContentScript') { // if called within background script proxy calls to content script var backgroundScript = {}; Object.keys(BackgroundScript).forEach(function(attr) { - if(typeof BackgroundScript[attr] === 'function') { + if (typeof BackgroundScript[attr] === 'function') { backgroundScript[attr] = function(request) { - var reqToBackgroundScript = { backgroundScriptCall: true, fn: attr, - request: request + request: request, }; var deferredResponse = $.Deferred(); - chrome.runtime.sendMessage(reqToBackgroundScript, function(response) { + browser.runtime.sendMessage(reqToBackgroundScript).then(function(response) { deferredResponse.resolve(response); }); return deferredResponse; }; - } - else { + } else { backgroundScript[attr] = BackgroundScript[attr]; } }); return backgroundScript; + } else { + throw 'Invalid BackgroundScript initialization - ' + location; } - else { - throw "Invalid BackgroundScript initialization - " + location; - } -}; \ No newline at end of file +} diff --git a/src/scripts/ChromePopupBrowser.js b/src/scripts/ChromePopupBrowser.js new file mode 100644 index 00000000..7d2ff761 --- /dev/null +++ b/src/scripts/ChromePopupBrowser.js @@ -0,0 +1,92 @@ +import * as browser from 'webextension-polyfill'; + +export default class ChromePopupBrowser { + constructor(options) { + this.pageLoadDelay = options.pageLoadDelay; + // @TODO somehow handle the closed window + } + + _initPopupWindow(callback, scope) { + let popup_browser = this; + if (this.window !== undefined) { + console.log(JSON.stringify(this.window)); + // check if tab exists + browser.tabs.get(this.tab.id).then(function(tab) { + if (!tab) { + throw 'Scraping window closed'; + } + }); + + callback.call(scope); + return; + } + + let createWindowOptions = { + type: 'popup', + width: 1042, + height: 768, + url: 'browser://newtab', + }; + + browser.windows.create(createWindowOptions).then(function(window) { + popup_browser.window = window; + popup_browser.tab = window.tabs[0]; + callback.call(scope); + }); + } + + loadUrl(url, callback) { + var tab = this.tab; + + var tabLoadListener = function(tabId, changeInfo, tab) { + if (tabId === this.tab.id) { + if (changeInfo.status === 'complete') { + // @TODO check url ? maybe it would be bad because some sites might use redirects + + // remove event listener + browser.tabs.onUpdated.removeListener(tabLoadListener); + + // callback tab is loaded after page load delay + setTimeout(callback, this.pageLoadDelay); + } + } + }.bind(this); + browser.tabs.onUpdated.addListener(tabLoadListener); + + browser.tabs.update(tab.id, { url: url }); + } + + close() { + browser.windows.remove(this.window.id); + } + + fetchData(url, sitemap, parentSelectorId, callback, scope) { + var current_browser = this; + + this._initPopupWindow(function() { + var tab = current_browser.tab; + + current_browser.loadUrl( + url, + function() { + var message = { + extractData: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + parentSelectorId: parentSelectorId, + }; + + browser.tabs.sendMessage(tab.id, message).then(function(data, selectors) { + console.log('extracted data from web page', data); + + if (selectors && scope) { + // table selector can dynamically add columns (addMissingColumns Feature) + scope.scraper.sitemap.selectors = selectors; + } + + callback.call(scope, data); + }); + }.bind(this) + ); + }, this); + } +} diff --git a/src/scripts/Config.js b/src/scripts/Config.js new file mode 100644 index 00000000..08341133 --- /dev/null +++ b/src/scripts/Config.js @@ -0,0 +1,52 @@ +import * as browser from 'webextension-polyfill'; + +export default class Config { + constructor() { + this.sitemapDb = ''; + this.dataDb = ''; + this.restUrl = ''; + this.defaults = { + storageType: 'local', + // this is where sitemap documents are stored + sitemapDb: 'scraper-sitemaps', + // this is where scraped data is stored. + // empty for local storage + dataDb: '', + restUrl: '', + }; + } + + /** + * Loads configuration from chrome extension sync storage + */ + loadConfiguration(callback) { + return new Promise(resolve => { + browser.storage.sync.get(['sitemapDb', 'dataDb', 'storageType', 'restUrl']).then( + function(items) { + this.storageType = items.storageType || this.defaults.storageType; + + this.sitemapDb = this.defaults.sitemapDb; + this.dataDb = this.defaults.dataDb; + this.restUrl = this.defaults.restUrl; + + if (this.storageType === 'couchdb') { + this.sitemapDb = items.sitemapDb || this.defaults.sitemapDb; + this.dataDb = items.dataDb || this.defaults.dataDb; + } else if (this.storageType === 'rest') { + this.restUrl = items.restUrl || this.defaults.restUrl; + } + resolve(); + }.bind(this) + ); + }); + } + + /** + * Saves configuration to chrome extension sync storage + * @param {type} items + * @returns {Promise} Promise + */ + updateConfiguration(items) { + return browser.storage.sync.set(items); + } +} diff --git a/src/scripts/ContentScript.js b/src/scripts/ContentScript.js new file mode 100644 index 00000000..12c7ac7f --- /dev/null +++ b/src/scripts/ContentScript.js @@ -0,0 +1,148 @@ +import getBackgroundScript from './BackgroundScript'; +import ContentSelector from './ContentSelector'; + +/** + * ContentScript that can be called from anywhere within the extension + */ +let ContentScript = { + /** + * Fetch + * @param request.CSSSelector css selector as string + * @returns $.Deferred() + */ + getHTML: function(request) { + let deferredHTML = $.Deferred(); + let html = $(request.CSSSelector) + .clone() + .wrap('

') + .parent() + .html(); + deferredHTML.resolve(html); + return deferredHTML.promise(); + }, + + /** + * Removes current content selector if is in use within the page + * @returns $.Deferred() + */ + removeCurrentContentSelector: function() { + let deferredResponse = $.Deferred(); + let contentSelector = window.cs; + if (contentSelector === undefined) { + deferredResponse.resolve(); + } else { + contentSelector.removeGUI(); + window.cs = undefined; + deferredResponse.resolve(); + } + + return deferredResponse.promise(); + }, + + /** + * Select elements within the page + * @param request.parentCSSSelector + * @param request.allowedElements + */ + selectSelector: function(request) { + let deferredResponse = $.Deferred(); + + this.removeCurrentContentSelector().done( + function() { + let contentSelector = new ContentSelector({ + parentCSSSelector: request.parentCSSSelector, + allowedElements: request.allowedElements, + }); + window.cs = contentSelector; + + let deferredCSSSelector = contentSelector.getCSSSelector(); + deferredCSSSelector + .done( + function(response) { + this.removeCurrentContentSelector().done( + function() { + deferredResponse.resolve(response); + window.cs = undefined; + }.bind(this) + ); + }.bind(this) + ) + .fail( + function(message) { + deferredResponse.reject(message); + window.cs = undefined; + }.bind(this) + ); + }.bind(this) + ); + + return deferredResponse.promise(); + }, + + /** + * Preview elements + * @param request.parentCSSSelector + * @param request.elementCSSSelector + */ + previewSelector: function(request) { + let deferredResponse = $.Deferred(); + this.removeCurrentContentSelector().done(function() { + let contentSelector = new ContentSelector({ + parentCSSSelector: request.parentCSSSelector, + }); + window.cs = contentSelector; + + let deferredSelectorPreview = contentSelector.previewSelector(request.elementCSSSelector); + deferredSelectorPreview + .done(function() { + deferredResponse.resolve(); + }) + .fail(function(message) { + deferredResponse.reject(message); + window.cs = undefined; + }); + }); + return deferredResponse; + }, +}; + +/** + * + * @param location configure from where the content script is being accessed (ContentScript, BackgroundPage, DevTools) + * @param backgroundScript BackgroundScript client + * @returns ContentScript + */ +export default function getContentScript(location) { + let contentScript; + + // Handle calls from different places + if (location === 'ContentScript') { + contentScript = ContentScript; + contentScript.backgroundScript = getBackgroundScript('ContentScript'); + return contentScript; + } else if (location === 'BackgroundScript' || location === 'DevTools') { + let backgroundScript = getBackgroundScript(location); + + // if called within background script proxy calls to content script + contentScript = {}; + Object.keys(ContentScript).forEach(function(attr) { + if (typeof ContentScript[attr] === 'function') { + contentScript[attr] = function(request) { + let reqToContentScript = { + contentScriptCall: true, + fn: attr, + request: request, + }; + + return backgroundScript.executeContentScript(reqToContentScript); + }; + } else { + contentScript[attr] = ContentScript[attr]; + } + }); + contentScript.backgroundScript = backgroundScript; + return contentScript; + } else { + throw 'Invalid ContentScript initialization - ' + location; + } +} diff --git a/src/scripts/ContentSelector.js b/src/scripts/ContentSelector.js new file mode 100644 index 00000000..ee1b3b40 --- /dev/null +++ b/src/scripts/ContentSelector.js @@ -0,0 +1,399 @@ +import CssSelector from '../libs/css-selector/lib/CssSelector'; +import ElementQuery from './ElementQuery'; + +export default class ContentSelector { + /** + * @param options.parentCSSSelector Elements can be only selected within this element + * @param options.allowedElements Elements that can only be selected + * @constructor + */ + constructor(options) { + // deferred response + this.deferredCSSSelectorResponse = $.Deferred(); + + this.allowedElements = options.allowedElements; + this.parentCSSSelector = options.parentCSSSelector.trim(); + this.alert = + options.alert || + function(txt) { + alert(txt); + }; + + if (this.parentCSSSelector) { + this.parent = $(this.parentCSSSelector)[0]; + + // handle situation when parent selector not found + if (this.parent === undefined) { + this.deferredCSSSelectorResponse.reject('parent selector not found'); + this.alert('Parent element not found!'); + } + } else { + this.parent = $('body')[0]; + } + } + + /** + * get css selector selected by the user + */ + getCSSSelector(request) { + if (this.deferredCSSSelectorResponse.state() !== 'rejected') { + // elements that are selected by the user + this.selectedElements = []; + // element selected from top + this.top = 0; + + // initialize css selector + this.initCssSelector(false); + + this.initGUI(); + } + + return this.deferredCSSSelectorResponse.promise(); + } + + getCurrentCSSSelector() { + if (this.selectedElements && this.selectedElements.length > 0) { + var cssSelector; + + // handle special case when parent is selected + if (this.isParentSelected()) { + if (this.selectedElements.length === 1) { + cssSelector = '_parent_'; + } else if ($('#-selector-toolbar [name=diferentElementSelection]').prop('checked')) { + var selectedElements = this.selectedElements.clone(); + selectedElements.splice(selectedElements.indexOf(this.parent), 1); + cssSelector = '_parent_, ' + this.cssSelector.getCssSelector(selectedElements, this.top); + } else { + // will trigger error where multiple selections are not allowed + cssSelector = this.cssSelector.getCssSelector(this.selectedElements, this.top); + } + } else { + cssSelector = this.cssSelector.getCssSelector(this.selectedElements, this.top); + } + + return cssSelector; + } + return ''; + } + + isParentSelected() { + return this.selectedElements.indexOf(this.parent) !== -1; + } + + /** + * initialize or reconfigure css selector class + * @param allowMultipleSelectors + */ + initCssSelector(allowMultipleSelectors) { + this.cssSelector = new CssSelector({ + enableSmartTableSelector: true, + parent: this.parent, + allowMultipleSelectors: allowMultipleSelectors, + ignoredClasses: ['-sitemap-select-item-selected', '-sitemap-select-item-hover', '-sitemap-parent', '-web-scraper-img-on-top', '-web-scraper-selection-active'], + query: jQuery, + }); + } + + previewSelector(elementCSSSelector) { + if (this.deferredCSSSelectorResponse.state() !== 'rejected') { + this.highlightParent(); + $(ElementQuery(elementCSSSelector, this.parent)).addClass('-sitemap-select-item-selected'); + this.deferredCSSSelectorResponse.resolve(); + } + + return this.deferredCSSSelectorResponse.promise(); + } + + initGUI() { + this.highlightParent(); + + // all elements except toolbar + this.$allElements = $(this.allowedElements + ':not(#-selector-toolbar):not(#-selector-toolbar *)', this.parent); + // allow selecting parent also + if (this.parent !== document.body) { + this.$allElements.push(this.parent); + } + + this.bindElementHighlight(); + this.bindElementSelection(); + this.bindKeyboardSelectionManipulations(); + this.attachToolbar(); + this.bindMultipleGroupCheckbox(); + this.bindMultipleGroupPopupHide(); + this.bindMoveImagesToTop(); + } + + bindElementSelection() { + this.$allElements.bind( + 'click.elementSelector', + function(e) { + var element = e.currentTarget; + if (this.selectedElements.indexOf(element) === -1) { + this.selectedElements.push(element); + } + this.highlightSelectedElements(); + + // Cancel all other events + return false; + }.bind(this) + ); + } + + /** + * Add to select elements the element that is under the mouse + */ + selectMouseOverElement() { + var element = this.mouseOverElement; + if (element) { + this.selectedElements.push(element); + this.highlightSelectedElements(); + } + } + + bindElementHighlight() { + $(this.$allElements) + .bind( + 'mouseover.elementSelector', + function(e) { + // allow event bubbling for other event listeners but not for web scraper. + if (e.target !== e.currentTarget) { + return; + } + + var element = e.currentTarget; + this.mouseOverElement = element; + $(element).addClass('-sitemap-select-item-hover'); + }.bind(this) + ) + .bind( + 'mouseout.elementSelector', + function(e) { + // allow event bubbling for other event listeners but not for web scraper. + if (e.target !== e.currentTarget) { + return; + } + + var element = e.currentTarget; + this.mouseOverElement = null; + $(element).removeClass('-sitemap-select-item-hover'); + }.bind(this) + ); + } + + bindMoveImagesToTop() { + $('body').addClass('-web-scraper-selection-active'); + + // do this only when selecting images + if (this.allowedElements === 'img') { + $('img') + .filter(function(i, element) { + return $(element).css('position') === 'static'; + }) + .addClass('-web-scraper-img-on-top'); + } + } + + unbindMoveImagesToTop() { + $('body.-web-scraper-selection-active').removeClass('-web-scraper-selection-active'); + $('img.-web-scraper-img-on-top').removeClass('-web-scraper-img-on-top'); + } + + selectChild() { + this.top--; + if (this.top < 0) { + this.top = 0; + } + } + + selectParent() { + this.top++; + } + + // User with keyboard arrows can select child or paret elements of selected elements. + bindKeyboardSelectionManipulations() { + // check for focus + var lastFocusStatus; + this.keyPressFocusInterval = setInterval( + function() { + var focus = document.hasFocus(); + if (focus === lastFocusStatus) return; + lastFocusStatus = focus; + + $('#-selector-toolbar .key-button').toggleClass('hide', !focus); + $('#-selector-toolbar .key-events').toggleClass('hide', focus); + }.bind(this), + 200 + ); + + // Using up/down arrows user can select elements from top of the + // selected element + $(document).bind( + 'keydown.selectionManipulation', + function(event) { + // select child C + if (event.keyCode === 67) { + this.animateClickedKey($('#-selector-toolbar .key-button-child')); + this.selectChild(); + } + // select parent P + else if (event.keyCode === 80) { + this.animateClickedKey($('#-selector-toolbar .key-button-parent')); + this.selectParent(); + } + // select element + else if (event.keyCode === 83) { + this.animateClickedKey($('#-selector-toolbar .key-button-select')); + this.selectMouseOverElement(); + } + + this.highlightSelectedElements(); + }.bind(this) + ); + } + + animateClickedKey(element) { + $(element) + .removeClass('clicked') + .removeClass('clicked-animation'); + setTimeout(function() { + $(element).addClass('clicked'); + setTimeout(function() { + $(element).addClass('clicked-animation'); + }, 100); + }, 1); + } + + highlightSelectedElements() { + try { + var resultCssSelector = this.getCurrentCSSSelector(); + + $('body #-selector-toolbar .selector').text(resultCssSelector); + // highlight selected elements + $('.-sitemap-select-item-selected').removeClass('-sitemap-select-item-selected'); + $(ElementQuery(resultCssSelector, this.parent)).addClass('-sitemap-select-item-selected'); + } catch (err) { + if (err === 'found multiple element groups, but allowMultipleSelectors disabled') { + console.log('multiple different element selection disabled'); + + this.showMultipleGroupPopup(); + // remove last added element + this.selectedElements.pop(); + this.highlightSelectedElements(); + } + } + } + + showMultipleGroupPopup() { + $('#-selector-toolbar .popover').attr('style', 'display:block !important;'); + } + + hideMultipleGroupPopup() { + $('#-selector-toolbar .popover').attr('style', ''); + } + + bindMultipleGroupPopupHide() { + $('#-selector-toolbar .popover .close').click(this.hideMultipleGroupPopup.bind(this)); + } + + unbindMultipleGroupPopupHide() { + $('#-selector-toolbar .popover .close').unbind('click'); + } + + bindMultipleGroupCheckbox() { + $('#-selector-toolbar [name=diferentElementSelection]').change( + function(e) { + if ($(e.currentTarget).is(':checked')) { + this.initCssSelector(true); + } else { + this.initCssSelector(false); + } + }.bind(this) + ); + } + unbindMultipleGroupCheckbox() { + $('#-selector-toolbar .diferentElementSelection').unbind('change'); + } + + attachToolbar() { + var $toolbar = + '

' + + '
' + + '
' + + '' + + '
' + + '
×
' + + '
' + + '
' + + '
' + + 'Different type element selection is disabled. If the element ' + + 'you clicked should also be included then enable this and ' + + 'click on the element again. Usually this is not needed.' + + '
' + + '
' + + '
' + + '
' + + '
Enable key events
' + + '
S
' + + '
P
' + + '
C
' + + '
Done selecting!
' + + '
'; + $('body').append($toolbar); + + $('body #-selector-toolbar .done-selecting-button').click( + function() { + this.selectionFinished(); + }.bind(this) + ); + } + highlightParent() { + // do not highlight parent if its the body + if (!$(this.parent).is('body') && !$(this.parent).is('#webpage')) { + $(this.parent).addClass('-sitemap-parent'); + } + } + + unbindElementSelection() { + $(this.$allElements).unbind('click.elementSelector'); + // remove highlighted element classes + this.unbindElementSelectionHighlight(); + } + unbindElementSelectionHighlight() { + $('.-sitemap-select-item-selected').removeClass('-sitemap-select-item-selected'); + $('.-sitemap-parent').removeClass('-sitemap-parent'); + } + unbindElementHighlight() { + $(this.$allElements) + .unbind('mouseover.elementSelector') + .unbind('mouseout.elementSelector'); + } + unbindKeyboardSelectionMaipulatios() { + $(document).unbind('keydown.selectionManipulation'); + clearInterval(this.keyPressFocusInterval); + } + removeToolbar() { + $('body #-selector-toolbar a').unbind('click'); + $('#-selector-toolbar').remove(); + } + + /** + * Remove toolbar and unbind events + */ + removeGUI() { + this.unbindElementSelection(); + this.unbindElementHighlight(); + this.unbindKeyboardSelectionMaipulatios(); + this.unbindMultipleGroupPopupHide(); + this.unbindMultipleGroupCheckbox(); + this.unbindMoveImagesToTop(); + this.removeToolbar(); + } + + selectionFinished() { + var resultCssSelector = this.getCurrentCSSSelector(); + + this.deferredCSSSelectorResponse.resolve({ + CSSSelector: resultCssSelector, + }); + } +} diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js new file mode 100644 index 00000000..4f7d9eca --- /dev/null +++ b/src/scripts/Controller.js @@ -0,0 +1,1665 @@ +import getBackgroundScript from './BackgroundScript'; +import getContentScript from './ContentScript'; +import Sitemap from './Sitemap'; +import SelectorGraphv2 from './SelectorGraphv2'; +import SelectorList from './SelectorList'; +import SelectorTable from './Selector/SelectorTable'; +import Model from './Model'; +import * as ich from 'icanhaz/ICanHaz'; +import 'jquery-flexdatalist/jquery.flexdatalist'; +import '../libs/jquery.bootstrapvalidator/bootstrapValidator'; +import * as browser from 'webextension-polyfill'; + +export default class SitemapController { + constructor(store, templateDir) { + this.store = store; + this.templateDir = templateDir; + this.backgroundScript = getBackgroundScript('DevTools'); + this.contentScript = getContentScript('DevTools'); + this.selectorTypes = [ + { + type: 'SelectorText', + title: 'Text', + }, + { + type: 'ConstantValue', + title: 'Constant value', + }, + { + type: 'SelectorInputValue', + title: 'Input value', + }, + { + type: 'SelectorLink', + title: 'Link', + }, + { + type: 'SelectorPopupLink', + title: 'Popup Link', + }, + { + type: 'SelectorImage', + title: 'Image', + }, + { + type: 'SelectorDocument', + title: 'Document', + }, + { + type: 'SelectorTable', + title: 'Table', + }, + { + type: 'SelectorElementAttribute', + title: 'Element attribute', + }, + { + type: 'SelectorElementStyle', + title: 'Element style', + }, + { + type: 'SelectorHTML', + title: 'HTML', + }, + { + type: 'SelectorElement', + title: 'Element', + }, + { + type: 'SelectorElementScroll', + title: 'Element scroll down', + }, + { + type: 'SelectorElementClick', + title: 'Element click', + }, + { + type: 'SelectorGroup', + title: 'Grouped', + }, + ]; + this.init(); + } + + control(controls) { + let controller = this; + + for (let selector in controls) { + for (let event in controls[selector]) { + $(document).on( + event, + selector, + (function(selector, event) { + return function() { + let continueBubbling = controls[selector][event].call(controller, this); + if (continueBubbling !== true) { + return false; + } + }; + })(selector, event) + ); + } + } + } + + /** + * Loads templates for ICanHaz + */ + loadTemplates(cbAllTemplatesLoaded) { + let templateIds = [ + 'Viewport', + 'SitemapList', + 'SitemapListItem', + 'SitemapCreate', + 'SitemapImport', + 'SitemapExport', + 'SitemapBrowseData', + 'SitemapScrapeConfig', + 'SitemapExportDataCSV', + 'SitemapEditMetadata', + 'SelectorList', + 'SelectorListItem', + 'SelectorEdit', + 'SelectorEditTableColumn', + 'SitemapSelectorGraph', + 'DataPreview', + ]; + let templatesLoaded = 0; + let cbLoaded = function(templateId, template) { + templatesLoaded++; + ich.addTemplate(templateId, template); + if (templatesLoaded === templateIds.length) { + cbAllTemplatesLoaded(); + } + }; + + templateIds.forEach( + function(templateId) { + $.get(this.templateDir + templateId + '.html', cbLoaded.bind(this, templateId)); + }.bind(this) + ); + } + + init() { + this.loadTemplates( + function() { + // currently viewed objects + this.clearState(); + + // render main viewport + ich.Viewport().appendTo('body'); + + // cancel all form submits + $('form').bind('submit', function() { + return false; + }); + + this.control({ + '#sitemaps-nav-button': { + click: this.showSitemaps, + }, + '#create-sitemap-create-nav-button': { + click: this.showCreateSitemap, + }, + '#create-sitemap-import-nav-button': { + click: this.showImportSitemapPanel, + }, + '#sitemap-export-nav-button': { + click: this.showSitemapExportPanel, + }, + '#sitemap-export-data-csv-nav-button': { + click: this.showSitemapExportDataCsvPanel, + }, + '#submit-create-sitemap': { + click: this.createSitemap, + }, + '#submit-import-sitemap': { + click: this.importSitemap, + }, + '#sitemap-edit-metadata-nav-button': { + click: this.editSitemapMetadata, + }, + '#sitemap-selector-list-nav-button': { + click: this.showSitemapSelectorList, + }, + '#sitemap-selector-graph-nav-button': { + click: this.showSitemapSelectorGraph, + }, + '#sitemap-browse-nav-button': { + click: this.browseSitemapData, + }, + 'button#submit-edit-sitemap': { + click: this.editSitemapMetadataSave, + }, + '#edit-sitemap-metadata-form': { + submit: function() { + return false; + }, + }, + '#sitemaps tr': { + click: this.editSitemap, + }, + '#sitemaps button[action=delete-sitemap]': { + click: this.deleteSitemap, + }, + '#sitemap-scrape-nav-button': { + click: this.showScrapeSitemapConfigPanel, + }, + '#submit-scrape-sitemap-form': { + submit: function() { + return false; + }, + }, + '#submit-scrape-sitemap': { + click: this.scrapeSitemap, + }, + '#sitemaps button[action=browse-sitemap-data]': { + click: this.sitemapListBrowseSitemapData, + }, + // @TODO move to tr + '#selector-tree tbody tr': { + click: this.showChildSelectors, + }, + '#selector-tree .breadcrumb a': { + click: this.treeNavigationshowSitemapSelectorList, + }, + '#selector-tree tr button[action=edit-selector]': { + click: this.editSelector, + }, + '#edit-selector select[name=type]': { + change: function() { + this.selectorTypeChanged(true); + }.bind(this), + }, + '#edit-selector button[action=save-selector]': { + click: this.saveSelector, + }, + '#edit-selector button[action=cancel-selector-editing]': { + click: this.cancelSelectorEditing, + }, + '#edit-selector #selectorId': { + keyup: this.updateSelectorParentListOnIdChange, + }, + '#selector-tree button[action=add-selector]': { + click: this.addSelector, + }, + '#selector-tree tr button[action=delete-selector]': { + click: this.deleteSelector, + }, + '#selector-tree tr button[action=preview-selector]': { + click: this.previewSelectorFromSelectorTree, + }, + '#selector-tree tr button[action=data-preview-selector]': { + click: this.previewSelectorDataFromSelectorTree, + }, + '#edit-selector button[action=select-selector]': { + click: this.selectSelector, + }, + '#edit-selector button[action=select-table-header-row-selector]': { + click: this.selectTableHeaderRowSelector, + }, + '#edit-selector button[action=refresh-header-row-selector]': { + click: this.refreshTableHeaderRowSelector, + }, + '#edit-selector button[action=select-table-data-row-selector]': { + click: this.selectTableDataRowSelector, + }, + '#edit-selector button[action=preview-selector]': { + click: this.previewSelector, + }, + '#edit-selector button[action=preview-click-element-selector]': { + click: this.previewClickElementSelector, + }, + '#edit-selector button[action=preview-table-row-selector]': { + click: this.previewTableRowSelector, + }, + '#edit-selector button[action=preview-selector-data]': { + click: this.previewSelectorDataFromSelectorEditing, + }, + }); + this.showSitemaps(); + }.bind(this) + ); + } + + clearState() { + this.state = { + // sitemap that is currently open + currentSitemap: null, + // selector ids that are shown in the navigation + editSitemapBreadcumbsSelectors: null, + currentParentSelectorId: null, + currentSelector: null, + }; + } + + setStateEditSitemap(sitemap) { + this.state.currentSitemap = sitemap; + this.state.editSitemapBreadcumbsSelectors = [{ id: '_root' }]; + this.state.currentParentSelectorId = '_root'; + } + + setActiveNavigationButton(navigationId) { + $('.nav .active').removeClass('active'); + $('#' + navigationId + '-nav-button') + .closest('li') + .addClass('active'); + + if (navigationId.match(/^sitemap-/)) { + $('#sitemap-nav-button').removeClass('disabled'); + $('#sitemap-nav-button') + .closest('li') + .addClass('active'); + $('#navbar-active-sitemap-id').text('(' + this.state.currentSitemap._id + ')'); + } else { + $('#sitemap-nav-button').addClass('disabled'); + $('#navbar-active-sitemap-id').text(''); + } + + if (navigationId.match(/^create-sitemap-/)) { + $('#create-sitemap-nav-button') + .closest('li') + .addClass('active'); + } + } + + /** + * Returns bootstrapValidator object for current form in viewport + */ + getFormValidator() { + return $('#viewport form').data('bootstrapValidator'); + } + + /** + * Returns whether current form in the viewport is valid + * @returns {Boolean} + */ + isValidForm() { + let validator = this.getFormValidator(); + + //validator.validate(); + // validate method calls submit which is not needed in this case. + for (let field in validator.options.fields) { + validator.validateField(field); + } + + return validator.isValid(); + } + + /** + * Add validation to sitemap creation or editing form + */ + initSitemapValidation() { + $('#viewport form').bootstrapValidator({ + fields: { + _id: { + validators: { + notEmpty: { + message: 'The sitemap id is required and cannot be empty', + }, + stringLength: { + min: 3, + message: 'The sitemap id should be at least 3 characters long', + }, + regexp: { + regexp: /^[a-z][a-z0-9_\$\(\)\+\-/]+$/, + message: 'Only lowercase characters (a-z), digits (0-9), or any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.', + }, + // placeholder for sitemap id existance validation + callback: { + message: 'Sitemap with this id already exists', + callback: function() { + return true; + }, + }, + }, + }, + startUrls: { + validators: { + notEmpty: { + message: 'The start URL is required and cannot be empty', + }, + callback: { + message: 'The start URLs are not valid. Please use "," as a seperator.', + callback: function(value) { + return Sitemap.validateStartUrls(value.split(',')); + }, + }, + }, + }, + model: { + validators: { + callback: { + callback: function(value) { + if (!value) { + return { + message: 'Empty value is possible model', + valid: true, + }; + } + try { + return Model.validateModel(JSON.parse(value)); + } catch (e) { + return { + valid: false, + message: 'JSON is not valid', + }; + } + }.bind(this), + }, + }, + }, + }, + }); + } + + showCreateSitemap() { + this.setActiveNavigationButton('create-sitemap-create'); + let sitemapForm = ich.SitemapCreate(); + $('#viewport').html(sitemapForm); + this.initSitemapValidation(); + + // //XXX quickFix for new sitemap creation bug + let validator = this.getFormValidator(); + validator.updateStatus('model', 'VALID', 'callback'); + + return true; + } + + initImportSitemapValidation() { + $('#viewport form').bootstrapValidator({ + fields: { + _id: { + validators: { + stringLength: { + min: 3, + message: 'The sitemap id should be at least 3 characters long', + }, + regexp: { + regexp: /^[a-z][a-z0-9_\$\(\)\+\-/]+$/, + message: 'Only lowercase characters (a-z), digits (0-9), or any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.', + }, + // placeholder for sitemap id existance validation + callback: { + message: 'Sitemap with this id already exists', + callback: function(value, validator) { + validator.revalidateField('sitemapJSON'); + return true; + }.bind(this), + }, + }, + }, + sitemapJSON: { + validators: { + notEmpty: { + message: 'Sitemap JSON is required and cannot be empty', + }, + callback: { + message: 'JSON is not valid', + callback: function(value, validator) { + try { + let sitemap = JSON.parse(value); + + let renameId = $('#viewport form [name="_id"]').val(); + if (!renameId) { + if (!sitemap.hasOwnProperty('_id')) { + return { + valid: false, + message: 'The sitemap id is required and cannot be empty', + }; + } + if (sitemap._id.length < 3) { + return { + valid: false, + message: 'The sitemap id should be at least 3 characters long', + }; + } + if (!sitemap._id.match('^[a-z][a-z0-9_\\$\\(\\)\\+\\-/]+$')) { + return { + valid: false, + message: + 'Only lowercase characters (a-z), digits (0-9), or any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.', + }; + } + } + + //check for start urls + if (!sitemap.hasOwnProperty('startUrls')) { + return { + valid: false, + message: 'The start URL is required and cannot be empty', + }; + } + if (!Sitemap.validateStartUrls(sitemap.startUrls)) { + return { + valid: false, + message: 'The start URLs are not valid', + }; + } + + let result = Model.validateModel(sitemap.model); + if (!result.valid) { + return result; + } + } catch (e) { + return { + valid: false, + message: 'JSON is not valid', + }; + } + return { + message: 'Valid sitemap', + valid: true, + }; + }.bind(this), + }, + }, + }, + }, + }); + } + + showImportSitemapPanel() { + this.setActiveNavigationButton('create-sitemap-import'); + let sitemapForm = ich.SitemapImport(); + $('#viewport').html(sitemapForm); + this.initImportSitemapValidation(); + return true; + } + + showSitemapExportPanel() { + this.setActiveNavigationButton('sitemap-export'); + let sitemap = this.state.currentSitemap; + let sitemapJSON = sitemap.exportSitemap(); + let sitemapExportForm = ich.SitemapExport({ + sitemapJSON: sitemapJSON, + }); + $('#viewport').html(sitemapExportForm); + return true; + } + + showSitemaps() { + this.clearState(); + this.setActiveNavigationButton('sitemaps'); + + this.store.getAllSitemaps().then(function(sitemaps) { + var $sitemapListPanel = ich.SitemapList(); + sitemaps.forEach(function(sitemap) { + var $sitemap = ich.SitemapListItem(sitemap); + $sitemap.data('sitemap', sitemap); + $sitemapListPanel.find('tbody').append($sitemap); + }); + $('#viewport').html($sitemapListPanel); + }); + } + + getSitemapFromMetadataForm() { + let id = $('#viewport form input[name=_id]').val(); + let $startUrlInputs = $('#viewport form .input-start-url'); + let startUrls = $startUrlInputs + .val() + .split(',') + .map(item => item.trim()); + let model = $('#viewport .input-model').val(); + if (model) { + return { + id: id, + startUrls: startUrls, + model: JSON.parse(model), + }; + } else { + return { + id: id, + startUrls: startUrls, + }; + } + } + + createSitemap() { + // cancel submit if invalid form + if (!this.isValidForm()) { + return false; + } + + let sitemapData = this.getSitemapFromMetadataForm(); + + // check whether sitemap with this id already exist + this.store.sitemapExists(sitemapData.id).then( + function(sitemapExists) { + if (sitemapExists) { + let validator = this.getFormValidator(); + validator.updateStatus('_id', 'INVALID', 'callback'); + } else { + let sitemap = new Sitemap({ + _id: sitemapData.id, + startUrls: sitemapData.startUrls, + model: sitemapData.model, + selectors: [], + }); + this.store.createSitemap(sitemap).then( + function(sitemap) { + this._editSitemap(sitemap, ['_root']); + }.bind(this, sitemap) + ); + } + }.bind(this) + ); + } + + importSitemap() { + // cancel submit if invalid form + if (!this.isValidForm()) { + return false; + } + + // load data from form + let sitemapJSON = $('[name=sitemapJSON]').val(); + let id = $('input[name=_id]').val(); + let sitemap = new Sitemap(); + sitemap.importSitemap(sitemapJSON); + if (id.length) { + sitemap._id = id; + } + // check whether sitemap with this id already exist + this.store.sitemapExists(sitemap._id).then( + function(sitemapExists) { + if (sitemapExists) { + let validator = this.getFormValidator(); + validator.updateStatus('_id', 'INVALID', 'callback'); + } else { + this.store.createSitemap(sitemap).then( + function(sitemap) { + this._editSitemap(sitemap, ['_root']); + }.bind(this) + ); + } + }.bind(this) + ); + } + + editSitemapMetadata(button) { + this.setActiveNavigationButton('sitemap-edit-metadata'); + + let sitemap = this.state.currentSitemap; + if (sitemap.model) { + sitemap.model = JSON.stringify(sitemap.model, null, 4); + } + let $sitemapMetadataForm = ich.SitemapEditMetadata(sitemap); + $('#viewport').html($sitemapMetadataForm); + this.initSitemapValidation(); + + return true; + } + + editSitemapMetadataSave(button) { + let sitemap = this.state.currentSitemap; + let sitemapData = this.getSitemapFromMetadataForm(); + + // cancel submit if invalid form + if (!this.isValidForm()) { + return false; + } + + // check whether sitemap with this id already exist + this.store.sitemapExists(sitemapData.id).then( + function(sitemapExists) { + if (sitemap._id !== sitemapData.id && sitemapExists) { + let validator = this.getFormValidator(); + validator.updateStatus('_id', 'INVALID', 'callback'); + return; + } + + // change data + sitemap.startUrls = sitemapData.startUrls; + sitemap.model = sitemapData.model; + + // just change sitemaps url + if (sitemapData.id === sitemap._id) { + this.store.saveSitemap(sitemap).then( + function(sitemap) { + this.showSitemapSelectorList(); + }.bind(this) + ); + } + // id changed. we need to delete the old one and create a new one + else { + let newSitemap = new Sitemap(sitemap); + let oldSitemap = sitemap; + newSitemap._id = sitemapData.id; + if (newSitemap._rev) { + delete newSitemap._rev; + } + this.store.createSitemap(newSitemap).then( + function(newSitemap) { + this.store.deleteSitemap(oldSitemap).then( + function() { + this.state.currentSitemap = newSitemap; + this.showSitemapSelectorList(); + }.bind(this) + ); + }.bind(this) + ); + } + }.bind(this) + ); + } + + /** + * Callback when sitemap edit button is clicked in sitemap grid + */ + editSitemap(tr) { + let sitemap = $(tr).data('sitemap'); + this._editSitemap(sitemap); + } + + _editSitemap(sitemap) { + this.setStateEditSitemap(sitemap); + this.setActiveNavigationButton('sitemap'); + + this.showSitemapSelectorList(); + } + + showSitemapSelectorList() { + this.setActiveNavigationButton('sitemap-selector-list'); + + let sitemap = this.state.currentSitemap; + let parentSelectors = this.state.editSitemapBreadcumbsSelectors; + let parentSelectorId = this.state.currentParentSelectorId; + + let $selectorListPanel = ich.SelectorList({ + parentSelectors: parentSelectors, + }); + let selectors = sitemap.getDirectChildSelectors(parentSelectorId); + selectors.forEach(function(selector) { + let $selector = ich.SelectorListItem(selector); + $selector.data('selector', selector); + $selectorListPanel.find('tbody').append($selector); + }); + $('#viewport').html($selectorListPanel); + + return true; + } + + showSitemapSelectorGraph() { + this.setActiveNavigationButton('sitemap-selector-graph'); + let sitemap = this.state.currentSitemap; + let $selectorGraphPanel = ich.SitemapSelectorGraph(); + $('#viewport').html($selectorGraphPanel); + let graphDiv = $('#selector-graph')[0]; + let graph = new SelectorGraphv2(sitemap); + graph.draw(graphDiv, $(document).width(), 200); + return true; + } + + showChildSelectors(tr) { + let selector = $(tr).data('selector'); + let parentSelectors = this.state.editSitemapBreadcumbsSelectors; + this.state.currentParentSelectorId = selector.id; + parentSelectors.push(selector); + + this.showSitemapSelectorList(); + } + + treeNavigationshowSitemapSelectorList(button) { + let parentSelectors = this.state.editSitemapBreadcumbsSelectors; + let controller = this; + $('#selector-tree .breadcrumb li a').each(function(i, parentSelectorButton) { + if (parentSelectorButton === button) { + parentSelectors.splice(i + 1); + controller.state.currentParentSelectorId = parentSelectors[i].id; + } + }); + this.showSitemapSelectorList(); + } + + initSelectorValidation() { + return $('#viewport form').bootstrapValidator({ + fields: { + id: { + validators: { + notEmpty: { + message: 'Sitemap id required and cannot be empty', + }, + stringLength: { + min: 3, + message: 'The sitemap id should be atleast 3 characters long', + }, + regexp: { + regexp: /^[^_].*$/, + message: 'Selector id cannot start with an underscore _', + }, + }, + }, + selector: { + validators: { + notEmpty: { + message: 'Selector is required and cannot be empty', + }, + }, + }, + regex: { + validators: { + callback: { + message: 'JavaScript does not support regular expressions that can match 0 characters.', + callback: function(value, validator) { + // allow no regex + if (!value) { + return true; + } + + try { + let matches = ''.match(new RegExp(value)); + return !(matches !== null && matches[0] === ''); + } catch (e) { + return false; + } + }, + }, + }, + }, + regexgroup: { + validators: { + callback: { + message: 'Regex group must be numeric', + callback: function(value, validator) { + if (value === '') { + return true; + } + return !isNaN(value); + }, + }, + }, + }, + clickElementSelector: { + validators: { + notEmpty: { + message: 'Click selector is required and cannot be empty', + }, + }, + }, + tableHeaderRowSelector: { + validators: { + notEmpty: { + message: 'Header row selector is required and cannot be empty', + }, + }, + }, + tableDataRowSelector: { + validators: { + notEmpty: { + message: 'Data row selector is required and cannot be empty', + }, + }, + }, + delay: { + validators: { + numeric: { + message: 'Delay must be numeric', + }, + }, + }, + paginationLimit: { + validators: { + numeric: { + message: 'Pagination limit must be numeric or empty', + }, + callback: { + message: 'Pagination limit must be 1 at least', + callback: function(value, validator) { + if (!value) { + return true; + } + return value >= 1; + }, + }, + }, + }, + parentSelectors: { + validators: { + notEmpty: { + message: 'You must choose at least one parent selector', + }, + callback: { + message: 'Cannot handle recursive element selectors', + callback: function(value, validator, $field) { + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + return !sitemap.selectors.hasRecursiveElementSelectors(); + }.bind(this), + }, + }, + }, + }, + }); + } + + editSelector(button) { + let selector = $(button) + .closest('tr') + .data('selector'); + this._editSelector(selector); + } + + updateSelectorParentListOnIdChange() { + let selector = this.getCurrentlyEditedSelector(); + $('.currently-edited') + .val(selector.id) + .text(selector.id); + } + + _editSelector(selector) { + let sitemap = this.state.currentSitemap; + let selectorIds = sitemap.getPossibleParentSelectorIds(); + + let $editSelectorForm = ich.SelectorEdit({ + selector: selector, + selectorIds: selectorIds, + selectorTypes: this.selectorTypes, + }); + $('#viewport').html($editSelectorForm); + + //TODO move this check to Model class + let data = []; + let idInData = false; + if (sitemap.model) { + for (let field of sitemap.model) { + data.push(field); + if (field.field_name === selector.id) { + idInData = true; + } + } + } + if (!idInData && selector.id) { + data.push({ field: '', entity: '', field_name: selector.id }); + } + + $('#selectorId').flexdatalist({ + init: this.initSelectorValidation(), + textProperty: '{field_name}', + valueProperty: 'field_name', + data: data, + searchIn: ['entity', 'field'], + visibleProperties: ['entity', 'field'], + groupBy: 'entity', + searchContain: true, + noResultsText: '', + minLength: 1, + }); + + // mark initially opened selector as currently edited + $('#edit-selector #parentSelectors option').each(function(i, element) { + if ($(element).val() === selector.id) { + $(element).addClass('currently-edited'); + } + }); + + // set clickType + if (selector.clickType) { + $editSelectorForm.find('[name=clickType]').val(selector.clickType); + } + + // set clickElementUniquenessType + if (selector.clickElementUniquenessType) { + $editSelectorForm.find('[name=clickElementUniquenessType]').val(selector.clickElementUniquenessType); + } + + // handle selects seperately + $editSelectorForm.find('[name=type]').val(selector.type); + selector.parentSelectors.forEach(function(parentSelectorId) { + $editSelectorForm.find("#parentSelectors [value='" + parentSelectorId + "']").attr('selected', 'selected'); + }); + + this.state.currentSelector = selector; + this.selectorTypeChanged(false); + } + + selectorTypeChanged(changeTrigger) { + // let type = $('#edit-selector select[name=type]').val(); + // add this selector to possible parent selector + let selector = this.getCurrentlyEditedSelector(); + // this.state.currentSelector = selector; + let features = selector.getFeatures(); + $('#edit-selector .feature').hide(); + features.forEach(function(feature) { + $('#edit-selector .feature-' + feature).show(); + }); + + if (changeTrigger && selector.type === 'SelectorLink') { + $('#edit-selector [name=extractAttribute]').val('href'); + } + + if (selector.canHaveChildSelectors()) { + if ($('#edit-selector #parentSelectors .currently-edited').length === 0) { + let $option = $(''); + $option.text(selector.id).val(selector.id); + $('#edit-selector #parentSelectors').append($option); + } + } + // remove if type doesn't allow to have child selectors + else { + $('#edit-selector #parentSelectors .currently-edited').remove(); + } + } + + saveSelector(button) { + let sitemap = this.state.currentSitemap; + let selector = this.state.currentSelector; + let newSelector = this.getCurrentlyEditedSelector(); + + // cancel submit if invalid form + if (!this.isValidForm()) { + return false; + } + + // cancel possible element selection + this.contentScript.removeCurrentContentSelector().done( + function() { + sitemap.updateSelector(selector, newSelector); + this.store.saveSitemap(sitemap).then( + function() { + this.showSitemapSelectorList(); + }.bind(this) + ); + }.bind(this) + ); + } + + /** + * Get selector from selector editing form + */ + getCurrentlyEditedSelector() { + let id = $('#edit-selector [name=id]').val(); + let selectorsSelector = $('#edit-selector [name=selector]').val(); + let tableDataRowSelector = $('#edit-selector [name=tableDataRowSelector]').val(); + let tableHeaderRowSelector = $('#edit-selector [name=tableHeaderRowSelector]').val(); + let tableAddMissingColumns = $('#edit-selector [name=tableAddMissingColumns]').is(':checked'); + let verticalTable = $('#edit-selector [name=verticalTable]').is(':checked'); + let clickElementSelector = $('#edit-selector [name=clickElementSelector]').val(); + let type = $('#edit-selector [name=type]').val(); + let clickElementUniquenessType = $('#edit-selector [name=clickElementUniquenessType]').val(); + let clickType = $('#edit-selector [name=clickType]').val(); + let paginationLimit = $('#edit-selector [name=paginationLimit]').val(); + let discardInitialElements = $('#edit-selector [name=discardInitialElements]').is(':checked'); + let multiple = $('#edit-selector [name=multiple]').is(':checked'); + let downloadImage = $('#edit-selector [name=downloadImage]').is(':checked'); + let downloadDocument = $('#edit-selector [name=downloadDocument]').is(':checked'); + let clickPopup = $('#edit-selector [name=clickPopup]').is(':checked'); + let delay = $('#edit-selector [name=delay]').val(); + let extractAttribute = $('#edit-selector [name=extractAttribute]').val(); + let extractStyle = $('#edit-selector [name=extractStyle]').val(); + let value = $('#edit-selector [name=value]').val(); + let parentSelectors = $('#edit-selector [name=parentSelectors]').val(); + let columns = []; + let $columnHeaders = $('#edit-selector .column-header'); + let $columnNames = $('#edit-selector .column-name'); + let $columnExtracts = $('#edit-selector .column-extract'); + let stringReplacement = { + replaceString: $('#edit-selector [name=replaceString]').val(), + replacementString: $('#edit-selector [name=replacementString]').val(), + }; + let textmanipulation = { + removeHtml: $('#edit-selector [name=removeHtml]').is(':checked'), + trimText: $('#edit-selector [name=trimText]').is(':checked'), + replaceText: $('#edit-selector [name=replaceText]').val(), + replacementText: $('#edit-selector [name=replacementText]').val(), + textPrefix: $('#edit-selector [name=textPrefix]').val(), + textSuffix: $('#edit-selector [name=textSuffix]').val(), + regex: $('#edit-selector [name=regex]').val(), + regexgroup: $('#edit-selector [name=regexgroup]').val(), + }; + + $columnHeaders.each(function(i) { + let header = $($columnHeaders[i]).val(); + let name = $($columnNames[i]).val(); + let extract = $($columnExtracts[i]).is(':checked'); + columns.push({ + header: header, + name: name, + extract: extract, + }); + }); + + return SelectorList.createSelector({ + id: id, + selector: selectorsSelector, + tableHeaderRowSelector: tableHeaderRowSelector, + tableAddMissingColumns: tableAddMissingColumns, + verticalTable: verticalTable, + tableDataRowSelector: tableDataRowSelector, + clickElementSelector: clickElementSelector, + clickElementUniquenessType: clickElementUniquenessType, + clickType: clickType, + paginationLimit: paginationLimit, + discardInitialElements: discardInitialElements, + type: type, + multiple: multiple, + downloadImage: downloadImage, + downloadDocument: downloadDocument, + clickPopup: clickPopup, + extractAttribute: extractAttribute, + extractStyle: extractStyle, + value: value, + parentSelectors: parentSelectors, + columns: columns, + delay: delay, + textmanipulation: textmanipulation, + stringReplacement: stringReplacement, + }); + } + + /** + * @returns {Sitemap|*} Cloned Sitemap with currently edited selector + */ + getCurrentlyEditedSelectorSitemap() { + let sitemap = this.state.currentSitemap.clone(); + let selector = sitemap.getSelectorById(this.state.currentSelector.id); + let newSelector = this.getCurrentlyEditedSelector(); + sitemap.updateSelector(selector, newSelector); + return sitemap; + } + + cancelSelectorEditing(button) { + // cancel possible element selection + this.contentScript.removeCurrentContentSelector().done( + function() { + this.showSitemapSelectorList(); + }.bind(this) + ); + } + + addSelector() { + let parentSelectorId = this.state.currentParentSelectorId; + let sitemap = this.state.currentSitemap; + + let selector = SelectorList.createSelector({ + parentSelectors: [parentSelectorId], + type: 'SelectorText', + multiple: false, + }); + + this._editSelector(selector, sitemap); + } + + deleteSelector(button) { + let sitemap = this.state.currentSitemap; + let selector = $(button) + .closest('tr') + .data('selector'); + sitemap.deleteSelector(selector); + + this.store.saveSitemap(sitemap).then( + function() { + this.showSitemapSelectorList(); + }.bind(this) + ); + } + + deleteSitemap(button) { + let sitemap = $(button) + .closest('tr') + .data('sitemap'); + let controller = this; + this.store.deleteSitemap(sitemap).then(function() { + controller.showSitemaps(); + }); + } + + initScrapeSitemapConfigValidation() { + $('#viewport form').bootstrapValidator({ + fields: { + requestInterval: { + validators: { + notEmpty: { + message: 'The request interval is required and cannot be empty', + }, + numeric: { + message: 'The request interval must be numeric', + }, + callback: { + message: 'The request interval must be atleast 2000 milliseconds', + callback: function(value, validator) { + return value >= 2000; + }, + }, + }, + }, + requestIntervalRandomness: { + validators: { + notEmpty: { + message: 'The request interval randomness is required and cannot be empty', + }, + numeric: { + message: 'The request interval randomness must be numeric', + }, + }, + }, + pageLoadDelay: { + validators: { + notEmpty: { + message: 'The page load delay is required and cannot be empty', + }, + numeric: { + message: 'The page laod delay must be numeric', + }, + callback: { + message: 'The page load delay must be atleast 500 milliseconds', + callback: function(value, validator) { + return value >= 500; + }, + }, + }, + }, + }, + }); + } + + showScrapeSitemapConfigPanel() { + this.setActiveNavigationButton('sitemap-scrape'); + let scrapeConfigPanel = ich.SitemapScrapeConfig(); + $('#viewport').html(scrapeConfigPanel); + this.initScrapeSitemapConfigValidation(); + return true; + } + + scrapeSitemap() { + if (!this.isValidForm()) { + return false; + } + + let requestInterval = $('input[name=requestInterval]').val(); + let pageLoadDelay = $('input[name=pageLoadDelay]').val(); + let intervalRandomness = $('input[name=requestIntervalRandomness]').val(); + + let sitemap = this.state.currentSitemap; + let request = { + scrapeSitemap: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + requestInterval: requestInterval, + pageLoadDelay: pageLoadDelay, + requestIntervalRandomness: intervalRandomness, + }; + + // show sitemap scraping panel + this.getFormValidator().destroy(); + $('.scraping-in-progress').removeClass('hide'); + $('#submit-scrape-sitemap') + .closest('.form-group') + .hide(); + $('#scrape-sitemap-config input').prop('disabled', true); + + browser.runtime.sendMessage(request).then( + function(selectors) { + // table selector can dynamically add columns + // replace current selector (columns) with the dynamicly created once + sitemap.selectors = new SelectorList(selectors); + this.browseSitemapData(); + }.bind(this) + ); + return false; + } + + sitemapListBrowseSitemapData(button) { + let sitemap = $(button) + .closest('tr') + .data('sitemap'); + this.setStateEditSitemap(sitemap); + this.browseSitemapData(); + } + + browseSitemapData() { + this.setActiveNavigationButton('sitemap-browse'); + let sitemap = this.state.currentSitemap; + this.store.getSitemapData(sitemap).then( + function(data) { + let dataColumns = sitemap.getDataColumns(); + + let dataPanel = ich.SitemapBrowseData({ + columns: dataColumns, + }); + $('#viewport').html(dataPanel); + + // display data + // Doing this the long way so there aren't xss vulnerubilites + // while working with data or with the selector titles + let $tbody = $('#sitemap-data tbody'); + data.forEach(function(row) { + let $tr = $(''); + dataColumns.forEach(function(column) { + let $td = $(''); + let cellData = row[column]; + if (typeof cellData === 'object') { + cellData = JSON.stringify(cellData); + } + $td.text(cellData); + $tr.append($td); + }); + $tbody.append($tr); + }); + }.bind(this) + ); + + return true; + } + + showSitemapExportDataCsvPanel() { + this.setActiveNavigationButton('sitemap-export-data-csv'); + + let sitemap = this.state.currentSitemap; + let exportPanel = ich.SitemapExportDataCSV(sitemap); + $('#viewport').html(exportPanel); + + $('.result').hide(); + $('.download-button').hide(); + + // generate data + $('#generate-csv').click( + function() { + $('.result').show(); + $('.download-button').hide(); + + let options = { + delimiter: $('#delimiter').val(), + newline: $('#newline').prop('checked'), + containBom: $('#utf-bom').prop('checked'), + }; + + this.store.getSitemapData(sitemap).then( + function(data) { + let blob = sitemap.getDataExportCsvBlob(data, options); + let button_a = $('.download-button a'); + button_a.attr('href', window.URL.createObjectURL(blob)); + button_a.attr('download', sitemap._id + '.csv'); + $('.download-button').show(); + $('.result').hide(); + }.bind(this) + ); + }.bind(this) + ); + + return true; + } + + selectSelector(button) { + let input = $(button) + .closest('.form-group') + .find('input.selector-value'); + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); + + let deferredSelector = this.contentScript.selectSelector({ + parentCSSSelector: parentCSSSelector, + allowedElements: selector.getItemCSSSelector(), + }); + + deferredSelector.done( + function(result) { + $(input).val(result.CSSSelector); + + // update validation for selector field + let validator = this.getFormValidator(); + validator.revalidateField(input); + + // @TODO how could this be encapsulated? + // update header row, data row selectors after selecting the table. selectors are updated based on tables + // inner html + if (selector.type === 'SelectorTable') { + this.getSelectorHTML().done( + function(html) { + let verticalTable = this.getCurrentlyEditedSelector().verticalTable; + let tableHeaderRowSelector = SelectorTable.getTableHeaderRowSelectorFromTableHTML(html, verticalTable); + let tableDataRowSelector = SelectorTable.getTableDataRowSelectorFromTableHTML(html, verticalTable); + $('input[name=tableHeaderRowSelector]').val(tableHeaderRowSelector); + $('input[name=tableDataRowSelector]').val(tableDataRowSelector); + + let headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(tableHeaderRowSelector, html, verticalTable); + this.renderTableHeaderColumns(headerColumns); + }.bind(this) + ); + } + }.bind(this) + ); + } + + getCurrentStateParentSelectorIds() { + let parentSelectorIds = this.state.editSitemapBreadcumbsSelectors.map(function(selector) { + return selector.id; + }); + + return parentSelectorIds; + } + + refreshTableHeaderRowSelector(button) { + let input = $(button) + .closest('.form-group') + .find('input.selector-value'); + let value = input.val(); + + this.getSelectorHTML().done( + function(html) { + // let verticalTable = this.getCurrentlyEditedSelector().verticalTable; + // let tableHeaderRowSelector = SelectorTable.getTableHeaderRowSelectorFromTableHTML(html, verticalTable); + // let tableDataRowSelector = SelectorTable.getTableDataRowSelectorFromTableHTML(html, verticalTable); + // $('input[name=tableHeaderRowSelector]').val(tableHeaderRowSelector); + // $('input[name=tableDataRowSelector]').val(tableDataRowSelector); + let headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(value, html); + this.renderTableHeaderColumns(headerColumns); + }.bind(this) + ); + + let validator = this.getFormValidator(); + validator.revalidateField(input); + } + + selectTableHeaderRowSelector(button) { + let input = $(button) + .closest('.form-group') + .find('input.selector-value'); + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); + + let deferredSelector = this.contentScript.selectSelector({ + parentCSSSelector: parentCSSSelector, + allowedElements: 'tr', + }); + + deferredSelector.done( + function(result) { + let tableHeaderRowSelector = result.CSSSelector; + $(input).val(tableHeaderRowSelector); + + this.getSelectorHTML().done( + function(html) { + let headerColumns = SelectorTable.getTableHeaderColumnsFromHTML(tableHeaderRowSelector, html); + this.renderTableHeaderColumns(headerColumns); + }.bind(this) + ); + + // update validation for selector field + let validator = this.getFormValidator(); + validator.revalidateField(input); + }.bind(this) + ); + } + + selectTableDataRowSelector(button) { + let input = $(button) + .closest('.form-group') + .find('input.selector-value'); + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); + + let deferredSelector = this.contentScript.selectSelector({ + parentCSSSelector: parentCSSSelector, + allowedElements: 'tr', + }); + + deferredSelector.done( + function(result) { + $(input).val(result.CSSSelector); + + // update validation for selector field + let validator = this.getFormValidator(); + validator.revalidateField(input); + }.bind(this) + ); + } + + /** + * update table selector column editing fields + */ + renderTableHeaderColumns(headerColumns) { + // reset previous columns + let $tbody = $('.feature-columns table tbody'); + $tbody.html(''); + headerColumns.forEach(function(column) { + let $row = ich.SelectorEditTableColumn(column); + $tbody.append($row); + }); + } + + /** + * Returns HTML that the current selector would select + */ + getSelectorHTML() { + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let CSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); + let deferredHTML = this.contentScript.getHTML({ CSSSelector: CSSSelector }); + + return deferredHTML; + } + + previewSelector(button) { + if (!$(button).hasClass('preview')) { + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); + let deferredSelectorPreview = this.contentScript.previewSelector({ + parentCSSSelector: parentCSSSelector, + elementCSSSelector: selector.selector, + }); + + deferredSelectorPreview.done(function() { + $(button).addClass('preview'); + }); + } else { + this.contentScript.removeCurrentContentSelector(); + $(button).removeClass('preview'); + } + } + + previewClickElementSelector(button) { + if (!$(button).hasClass('preview')) { + let sitemap = this.state.currentSitemap; + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); + + let deferredSelectorPreview = this.contentScript.previewSelector({ + parentCSSSelector: parentCSSSelector, + elementCSSSelector: selector.clickElementSelector, + }); + + deferredSelectorPreview.done(function() { + $(button).addClass('preview'); + }); + } else { + this.contentScript.removeCurrentContentSelector(); + $(button).removeClass('preview'); + } + } + + previewTableRowSelector(button) { + if (!$(button).hasClass('preview')) { + let sitemap = this.getCurrentlyEditedSelectorSitemap(); + let selector = this.getCurrentlyEditedSelector(); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getCSSSelectorWithinOnePage(selector.id, currentStateParentSelectorIds); + let rowSelector = $(button) + .closest('.form-group') + .find('input') + .val(); + + let deferredSelectorPreview = this.contentScript.previewSelector({ + parentCSSSelector: parentCSSSelector, + elementCSSSelector: rowSelector, + }); + + deferredSelectorPreview.done(function() { + $(button).addClass('preview'); + }); + } else { + this.contentScript.removeCurrentContentSelector(); + $(button).removeClass('preview'); + } + } + + previewSelectorFromSelectorTree(button) { + if (!$(button).hasClass('preview')) { + let sitemap = this.state.currentSitemap; + let selector = $(button) + .closest('tr') + .data('selector'); + let currentStateParentSelectorIds = this.getCurrentStateParentSelectorIds(); + let parentCSSSelector = sitemap.selectors.getParentCSSSelectorWithinOnePage(currentStateParentSelectorIds); + let deferredSelectorPreview = this.contentScript.previewSelector({ + parentCSSSelector: parentCSSSelector, + elementCSSSelector: selector.selector, + }); + + deferredSelectorPreview.done(function() { + $(button).addClass('preview'); + }); + } else { + this.contentScript.removeCurrentContentSelector(); + $(button).removeClass('preview'); + } + } + + previewSelectorDataFromSelectorTree(button) { + let sitemap = this.state.currentSitemap; + let selector = $(button) + .closest('tr') + .data('selector'); + this.previewSelectorData(sitemap, selector.id); + } + + previewSelectorDataFromSelectorEditing() { + let sitemap = this.state.currentSitemap.clone(); + let selector = sitemap.getSelectorById(this.state.currentSelector.id); + let newSelector = this.getCurrentlyEditedSelector(); + sitemap.updateSelector(selector, newSelector); + this.previewSelectorData(sitemap, newSelector.id); + } + + /** + * Returns a list of selector ids that the user has opened + * @returns {Array} + */ + getStateParentSelectorIds() { + let parentSelectorIds = []; + this.state.editSitemapBreadcumbsSelectors.forEach(function(selector) { + parentSelectorIds.push(selector.id); + }); + return parentSelectorIds; + } + + previewSelectorData(sitemap, selectorId) { + // data preview will be base on how the selector tree is opened + let parentSelectorIds = this.getStateParentSelectorIds(); + + let request = { + previewSelectorData: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + parentSelectorIds: parentSelectorIds, + selectorId: selectorId, + }; + browser.runtime.sendMessage(request).then(function(response) { + if (response.length === 0) { + return; + } + let dataColumns = Object.keys(response[0]); + + console.log(dataColumns); + + let $dataPreviewPanel = ich.DataPreview({ + columns: dataColumns, + }); + $('#viewport').append($dataPreviewPanel); + $dataPreviewPanel.modal('show'); + // display data + // Doing this the long way so there aren't xss vulnerubilites + // while working with data or with the selector titles + let $tbody = $('tbody', $dataPreviewPanel); + response.forEach(function(row) { + let $tr = $(''); + dataColumns.forEach(function(column) { + let $td = $(''); + let cellData = row[column]; + if (typeof cellData === 'object') { + cellData = JSON.stringify(cellData); + } + $td.text(cellData); + $tr.append($td); + }); + $tbody.append($tr); + }); + + let windowHeight = $(window).height(); + + $('.data-preview-modal .modal-body').height(windowHeight - 130); + + // remove modal from dom after it is closed + $dataPreviewPanel.on('hidden.bs.modal', function() { + $(this).remove(); + }); + }); + } +} diff --git a/src/scripts/DataExtractor.js b/src/scripts/DataExtractor.js new file mode 100644 index 00000000..f860f780 --- /dev/null +++ b/src/scripts/DataExtractor.js @@ -0,0 +1,328 @@ +import Sitemap from './Sitemap'; +import SelectorList from './SelectorList'; +import '../libs/jquery.whencallsequentially'; +import 'sugar'; + +export default class DataExtractor { + constructor(options) { + if (options.sitemap instanceof Sitemap) { + this.sitemap = options.sitemap; + } else { + this.sitemap = new Sitemap(options.sitemap); + } + + this.parentSelectorId = options.parentSelectorId; + this.parentElement = options.parentElement || $('html')[0]; + } + + /** + * Returns a list of independent selector lists. follow=true splits selectors in trees. + * Two side by side type=multiple selectors split trees. + */ + findSelectorTrees() { + return this._findSelectorTrees(this.parentSelectorId, new SelectorList()); + } + + /** + * the selector cannot return multiple records and it also cannot create new jobs. Also all of its child selectors + * must have the same features + * @param selector + * @returns {boolean} + */ + selectorIsCommonToAllTrees(selector) { + // selectors which return mutiple items cannot be common to all + // selectors + if (selector.willReturnMultipleRecords()) { + return false; + } + + // Link selectors which will follow to a new page also cannot be common + // to all selectors + if (selector.canCreateNewJobs() && this.sitemap.getDirectChildSelectors(selector.id).length > 0) { + return false; + } + + // also all child selectors must have the same features + let childSelectors = this.sitemap.getAllSelectors(selector.id); + for (let i in childSelectors) { + let childSelector = childSelectors[i]; + if (!this.selectorIsCommonToAllTrees(childSelector)) { + return false; + } + } + return true; + } + + getSelectorsCommonToAllTrees(parentSelectorId) { + let commonSelectors = []; + let childSelectors = this.sitemap.getDirectChildSelectors(parentSelectorId); + + childSelectors.forEach( + function(childSelector) { + if (this.selectorIsCommonToAllTrees(childSelector)) { + commonSelectors.push(childSelector); + // also add all child selectors which. Child selectors were also checked + + let selectorChildSelectors = this.sitemap.getAllSelectors(childSelector.id); + selectorChildSelectors.forEach(function(selector) { + if (commonSelectors.indexOf(selector) === -1) { + commonSelectors.push(selector); + } + }); + } + }.bind(this) + ); + + return commonSelectors; + } + + _findSelectorTrees(parentSelectorId, commonSelectorsFromParent) { + let commonSelectors = commonSelectorsFromParent.concat(this.getSelectorsCommonToAllTrees(parentSelectorId)); + + // find selectors that will be making a selector tree + let selectorTrees = []; + let childSelectors = this.sitemap.getDirectChildSelectors(parentSelectorId); + childSelectors.forEach( + function(selector) { + if (!this.selectorIsCommonToAllTrees(selector)) { + // this selector will be making a new selector tree. But this selector might contain some child + // selectors that are making more trees so here should be a some kind of seperation for that + if (!selector.canHaveLocalChildSelectors()) { + let selectorTree = commonSelectors.concat([selector]); + selectorTrees.push(selectorTree); + } else { + // find selector tree within this selector + let commonSelectorsFromParent = commonSelectors.concat([selector]); + let childSelectorTrees = this._findSelectorTrees(selector.id, commonSelectorsFromParent); + selectorTrees = selectorTrees.concat(childSelectorTrees); + } + } + }.bind(this) + ); + + // it there were not any selectors that make a separate tree then all common selectors make up a single selector tree + if (selectorTrees.length === 0) { + return [commonSelectors]; + } else { + return selectorTrees; + } + } + + getSelectorTreeCommonData(selectors, parentSelectorId, parentElement) { + let childSelectors = selectors.getDirectChildSelectors(parentSelectorId); + let deferredDataCalls = []; + childSelectors.forEach( + function(selector) { + if (!selectors.willReturnMultipleRecords(selector.id)) { + deferredDataCalls.push(this.getSelectorCommonData.bind(this, selectors, selector, parentElement)); + } + }.bind(this) + ); + + let deferredResponse = $.Deferred(); + $.whenCallSequentially(deferredDataCalls).done(function(responses) { + let commonData = {}; + responses.forEach(function(data) { + commonData = Object.merge(commonData, data); + }); + deferredResponse.resolve(commonData); + }); + + return deferredResponse; + } + + getSelectorCommonData(selectors, selector, parentElement) { + let d = $.Deferred(); + let deferredData = selector.getData(parentElement); + deferredData.done( + function(data) { + if (selector.willReturnElements()) { + let newParentElement = data[0]; + let deferredChildCommonData = this.getSelectorTreeCommonData(selectors, selector.id, newParentElement); + deferredChildCommonData.done(function(data) { + d.resolve(data); + }); + } else { + d.resolve(data[0]); + } + }.bind(this) + ); + + return d; + } + + /** + * Returns all data records for a selector that can return multiple records + */ + getMultiSelectorData(selectors, selector, parentElement, commonData) { + let deferredResponse = $.Deferred(); + + // if the selector is not an Element selector then its fetched data is the result. + if (!selector.willReturnElements()) { + let deferredData = selector.getData(parentElement); + deferredData.done( + function(selectorData) { + let newCommonData = Object.clone(commonData, true); + let resultData = []; + + selectorData.forEach( + function(record) { + Object.merge(record, newCommonData, true); + resultData.push(record); + }.bind(this) + ); + + deferredResponse.resolve(resultData); + }.bind(this) + ); + } + + // handle situation when this selector is an elementSelector + let deferredData = selector.getData(parentElement); + deferredData.done( + function(selectorData) { + let deferredDataCalls = []; + + selectorData.forEach( + function(element) { + let newCommonData = Object.clone(commonData, true); + let childRecordDeferredCall = this.getSelectorTreeData.bind(this, selectors, selector.id, element, newCommonData); + deferredDataCalls.push(childRecordDeferredCall); + }.bind(this) + ); + + $.whenCallSequentially(deferredDataCalls).done( + function(responses) { + let resultData = []; + responses.forEach(function(childRecordList) { + childRecordList.forEach(function(childRecord) { + let rec = {}; + Object.merge(rec, childRecord, true); + resultData.push(rec); + }); + }); + deferredResponse.resolve(resultData); + }.bind(this) + ); + }.bind(this) + ); + + return deferredResponse; + } + + getSelectorTreeData(selectors, parentSelectorId, parentElement, commonData) { + let childSelectors = selectors.getDirectChildSelectors(parentSelectorId); + let childCommonDataDeferred = this.getSelectorTreeCommonData(selectors, parentSelectorId, parentElement); + let deferredResponse = $.Deferred(); + + childCommonDataDeferred.done( + function(childCommonData) { + commonData = Object.merge(commonData, childCommonData); + + let dataDeferredCalls = []; + + childSelectors.forEach( + function(selector) { + if (selectors.willReturnMultipleRecords(selector.id)) { + let newCommonData = Object.clone(commonData, true); + let dataDeferredCall = this.getMultiSelectorData.bind(this, selectors, selector, parentElement, newCommonData); + dataDeferredCalls.push(dataDeferredCall); + } + }.bind(this) + ); + + // merge all data records together + $.whenCallSequentially(dataDeferredCalls).done( + function(responses) { + let resultData = []; + responses.forEach(function(childRecords) { + childRecords.forEach(function(childRecord) { + let rec = {}; + Object.merge(rec, childRecord, true); + resultData.push(rec); + }); + }); + + if (resultData.length === 0) { + // If there are no multi record groups then return common data. + // In a case where common data is empty return nothing. + if (Object.keys(commonData).length === 0) { + deferredResponse.resolve([]); + } else { + deferredResponse.resolve([commonData]); + } + } else { + deferredResponse.resolve(resultData); + } + }.bind(this) + ); + }.bind(this) + ); + + return deferredResponse; + } + + getData() { + let selectorTrees = this.findSelectorTrees(); + let dataDeferredCalls = []; + + selectorTrees.forEach( + function(selectorTree) { + let deferredTreeDataCall = this.getSelectorTreeData.bind(this, selectorTree, this.parentSelectorId, this.parentElement, {}); + dataDeferredCalls.push(deferredTreeDataCall); + }.bind(this) + ); + + let responseDeferred = $.Deferred(); + $.whenCallSequentially(dataDeferredCalls).done( + function(responses) { + let results = []; + responses.forEach( + function(dataResults) { + results = results.concat(dataResults); + }.bind(this) + ); + responseDeferred.resolve(results); + }.bind(this) + ); + return responseDeferred; + } + + getSingleSelectorData(parentSelectorIds, selectorId) { + // to fetch only single selectors data we will create a sitemap that only contains this selector, his + // parents and all child selectors + let sitemap = this.sitemap; + let selector = this.sitemap.selectors.getSelector(selectorId); + let childSelectors = sitemap.selectors.getAllSelectors(selectorId); + let parentSelectors = []; + for (let i = parentSelectorIds.length - 1; i >= 0; i--) { + let id = parentSelectorIds[i]; + if (id === '_root') break; + let parentSelector = this.sitemap.selectors.getSelector(id); + parentSelectors.push(parentSelector); + } + + // merge all needed selectors together + let selectors = parentSelectors.concat(childSelectors); + selectors.push(selector); + sitemap.selectors = new SelectorList(selectors); + + let parentSelectorId; + // find the parent that leaded to the page where required selector is being used + for (let i = parentSelectorIds.length - 1; i >= 0; i--) { + let id = parentSelectorIds[i]; + if (id === '_root') { + parentSelectorId = id; + break; + } + let parentSelector = this.sitemap.selectors.getSelector(parentSelectorIds[i]); + if (!parentSelector.willReturnElements()) { + parentSelectorId = id; + break; + } + } + this.parentSelectorId = parentSelectorId; + + return this.getData(); + } +} diff --git a/extension/scripts/DateUtils/DatePatternSupport.js b/src/scripts/DateUtils/DatePatternSupport.js similarity index 56% rename from extension/scripts/DateUtils/DatePatternSupport.js rename to src/scripts/DateUtils/DatePatternSupport.js index ad3192b8..c4d55f93 100644 --- a/extension/scripts/DateUtils/DatePatternSupport.js +++ b/src/scripts/DateUtils/DatePatternSupport.js @@ -1,29 +1,28 @@ -/* +/* * Support for "[date<01.01.2016>]" pattern - * + * * @author © Denis Bakhtenkov denis.bakhtenkov@gmail.com * @version 2016 */ +import DateRoller from './DateRoller'; +import SimpleDateFormatter from './SimpleDateFormatter'; -/* global DateRoller */ - -var DatePatternSupport = { +export default class DatePatternSupport { /** - * + * * @param {String} startUrl * @returns {Array} */ - expandUrl: function (startUrl) { - + static expandUrl(startUrl) { function nowSupport(d) { switch (d) { - case "now": + case 'now': return df.format(new Date()); - case "yesterday": + case 'yesterday': var date = new Date(); date.setDate(date.getDate() - 1); return df.format(new Date(date)); - case "tomorrow": + case 'tomorrow': var date = new Date(); date.setDate(date.getDate() + 1); return df.format(new Date(date)); @@ -32,27 +31,26 @@ var DatePatternSupport = { } } - var startUrls = startUrl; + let startUrls = startUrl; // single start url if (startUrl.push === undefined) { startUrls = [startUrls]; } - var df; - var urls = []; - startUrls.forEach(function (startUrl) { - var re = /^(.*?)\[date<(.*)><(.*)><(.*)>\](.*)$/; - var matches = startUrl.match(re); + let df; + let urls = []; + startUrls.forEach(function(startUrl) { + let re = /^(.*?)\[date<(.*)><(.*)><(.*)>\](.*)$/; + let matches = startUrl.match(re); if (matches) { df = new SimpleDateFormatter(matches[2]); - var startDate = df.parse(nowSupport(matches[3])); - var endDate = df.parse(nowSupport(matches[4])); + let startDate = df.parse(nowSupport(matches[3])); + let endDate = df.parse(nowSupport(matches[4])); - var roller = DateRoller.days(startDate, endDate); - roller.forEach(function (date) { + let roller = DateRoller.days(startDate, endDate); + roller.forEach(function(date) { urls.push(matches[1] + df.format(date) + matches[5]); }); - } else { urls.push(startUrl); } @@ -60,5 +58,4 @@ var DatePatternSupport = { return urls; } - -}; \ No newline at end of file +} diff --git a/extension/scripts/DateUtils/DateRoller.js b/src/scripts/DateUtils/DateRoller.js similarity index 74% rename from extension/scripts/DateUtils/DateRoller.js rename to src/scripts/DateUtils/DateRoller.js index ff22df9e..d51d986e 100644 --- a/extension/scripts/DateUtils/DateRoller.js +++ b/src/scripts/DateUtils/DateRoller.js @@ -1,34 +1,32 @@ -/* +/* * Iterator from first day to second - * + * * @author © Denis Bakhtenkov denis.bakhtenkov@gmail.com * @version 2016 */ -var DateRoller = { - +export default class DateRoller { /** - * + * * @param {Date} from * @param {Date} to * @returns {Array} all days between From and To */ - days: function (from, to) { - + static days(from, to) { /** - * + * * @param {Date} first * @param {Date} second * @returns {Number} */ function compareDays(first, second) { - var day = 24 * 60 * 60 * 1000; + let day = 24 * 60 * 60 * 1000; return Math.floor(first / day) - Math.floor(second / day); } - var res = []; - var curDate = new Date(from); - var step = from <= to ? 1 : -1; + let res = []; + let curDate = new Date(from); + let step = from <= to ? 1 : -1; do { res.push(new Date(curDate)); @@ -37,5 +35,4 @@ var DateRoller = { return res; } - -}; \ No newline at end of file +} diff --git a/src/scripts/DateUtils/SimpleDateFormatter.js b/src/scripts/DateUtils/SimpleDateFormatter.js new file mode 100644 index 00000000..8fbab5c0 --- /dev/null +++ b/src/scripts/DateUtils/SimpleDateFormatter.js @@ -0,0 +1,111 @@ +/** + * Formatter for Date, parse and format with pattern + * + * @author © Denis Bakhtenkov denis.bakhtenkov@gmail.com + * @version 2016 + * @param {String} pattern + * default is dd.MM.yyyy + * @returns {SimpleDateFormatter} + */ +export default class SimpleDateFormatter { + constructor(pattern) { + this.pattern = pattern || 'dd.MM.yyyy'; + this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + } + + /** + * Return pattern + * @returns {String} + */ + getPattern() { + return this.pattern; + } + + /** + * 'dd.MM.yyyy hh:mm:ss' + * @param {Date} date + * @returns {String} + */ + format(date) { + /** + * Adding left 'zero' if value's length less than digits + * @param {Number} value + * @param {Number} digits + * @returns {String} + */ + function lzero(value, digits) { + digits = digits || 2; + var result = value.toString(); + while (result.length < digits) { + result = '0' + result; + } + return result; + } + + var variants = { + yyyy: date.getFullYear(), + yy: lzero(date.getFullYear() % 100), + MMM: this.months[date.getMonth()], + MM: lzero(date.getMonth() + 1), + dd: lzero(date.getDate()), + hh: lzero(date.getHours()), + mm: lzero(date.getMinutes()), + sss: lzero(date.getMilliseconds(), 3), + ss: lzero(date.getSeconds()), + }; + + var format = this.pattern; + + for (var i in variants) { + format = format.replace(i, variants[i]); + } + + return format; + } + + /** + * 16.06.2016 + * dd.MM.yyyy + * + * @param {String} string + * @returns {Date} + */ + parse(string) { + var date = new Date(0); + var pat = this.pattern; + var input = string; + var variants = { + yyyy: 'date.setFullYear(parseInt(value));', + yy: 'date.setYear(parseInt(value) + 2000);', + MMM: 'date.setMonth(parseInt(value));', + MM: 'date.setMonth(parseInt(value) - 1);', + dd: 'date.setDate(parseInt(value));', + hh: 'date.setHours(parseInt(value));', + mm: 'date.setMinutes(parseInt(value));', + sss: 'date.setMilliseconds(parseInt(value));', + ss: 'date.setSeconds(parseInt(value));', + }; + + for (var i in variants) { + var pos = pat.search(i); + if (pos !== -1) { + var value = input.substr(pos, i.length); + input = input.substring(0, pos) + input.substring(pos + i.length); + pat = pat.substring(0, pos) + pat.substring(pos + i.length); + if (i === 'MMM') { + for (var j in this.months) { + if (value === this.months[j]) { + value = j; + eval(variants[i]); + break; + } + } + } else { + eval(variants[i]); + } + } + } + + return date; + } +} diff --git a/src/scripts/ElementQuery.js b/src/scripts/ElementQuery.js new file mode 100644 index 00000000..eb4dbb9c --- /dev/null +++ b/src/scripts/ElementQuery.js @@ -0,0 +1,55 @@ +function getSelectorParts(CSSSelector) { + let selectors = CSSSelector.split(/(,|".*?"|'.*?'|\(.*?\))/); + + let resultSelectors = []; + let currentSelector = ''; + selectors.forEach(function(selector) { + if (selector === ',') { + if (currentSelector.trim().length) { + resultSelectors.push(currentSelector.trim()); + } + currentSelector = ''; + } else { + currentSelector += selector; + } + }); + if (currentSelector.trim().length) { + resultSelectors.push(currentSelector.trim()); + } + + return resultSelectors; +} + +/** + * Element selector. Uses jQuery as base and adds some more features + * @param parentElement + * @param selector + */ +export default function ElementQuery(CSSSelector, parentElement) { + CSSSelector = CSSSelector || ''; + + let selectedElements = []; + + let addElement = function(element) { + if (selectedElements.indexOf(element) === -1) { + selectedElements.push(element); + } + }; + + let selectorParts = getSelectorParts(CSSSelector); + selectorParts.forEach(function(selector) { + // handle special case when parent is selected + if (selector === '_parent_') { + $(parentElement).each(function(i, element) { + addElement(element); + }); + } else { + let elements = $(selector, parentElement); + elements.each(function(i, element) { + addElement(element); + }); + } + }); + + return selectedElements; +} diff --git a/src/scripts/Job.js b/src/scripts/Job.js new file mode 100644 index 00000000..e67b03c3 --- /dev/null +++ b/src/scripts/Job.js @@ -0,0 +1,87 @@ +export default class Job { + constructor(url, parentSelector, scraper, parentJob, baseData) { + if (parentJob !== undefined) { + this.url = this.combineUrls(parentJob.url, url); + } else { + this.url = url; + } + this.parentSelector = parentSelector; + this.scraper = scraper; + this.dataItems = []; + this.baseData = baseData || {}; + } + + combineUrls(parentUrl, childUrl) { + let urlMatcher = new RegExp( + '(https?://)?([a-z0-9\\-\\.]+\\.[a-z0-9\\-]+(:\\d+)?|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d+)?)?(\\/[^\\?]*\\/|\\/)?([^\\?]*)?(\\?.*)?', + 'i' + ); + + let parentMatches = parentUrl.match(urlMatcher); + let childMatches = childUrl.match(urlMatcher); + + // special case for urls like this: ?a=1 or like-this/ + if (childMatches[1] === undefined && childMatches[2] === undefined && childMatches[5] === undefined && childMatches[6] === undefined) { + let url = parentMatches[1] + parentMatches[2] + parentMatches[5] + parentMatches[6] + childMatches[7]; + return url; + } + + if (childMatches[1] === undefined) { + childMatches[1] = parentMatches[1]; + } + if (childMatches[2] === undefined) { + childMatches[2] = parentMatches[2]; + } + if (childMatches[5] === undefined) { + if (parentMatches[5] === undefined) { + childMatches[5] = '/'; + } else { + childMatches[5] = parentMatches[5]; + } + } + + if (childMatches[6] === undefined) { + childMatches[6] = ''; + } + if (childMatches[7] === undefined) { + childMatches[7] = ''; + } + + return childMatches[1] + childMatches[2] + childMatches[5] + childMatches[6] + childMatches[7]; + } + + execute(popupBrowser, callback, scope) { + let sitemap = this.scraper.sitemap; + let job = this; + popupBrowser.fetchData( + this.url, + sitemap, + this.parentSelector, + function(results) { + // merge data with data from initialization + for (let i in results) { + let result = results[i]; + for (let key in this.baseData) { + if (!(key in result)) { + result[key] = this.baseData[key]; + } + } + this.dataItems.push(result); + } + + if (sitemap) { + // table selector can dynamically add columns (addMissingColumns Feature) + sitemap.selectors = this.scraper.sitemap.selectors; + } + + console.log(job); + callback(job); + }.bind(this), + this + ); + } + + getResults() { + return this.dataItems; + } +} diff --git a/src/scripts/Model.js b/src/scripts/Model.js new file mode 100644 index 00000000..8dfd1f9d --- /dev/null +++ b/src/scripts/Model.js @@ -0,0 +1,28 @@ +export default class Model { + static validateModel(model) { + if (model === undefined) { + return { + message: 'Empty value is possible model', + valid: true, + }; + } + if (!Array.isArray(model)) { + return { + valid: false, + message: 'JSON must be array', + }; + } + for (let field_rule of model) { + if (!('entity' in field_rule) || !('field' in field_rule) || !('field_name' in field_rule)) { + return { + valid: false, + message: 'Each object in JSON array must contain keys entity, field, field_name.', + }; + } + } + return { + message: 'Valid model', + valid: true, + }; + } +} diff --git a/extension/scripts/Queue.js b/src/scripts/Queue.js similarity index 61% rename from extension/scripts/Queue.js rename to src/scripts/Queue.js index a45065b8..f5b9274e 100644 --- a/extension/scripts/Queue.js +++ b/src/scripts/Queue.js @@ -1,26 +1,24 @@ -var Queue = function () { - this.jobs = []; - this.scrapedUrls = {}; -}; - -Queue.prototype = { +export default class Queue { + constructor() { + this.jobs = []; + this.scrapedUrls = {}; + } /** * Returns false if page is already scraped * @param job * @returns {boolean} */ - add: function (job) { - + add(job) { if (this.canBeAdded(job)) { this.jobs.push(job); this._setUrlScraped(job.url); return true; } return false; - }, + } - canBeAdded: function (job) { + canBeAdded(job) { if (this.isScraped(job.url)) { return false; } @@ -30,28 +28,26 @@ Queue.prototype = { return false; } return true; - }, + } - getQueueSize: function () { + getQueueSize() { return this.jobs.length; - }, + } - isScraped: function (url) { - return (this.scrapedUrls[url] !== undefined); - }, + isScraped(url) { + return this.scrapedUrls[url] !== undefined; + } - _setUrlScraped: function (url) { + _setUrlScraped(url) { this.scrapedUrls[url] = true; - }, - - getNextJob: function () { + } + getNextJob() { // @TODO test this if (this.getQueueSize() > 0) { return this.jobs.pop(); - } - else { + } else { return false; } } -}; \ No newline at end of file +} diff --git a/src/scripts/Scraper.js b/src/scripts/Scraper.js new file mode 100644 index 00000000..d61b967e --- /dev/null +++ b/src/scripts/Scraper.js @@ -0,0 +1,213 @@ +import Job from './Job'; +import '../libs/jquery.whencallsequentially'; + +export default class Scraper { + /** + * Scraping delay between two page opening requests + */ + constructor(options) { + this.queue = options.queue; + this.sitemap = options.sitemap; + this.store = options.store; + this.browser = options.browser; + this.resultWriter = null; // db instance for scraped data writing + this.requestInterval = 2000; + this._timeNextScrapeAvailable = 0; + this.requestInterval = parseInt(options.requestInterval); + this.requestIntervalRandomness = parseInt(options.requestIntervalRandomness); + this.pageLoadDelay = parseInt(options.pageLoadDelay); + } + + initFirstJobs() { + var urls = this.sitemap.getStartUrls(); + + urls.forEach( + function(url) { + var firstJob = new Job(url, '_root', this); + this.queue.add(firstJob); + }.bind(this) + ); + } + + run(executionCallback) { + var scraper = this; + + // callback when scraping is finished + this.executionCallback = executionCallback; + + this.initFirstJobs(); + + this.store.initSitemapDataDb(this.sitemap._id).then(function(resultWriter) { + scraper.resultWriter = resultWriter; + scraper._run(); + }); + } + + recordCanHaveChildJobs(record) { + if (record._follow === undefined) { + return false; + } + + var selectorId = record._followSelectorId; + var childSelectors = this.sitemap.getDirectChildSelectors(selectorId); + if (childSelectors.length === 0) { + return false; + } else { + return true; + } + } + + getFileFilename(url) { + var parts = url.split('/'); + var filename = parts[parts.length - 1]; + filename = filename.replace(/\?/g, ''); + if (filename.length > 130) { + filename = filename.substr(0, 130); + } + return filename; + } + + /** + * Save files for user if the records contains them + * @param record + */ + saveFile(record) { + let deferredResponse = $.Deferred(); + let deferredFileStoreCalls = []; + let prefixLength = '_fileBase64-'.length; + + for (let attr in record) { + if (attr.substr(0, prefixLength) === '_fileBase64-') { + var selectorId = attr.substring(prefixLength, attr.length); + deferredFileStoreCalls.push( + function(selectorId) { + var fileBase64 = record['_fileBase64-' + selectorId]; + var documentFilename = record['_filename' + selectorId]; + + var deferredDownloadDone = $.Deferred(); + var deferredBlob = Base64.base64ToBlob(fileBase64, record['_fileMimeType-' + selectorId]); + + delete record['_fileMimeType-' + selectorId]; + delete record['_fileBase64-' + selectorId]; + delete record['_filename' + selectorId]; + + deferredBlob.done( + function(blob) { + var downloadUrl = window.URL.createObjectURL(blob); + var fileSavePath = this.sitemap._id + '/' + selectorId + '/' + documentFilename; + + // download file using chrome api + var downloadRequest = { + url: downloadUrl, + filename: fileSavePath, + }; + + // wait for the download to finish + chrome.downloads.download(downloadRequest, function(downloadId) { + var cbDownloaded = function(downloadItem) { + if (downloadItem.id === downloadId && downloadItem.state) { + if (downloadItem.state.current === 'complete') { + deferredDownloadDone.resolve(); + chrome.downloads.onChanged.removeListener(cbDownloaded); + } else if (downloadItem.state.current === 'interrupted') { + deferredDownloadDone.reject('download failed'); + chrome.downloads.onChanged.removeListener(cbDownloaded); + } + } + }; + + chrome.downloads.onChanged.addListener(cbDownloaded); + }); + }.bind(this) + ); + + return deferredDownloadDone.promise(); + }.bind(this, selectorId) + ); + } + } + + $.whenCallSequentially(deferredFileStoreCalls).done(function() { + deferredResponse.resolve(); + }); + + return deferredResponse.promise(); + } + + // @TODO remove recursion and add an iterative way to run these jobs. + _run() { + var job = this.queue.getNextJob(); + if (job === false) { + console.log('Scraper execution is finished'); + this.executionCallback(); + return; + } + + job.execute( + this.browser, + function(job) { + var scrapedRecords = []; + var deferredDatamanipulations = []; + + var records = job.getResults(); + records.forEach( + function(record) { + //var record = JSON.parse(JSON.stringify(rec)); + + deferredDatamanipulations.push(this.saveFile.bind(this, record)); + + // @TODO refactor job exstraction to a seperate method + if (this.recordCanHaveChildJobs(record)) { + // var followSelectorId = record._followSelectorId; + var followURL = record['_follow']; + var followSelectorId = record['_followSelectorId']; + delete record['_follow']; + delete record['_followSelectorId']; + var newJob = new Job(followURL, followSelectorId, this, job, record); + if (this.queue.canBeAdded(newJob)) { + this.queue.add(newJob); + } + // store already scraped links + else { + console.log('Ignoring next'); + console.log(record); + // scrapedRecords.push(record); + } + } else { + if (record._follow !== undefined) { + delete record['_follow']; + delete record['_followSelectorId']; + } + scrapedRecords.push(record); + } + }.bind(this) + ); + + $.whenCallSequentially(deferredDatamanipulations).done( + function() { + this.store.saveSitemap(this.sitemap, function() {}); + this.resultWriter.writeDocs( + scrapedRecords, + function() { + var now = new Date().getTime(); + // delay next job if needed + this._timeNextScrapeAvailable = now + this.requestInterval + Math.random() * this.requestIntervalRandomness; + if (now >= this._timeNextScrapeAvailable) { + this._run(); + } else { + var delay = this._timeNextScrapeAvailable - now; + setTimeout( + function() { + this._run(); + }.bind(this), + delay + ); + } + }.bind(this) + ); + }.bind(this) + ); + }.bind(this) + ); + } +} diff --git a/src/scripts/Selector.js b/src/scripts/Selector.js new file mode 100644 index 00000000..f893a0d2 --- /dev/null +++ b/src/scripts/Selector.js @@ -0,0 +1,313 @@ +import ElementQuery from './ElementQuery'; + +export default class Selector { + constructor(selector) { + // if (selector.type === 'ConstantValue'){ + // this = new ConstantValue(selector); + // } + // this.updateData(['id', 'type', 'selector', 'parentSelectors']); + // this.initType(); + } + + /** + * Update current selector configuration + * @param data + */ + updateData(data, features) { + let allowedKeys = ['id', 'type', 'selector', 'parentSelectors']; + //XXX no need in information from window + allowedKeys = allowedKeys.concat(features); + + // update data + for (let key in data) { + if (allowedKeys.indexOf(key) !== -1 || typeof data[key] === 'function') { + this[key] = data[key]; + } + } + + // remove values that are not needed for this type of selector + for (let key in this) { + if (allowedKeys.indexOf(key) === -1 && typeof this[key] !== 'function') { + delete this[key]; + } + } + } + + /** + * override objects methods based on seletor type + */ + initType() { + // if (window[this.type] === undefined) { + // throw 'Selector type not defined ' + this.type; + // } + // + // // overrides objects methods + // for (let i in window[this.type]) { + // this[i] = window[this.type][i]; + // } + } + + /** + * Manipulates return data from selector. + * @param data + */ + manipulateData(data) { + let regex = function(content, regex, regexgroup) { + try { + content = $.trim(content); + let matches = content.match(new RegExp(regex, 'gm')), + groupDefined = regexgroup !== ''; + + regexgroup = groupDefined ? regexgroup : 0; + + if (matches !== null) { + return matches[regexgroup]; + } else { + return ''; + } + } catch (e) { + console.log('%c Skipping regular expression: ' + e.message, 'background: red; color: white;'); + } + }; + + let removeHtml = function(content) { + return $('
') + .html(content) + .text(); + }; + + let trimText = function(content) { + return content.trim(); + }; + + let replaceText = function(content, replaceText, replacementText) { + let replace; + try { + let regex = new RegExp(replaceText, 'gm'); + replace = regex.test(content) ? regex : replaceText; + } catch (e) { + replace = replaceText; + } + + return content.replace(replace, replacementText); + }; + + let textPrefix = function(content, prefix) { + return (content = prefix + content); + }; + + let textSuffix = function(content, suffix) { + return (content += suffix); + }; + + $(data).each( + function(i, element) { + let content = element[this.id], + isString = typeof content === 'string' || content instanceof String, + isUnderlyingString = !isString && $(content).text() !== '', + isArray = Array.isArray(content), + isTextmManipulationDefined = typeof this.textmanipulation != 'undefined' && this.textmanipulation !== '', + textManipulationAvailable = (isString || isUnderlyingString) && isTextmManipulationDefined; + + if (textManipulationAvailable) { + content = isString ? content : $(content).text(); + + // use key in object since unit tests might not define each property + let keys = []; + for (let key in this.textmanipulation) { + if (!this.textmanipulation.hasOwnProperty(key)) { + continue; + } + keys.push(key); + } + + function propertyIsAvailable(key) { + return keys.indexOf(key) >= 0; + } + + if (propertyIsAvailable('regex')) { + let group = this.textmanipulation.regexgroup; + let value = this.textmanipulation.regex; + group = typeof group != 'undefined' ? group : ''; + if (value !== '') { + content = regex(content, value, group); + } + } + + if (propertyIsAvailable('removeHtml')) { + if (this.textmanipulation.removeHtml) { + content = removeHtml(content); + } + } + + if (propertyIsAvailable('trimText')) { + if (this.textmanipulation.trimText) { + content = trimText(content); + } + } + + if (propertyIsAvailable('replaceText')) { + let replacement = this.textmanipulation.replacementText; + replacement = typeof replacement != 'undefined' ? replacement : ''; + content = replaceText(content, this.textmanipulation.replaceText, replacement); + } + + if (propertyIsAvailable('textPrefix')) { + if (this.textmanipulation.textPrefix !== '') { + content = textPrefix(content, this.textmanipulation.textPrefix); + } + } + + if (propertyIsAvailable('textSuffix')) { + if (this.textmanipulation.textSuffix !== '') { + content = textSuffix(content, this.textmanipulation.textSuffix); + } + } + + element[this.id] = content; + } else if (isArray && isTextmManipulationDefined) { + element[this.id] = JSON.stringify(content); + this.manipulateData(element); + } + }.bind(this) + ); + } + + /** + * Is this selector configured to return multiple items? + * @returns {boolean} + */ + willReturnMultipleRecords() { + return this.canReturnMultipleRecords() && this.multiple; + } + + /** + * CSS selector which will be used for element selection + * @returns {string} + */ + getItemCSSSelector() { + return '*'; + } + + /** + * Check whether a selector is a paren selector of this selector + * @param selectorId + * @returns {boolean} + */ + hasParentSelector(selectorId) { + return this.parentSelectors.indexOf(selectorId) !== -1; + } + + removeParentSelector(selectorId) { + let index = this.parentSelectors.indexOf(selectorId); + if (index !== -1) { + this.parentSelectors.splice(index, 1); + } + } + + renameParentSelector(originalId, replacementId) { + if (this.hasParentSelector(originalId)) { + let pos = this.parentSelectors.indexOf(originalId); + this.parentSelectors.splice(pos, 1, replacementId); + } + } + + getDataElements(parentElement) { + let elements = ElementQuery(this.selector, parentElement); + if (this.multiple) { + return elements; + } else if (elements.length > 0) { + return [elements[0]]; + } else { + return []; + } + } + + stringReplace(url, stringReplacement) { + if (stringReplacement && stringReplacement.replaceString) { + let replace; + let replacement = stringReplacement.replacementString || ''; + try { + let regex = new RegExp(stringReplacement.replaceString, 'gm'); + replace = regex.test(url) ? regex : stringReplacement.replaceString; + } catch (e) { + replace = stringReplacement.replaceString; + } + + return url.replace(replace, replacement); + } else { + return url; + } + } + + getData(parentElement) { + let d = $.Deferred(); + let timeout = this.delay || 0; + + // this works much faster because $.whenCallSequentially isn't running next data extraction immediately + if (timeout === 0) { + let deferredData = this._getData(parentElement); + deferredData.done( + function(data) { + this.manipulateData(data); + d.resolve(data); + }.bind(this) + ); + } else { + setTimeout( + function() { + let deferredData = this._getData(parentElement); + deferredData.done( + function(data) { + this.manipulateData(data); + d.resolve(data); + }.bind(this) + ); + }.bind(this), + timeout + ); + } + + return d.promise(); + } + + getFilenameFromUrl(url) { + let parts = url.split('/'); + let filename = parts[parts.length - 1]; + filename = filename.replace(/\?/g, ''); + if (filename.length > 130) { + filename = filename.substr(0, 130); + } + return filename; + } + + downloadFileAsBase64(url) { + let deferredResponse = $.Deferred(); + let xhr = new XMLHttpRequest(); + let fileName = this.getFilenameFromUrl(url); + xhr.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200) { + let blob = this.response; + let mimeType = blob.type; + let deferredBlob = Base64.blobToBase64(blob); + + deferredBlob.done(function(fileBase64) { + deferredResponse.resolve({ + mimeType: mimeType, + fileBase64: fileBase64, + filename: fileName, + }); + }); + } else { + deferredResponse.reject(xhr.statusText); + } + } + }; + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.send(); + + return deferredResponse.promise(); + } +} diff --git a/src/scripts/Selector/ConstantValue.js b/src/scripts/Selector/ConstantValue.js new file mode 100644 index 00000000..1b816786 --- /dev/null +++ b/src/scripts/Selector/ConstantValue.js @@ -0,0 +1,45 @@ +import Selector from '../Selector'; + +export default class ConstantValue extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return false; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + let dfd = $.Deferred(); + let data = {}; + data[this.id] = this.value; + + dfd.resolve([data]); + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['value']; + } +} diff --git a/src/scripts/Selector/SelectorDocument.js b/src/scripts/Selector/SelectorDocument.js new file mode 100644 index 00000000..85131fd0 --- /dev/null +++ b/src/scripts/Selector/SelectorDocument.js @@ -0,0 +1,102 @@ +import Selector from '../Selector'; +import '../../libs/jquery.whencallsequentially'; + +export default class SelectorDocument extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var elements = this.getDataElements(parentElement); + + var dfd = $.Deferred(); + + // return empty record if not multiple type and no elements found + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id] = null; + dfd.resolve([data]); + return dfd; + } + + // extract links one by one + var deferredDataExtractionCalls = []; + $(elements).each( + function(k, element) { + deferredDataExtractionCalls.push( + function(element) { + var href = this.stringReplace(element.href, this.stringReplacement); + var deferredData = $.Deferred(); + var data = {}; + + data[this.id] = $(element).text(); + + data[this.id + '-href'] = href; + + if (!this.downloadDocument) { + deferredData.resolve(data); + } else if (href) { + var deferredFileBase64 = this.downloadFileAsBase64(href); + + deferredFileBase64 + .done( + function(base64Response) { + data['_fileBase64-' + this.id] = base64Response.fileBase64; + data['_fileMimeType-' + this.id] = base64Response.mimeType; + data['_filename' + this.id] = base64Response.filename; + + deferredData.resolve(data); + }.bind(this) + ) + .fail(function() { + deferredData.resolve(data); + }); + } else { + deferredData.resolve(data); + } + return deferredData.promise(); + }.bind(this, element) + ); + }.bind(this) + ); + + $.whenCallSequentially(deferredDataExtractionCalls).done(function(responses) { + var result = []; + responses.forEach(function(dataResult) { + result.push(dataResult); + }); + dfd.resolve(result); + }); + + return dfd.promise(); + } + + getDataColumns() { + return [this.id, this.id + '-href']; + } + + getFeatures() { + return ['selector', 'multiple', 'delay', 'downloadDocument', 'stringReplacement']; + } +} diff --git a/src/scripts/Selector/SelectorElement.js b/src/scripts/Selector/SelectorElement.js new file mode 100644 index 00000000..2a968079 --- /dev/null +++ b/src/scripts/Selector/SelectorElement.js @@ -0,0 +1,45 @@ +import Selector from '../Selector'; + +export default class SelectorElement extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return true; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return true; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + var elements = this.getDataElements(parentElement); + dfd.resolve(jQuery.makeArray(elements)); + + return dfd.promise(); + } + + getDataColumns() { + return []; + } + + getFeatures() { + return ['selector', 'multiple', 'delay']; + } +} diff --git a/src/scripts/Selector/SelectorElementAttribute.js b/src/scripts/Selector/SelectorElementAttribute.js new file mode 100644 index 00000000..a5fc66a2 --- /dev/null +++ b/src/scripts/Selector/SelectorElementAttribute.js @@ -0,0 +1,61 @@ +import Selector from '../Selector'; + +export default class SelectorElementAttribute extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + var elements = this.getDataElements(parentElement); + + var result = []; + $(elements).each( + function(k, element) { + var data = {}; + + data[this.id] = $(element).attr(this.extractAttribute); + result.push(data); + }.bind(this) + ); + + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id + '-src'] = null; + result.push(data); + } + dfd.resolve(result); + + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['selector', 'multiple', 'extractAttribute', 'delay', 'textmanipulation']; + } +} diff --git a/src/scripts/Selector/SelectorElementClick.js b/src/scripts/Selector/SelectorElementClick.js new file mode 100644 index 00000000..cbe1c768 --- /dev/null +++ b/src/scripts/Selector/SelectorElementClick.js @@ -0,0 +1,176 @@ +import Selector from '../Selector'; +import ElementQuery from '../ElementQuery'; +import UniqueElementList from '../UniqueElementList'; + +export default class SelectorElementClick extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return true; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return true; + } + + getClickElements(parentElement) { + return ElementQuery(this.clickElementSelector, parentElement); + } + + /** + * Check whether element is still reachable from html. Useful to check whether the element is removed from DOM. + * @param element + */ + isElementInHTML(element) { + return $(element).closest('html').length !== 0; + } + + getElementCSSSelector(element) { + let nthChild, prev; + for (nthChild = 1, prev = element.previousElementSibling; prev !== null; prev = prev.previousElementSibling, nthChild++) {} + let tagName = element.tagName.toLocaleLowerCase(); + let cssSelector = tagName + ':nth-child(' + nthChild + ')'; + + while (element.parentElement) { + element = element.parentElement; + let tagName = element.tagName.toLocaleLowerCase(); + if (tagName === 'body' || tagName === 'html') { + cssSelector = tagName + '>' + cssSelector; + } else { + for (nthChild = 1, prev = element.previousElementSibling; prev !== null; prev = prev.previousElementSibling, nthChild++) {} + cssSelector = tagName + ':nth-child(' + nthChild + ')>' + cssSelector; + } + } + + return cssSelector; + } + + triggerButtonClick(clickElement) { + let cssSelector = this.getElementCSSSelector(clickElement); + + // this function will trigger the click from browser land + let script = document.createElement('script'); + script.type = 'text/javascript'; + script.text = '' + '(function(){ ' + "let el = document.querySelectorAll('" + cssSelector + "')[0]; " + 'el.click(); ' + '})();'; + document.body.appendChild(script); + } + + getClickElementUniquenessType() { + if (this.clickElementUniquenessType === undefined) { + return 'uniqueText'; + } else { + return this.clickElementUniquenessType; + } + } + + _getData(parentElement) { + let paginationLimit = parseInt(this.paginationLimit); + let paginationCount = 1; + let delay = parseInt(this.delay) || 0; + let deferredResponse = $.Deferred(); + let foundElements = new UniqueElementList('uniqueHTMLText'); + let clickElements = this.getClickElements(parentElement); + let doneClickingElements = new UniqueElementList(this.getClickElementUniquenessType()); + + // add elements that are available before clicking + let elements = this.getDataElements(parentElement); + elements.forEach(foundElements.push.bind(foundElements)); + + // discard initial elements + if (this.discardInitialElements) { + foundElements = new UniqueElementList('uniqueText'); + } + + // no elements to click at the beginning + if (clickElements.length === 0) { + deferredResponse.resolve(foundElements); + return deferredResponse.promise(); + } + + // initial click and wait + let currentClickElement = clickElements[0]; + this.triggerButtonClick(currentClickElement); + let nextElementSelection = new Date().getTime() + delay; + + // infinitely scroll down and find all items + let interval = setInterval( + function() { + // find those click elements that are not in the black list + let allClickElements = this.getClickElements(parentElement); + clickElements = []; + allClickElements.forEach(function(element) { + if (!doneClickingElements.isAdded(element)) { + clickElements.push(element); + } + }); + + let now = new Date().getTime(); + // sleep. wait when to extract next elements + if (now < nextElementSelection) { + //console.log("wait"); + return; + } + + // add newly found elements to element foundElements array. + let elements = this.getDataElements(parentElement); + let addedAnElement = false; + elements.forEach(function(element) { + let added = foundElements.push(element); + if (added) { + addedAnElement = true; + } + }); + //console.log("added", addedAnElement); + + // no new elements found. Stop clicking this button + if (!addedAnElement) { + doneClickingElements.push(currentClickElement); + } + + // continue clicking and add delay, but if there is nothing + // more to click the finish + //console.log("total buttons", clickElements.length) + if (clickElements.length === 0 || paginationCount >= paginationLimit) { + clearInterval(interval); + deferredResponse.resolve(foundElements); + } else { + paginationCount++; + //console.log("click"); + currentClickElement = clickElements[0]; + // click on elements only once if the type is clickonce + if (this.clickType === 'clickOnce') { + doneClickingElements.push(currentClickElement); + } + this.triggerButtonClick(currentClickElement); + nextElementSelection = now + delay; + } + }.bind(this), + 50 + ); + + return deferredResponse.promise(); + } + + getDataColumns() { + return []; + } + + getFeatures() { + return ['selector', 'multiple', 'delay', 'clickElementSelector', 'clickType', 'discardInitialElements', 'clickElementUniquenessType', 'paginationLimit']; + } +} diff --git a/src/scripts/Selector/SelectorElementScroll.js b/src/scripts/Selector/SelectorElementScroll.js new file mode 100644 index 00000000..77c9c35a --- /dev/null +++ b/src/scripts/Selector/SelectorElementScroll.js @@ -0,0 +1,79 @@ +import Selector from '../Selector'; + +export default class SelectorElementScroll extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return true; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return true; + } + + scrollToBottom() { + window.scrollTo(0, document.body.scrollHeight); + } + + _getData(parentElement) { + let paginationLimit = parseInt(this.paginationLimit); + let paginationCount = 1; + let delay = parseInt(this.delay) || 0; + let deferredResponse = $.Deferred(); + let foundElements = []; + + // initially scroll down and wait + this.scrollToBottom(); + let nextElementSelection = new Date().getTime() + delay; + + // infinitely scroll down and find all items + let interval = setInterval( + function() { + let now = new Date().getTime(); + // sleep. wait when to extract next elements + if (now < nextElementSelection) { + return; + } + + let elements = this.getDataElements(parentElement); + // no new elements found or pagination limit + if (elements.length === foundElements.length || paginationCount >= paginationLimit) { + clearInterval(interval); + deferredResponse.resolve($.makeArray(elements)); + } else { + paginationCount++; + // continue scrolling and add delay + foundElements = elements; + this.scrollToBottom(); + nextElementSelection = now + delay; + } + }.bind(this), + 50 + ); + + return deferredResponse.promise(); + } + + getDataColumns() { + return []; + } + + getFeatures() { + return ['selector', 'multiple', 'delay', 'paginationLimit']; + } +} diff --git a/src/scripts/Selector/SelectorElementStyle.js b/src/scripts/Selector/SelectorElementStyle.js new file mode 100644 index 00000000..3adce920 --- /dev/null +++ b/src/scripts/Selector/SelectorElementStyle.js @@ -0,0 +1,59 @@ +import Selector from '../Selector'; + +export default class SelectorElementStyle extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + var elements = this.getDataElements(parentElement); + + var result = []; + $(elements).each( + function(k, element) { + var data = {}; + data[this.id] = $(element).css(this.extractStyle); + result.push(data); + }.bind(this) + ); + + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id + '-src'] = null; + result.push(data); + } + dfd.resolve(result); + + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['selector', 'multiple', 'extractStyle', 'delay', 'textmanipulation']; + } +} diff --git a/src/scripts/Selector/SelectorGroup.js b/src/scripts/Selector/SelectorGroup.js new file mode 100644 index 00000000..44ad031f --- /dev/null +++ b/src/scripts/Selector/SelectorGroup.js @@ -0,0 +1,68 @@ +import Selector from '../Selector'; + +export default class SelectorGroup extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return false; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + // cannot reuse this.getDataElements because it depends on *multiple* property + var elements = $(this.selector, parentElement); + + var records = []; + $(elements).each( + function(k, element) { + var data = {}; + + data[this.id] = $(element).text(); + + if (this.extractAttribute) { + data[this.id + '-' + this.extractAttribute] = $(element).attr(this.extractAttribute); + } + + if (this.extractStyle) { + data[this.id + '-' + this.extractStyle] = $(element).css(this.extractStyle); + } + + records.push(data); + }.bind(this) + ); + + var result = {}; + result[this.id] = records; + + dfd.resolve([result]); + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['selector', 'delay', 'extractAttribute', 'textmanipulation', 'extractStyle']; + } +} diff --git a/src/scripts/Selector/SelectorHTML.js b/src/scripts/Selector/SelectorHTML.js new file mode 100644 index 00000000..8aa33fad --- /dev/null +++ b/src/scripts/Selector/SelectorHTML.js @@ -0,0 +1,65 @@ +import Selector from '../Selector'; + +export default class SelectorHTML extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + var elements = this.getDataElements(parentElement); + + var result = []; + $(elements).each( + function(k, element) { + var data = {}; + var html = $(element).html(); + + // do something + + data[this.id] = html; + + result.push(data); + }.bind(this) + ); + + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id] = null; + result.push(data); + } + + dfd.resolve(result); + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['selector', 'multiple', 'textmanipulation', 'delay']; + } +} diff --git a/src/scripts/Selector/SelectorImage.js b/src/scripts/Selector/SelectorImage.js new file mode 100644 index 00000000..b2aaa6bc --- /dev/null +++ b/src/scripts/Selector/SelectorImage.js @@ -0,0 +1,108 @@ +import Selector from '../Selector'; +import '../../libs/jquery.whencallsequentially'; + +export default class SelectorImage extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + var elements = this.getDataElements(parentElement); + + var deferredDataCalls = []; + $(elements).each( + function(i, element) { + deferredDataCalls.push( + function() { + var deferredData = $.Deferred(), + data = {}; + + src = element.src; + + // get url from style + if (src == null) { + src = $(element).css('background-image'); + src = /^url\((['"]?)(.*)\1\)$/.exec(src); + src = src ? src[2] : ''; + } + + src = this.stringReplace(src, this.stringReplacement); + + data[this.id + '-src'] = src; + + // download image if required + if (!this.downloadImage) { + deferredData.resolve(data); + } else { + var deferredFileBase64 = this.downloadFileAsBase64(src); + deferredFileBase64 + .done( + function(imageResponse) { + data['_fileBase64-' + this.id] = imageResponse.fileBase64; + data['_fileMimeType-' + this.id] = imageResponse.mimeType; + data['_filename' + this.id] = imageResponse.filename; + + deferredData.resolve(data); + }.bind(this) + ) + .fail(function() { + // failed to download image continue. + // @TODO handle errror + deferredData.resolve(data); + }); + } + + return deferredData.promise(); + }.bind(this) + ); + }.bind(this) + ); + + $.whenCallSequentially(deferredDataCalls).done(function(dataResults) { + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id + '-src'] = null; + dataResults.push(data); + } + + dfd.resolve(dataResults); + }); + + return dfd.promise(); + } + + getDataColumns() { + return [this.id + '-src']; + } + + getFeatures() { + return ['selector', 'multiple', 'delay', 'downloadImage', 'stringReplacement']; + } + + getItemCSSSelector() { + return ['img', 'div']; + } +} diff --git a/src/scripts/Selector/SelectorInputValue.js b/src/scripts/Selector/SelectorInputValue.js new file mode 100644 index 00000000..b30cf0f9 --- /dev/null +++ b/src/scripts/Selector/SelectorInputValue.js @@ -0,0 +1,56 @@ +import Selector from '../Selector'; + +export default class SelectorInputValue extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return false; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return true; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var dfd = $.Deferred(); + + var elements = this.getDataElements(parentElement); + + var result = []; + $(elements).each( + function(k, element) { + $(element).val(this.value); + }.bind(this) + ); + + var data = {}; + data[this.id] = this.value; + result.push(data); + + dfd.resolve(result); + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['value', 'selector']; + } +} diff --git a/src/scripts/Selector/SelectorLink.js b/src/scripts/Selector/SelectorLink.js new file mode 100644 index 00000000..6309fc1a --- /dev/null +++ b/src/scripts/Selector/SelectorLink.js @@ -0,0 +1,94 @@ +import Selector from '../Selector'; +import '../../libs/jquery.whencallsequentially'; + +export default class SelectorLink extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return true; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var elements = this.getDataElements(parentElement); + + var dfd = $.Deferred(); + + // return empty record if not multiple type and no elements found + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id] = null; + dfd.resolve([data]); + return dfd; + } + + // extract links one by one + var deferredDataExtractionCalls = []; + $(elements).each( + function(k, element) { + deferredDataExtractionCalls.push( + function(element) { + var deferredData = $.Deferred(); + var data = {}; + + var extracted_value; + if (this.extractAttribute) { + extracted_value = element[this.extractAttribute]; + } else { + extracted_value = $(element).text(); + } + extracted_value = this.stringReplace(extracted_value, this.stringReplacement); + + data[this.id] = $(element).text(); + data[this.id + '-href'] = extracted_value; + data._followSelectorId = this.id; + data._follow = extracted_value; + deferredData.resolve(data); + + return deferredData; + }.bind(this, element) + ); + }.bind(this) + ); + + $.whenCallSequentially(deferredDataExtractionCalls).done(function(responses) { + var result = []; + responses.forEach(function(dataResult) { + result.push(dataResult); + }); + dfd.resolve(result); + }); + + return dfd.promise(); + } + + getDataColumns() { + return [this.id, this.id + '-href']; + } + + getFeatures() { + return ['selector', 'extractAttribute', 'multiple', 'delay', 'stringReplacement']; + } + + getItemCSSSelector() { + return 'a'; + } +} diff --git a/src/scripts/Selector/SelectorPopupLink.js b/src/scripts/Selector/SelectorPopupLink.js new file mode 100644 index 00000000..1d5f34b8 --- /dev/null +++ b/src/scripts/Selector/SelectorPopupLink.js @@ -0,0 +1,162 @@ +import Selector from '../Selector'; +import '../../libs/jquery.whencallsequentially'; + +export default class SelectorPopupLink extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return true; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return true; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + var elements = this.getDataElements(parentElement); + + var dfd = $.Deferred(); + + // return empty record if not multiple type and no elements found + if (this.multiple === false && elements.length === 0) { + var data = {}; + data[this.id] = null; + dfd.resolve([data]); + return dfd; + } + + // extract links one by one + var deferredDataExtractionCalls = []; + $(elements).each( + function(k, element) { + deferredDataExtractionCalls.push( + function(element) { + var deferredData = $.Deferred(); + + var data = {}; + data[this.id] = $(element).text(); + data._followSelectorId = this.id; + + var deferredPopupURL = this.getPopupURL(element); + deferredPopupURL.done( + function(url) { + data[this.id + '-href'] = url; + data._follow = url; + deferredData.resolve(data); + }.bind(this) + ); + + return deferredData; + }.bind(this, element) + ); + }.bind(this) + ); + + $.whenCallSequentially(deferredDataExtractionCalls).done(function(responses) { + var result = []; + responses.forEach(function(dataResult) { + result.push(dataResult); + }); + dfd.resolve(result); + }); + + return dfd.promise(); + } + + getElementCSSSelector(element) { + var nthChild, prev; + for (nthChild = 1, prev = element.previousElementSibling; prev !== null; prev = prev.previousElementSibling, nthChild++); + var tagName = element.tagName.toLocaleLowerCase(); + var cssSelector = tagName + ':nth-child(' + nthChild + ')'; + + while (element.parentElement) { + element = element.parentElement; + var tagName = element.tagName.toLocaleLowerCase(); + if (tagName === 'body' || tagName === 'html') { + cssSelector = tagName + '>' + cssSelector; + } else { + for (nthChild = 1, prev = element.previousElementSibling; prev !== null; prev = prev.previousElementSibling, nthChild++); + cssSelector = tagName + ':nth-child(' + nthChild + ')>' + cssSelector; + } + } + + return cssSelector; + } + + /** + * Gets an url from a window.open call by mocking the window.open function + * @param element + * @returns $.Deferred() + */ + getPopupURL(element) { + // override window.open function. we need to execute this in page scope. + // we need to know how to find this element from page scope. + var cssSelector = this.getElementCSSSelector(element); + + // this function will catch window.open call and place the requested url as the elements data attribute + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.text = + '' + + '(function(){ ' + + 'var open = window.open; ' + + "var el = document.querySelectorAll('" + + cssSelector + + "')[0]; " + + 'var openNew = function() { ' + + 'var url = arguments[0]; ' + + 'el.dataset.webScraperExtractUrl = url; ' + + 'window.open = open; ' + + '};' + + 'window.open = openNew; ' + + 'el.click(); ' + + '})();'; + document.body.appendChild(script); + + // wait for url to be available + var deferredURL = $.Deferred(); + var timeout = Math.abs(5000 / 30); // 5s timeout to generate an url for popup + var interval = setInterval(function() { + var url = $(element).data('web-scraper-extract-url'); + if (url) { + deferredURL.resolve(url); + clearInterval(interval); + script.remove(); + } + // timeout popup opening + if (timeout-- <= 0) { + clearInterval(interval); + script.remove(); + } + }, 30); + + return deferredURL.promise(); + } + + getDataColumns() { + return [this.id, this.id + '-href']; + } + + getFeatures() { + return ['selector', 'multiple', 'delay']; + } + + getItemCSSSelector() { + return '*'; + } +} diff --git a/src/scripts/Selector/SelectorTable.js b/src/scripts/Selector/SelectorTable.js new file mode 100644 index 00000000..9fb59e51 --- /dev/null +++ b/src/scripts/Selector/SelectorTable.js @@ -0,0 +1,297 @@ +import Selector from '../Selector'; + +export default class SelectorTable extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + getTableHeaderColumns($table) { + let columns = {}; + let headerRowSelector = this.getTableHeaderRowSelector(); + let $headerRow = $table.find(headerRowSelector); + + if ($headerRow.length > 0) { + if ($headerRow.length > 1) { + if ($headerRow[0].nodeName === 'TR') { + $headerRow = $headerRow.find('th:first-child'); + if ($headerRow.length === 0) { + console.log('%c Please specify row header cell selector ', 'background: red; color: white;'); + } + } + } else if ($headerRow.find('th').length) { + $headerRow = $headerRow.find('th'); + } else if ($headerRow.find('td').length) { + $headerRow = $headerRow.find('td'); + } + + $headerRow.each( + function(i, value) { + let header = $(value) + .text() + .trim(); + columns[header] = { + index: i + 1, + }; + }.bind(this) + ); + + this.addMissingColumns($headerRow); + } + return columns; + } + + addMissingColumns(headerRow) { + headerRow.each( + function(i, value) { + if (this.tableAddMissingColumns) { + let header = $(value) + .text() + .trim(); + let column = $.grep(this.columns, function(h) { + return h.name === header; + }); + + if (column.length !== 1) { + this.columns.push({ + header: header, + extract: true, + }); + } + } + }.bind(this) + ); + } + + getVerticalDataCells(table, dataSelector) { + let selectors = $(table).find(dataSelector), + isRow = selectors[0].nodeName === 'TR', + result = []; + + if (isRow) { + console.log('%c Please specify row data cell selector ', 'background: red; color: white;'); + } else { + for (let i = 0; i < selectors.length; i++) { + result.push({}); + } + selectors.each( + function(i, dataCell) { + if (dataCell.cellIndex === 0) { + console.log("%c Vertical rows can't have first column as data cell ", 'background: red; color: white;'); + } else { + let headerCellName = $(dataCell) + .closest('tr') + .find('th, td')[0].innerText; + + let listDataColumnName = this.getDataColumnName(headerCellName); + let dataCellvalue = dataCell.innerText; + if (listDataColumnName) { + result[dataCell.cellIndex - 1][listDataColumnName] = dataCellvalue; + } + } + }.bind(this) + ); + } + + return result; + } + + _getData(parentElement) { + let dfd = $.Deferred(); + let verticalTable = this.verticalTable; + let tables = this.getDataElements(parentElement); + + let result = []; + $(tables).each( + function(k, table) { + let dataSelector = this.getTableDataRowSelector(); + if (verticalTable) { + let columnsList = this.getVerticalDataCells(table, dataSelector); + columnsList.forEach(function(column) { + if (!$.isEmptyObject(column)) { + result.push(column); + } + }); + } else { + let columnIndices = this.getTableHeaderColumns($(table)); + $(table) + .find(dataSelector) + .each( + function(i, dataCell) { + let data = {}; + + this.columns.forEach(function(column) { + let header = columnIndices[column.header.trim()]; + let rowText = $(dataCell) + .find('>:nth-child(' + header.index + ')') + .text() + .trim(); + if (column.extract) { + data[column.name] = rowText; + } + }); + result.push(data); + }.bind(this) + ); + } + }.bind(this) + ); + + dfd.resolve(result); + return dfd.promise(); + } + + getDataColumns() { + let dataColumns = []; + this.columns.forEach(function(column) { + if (column.extract) { + dataColumns.push(column.name); + } + }); + return dataColumns; + } + + getDataColumnName(header) { + let answer = this.columns.find(function(column) { + return column.extract && header === column.header.trim(); + }); + if (answer) { + return answer.name; + } + } + + getFeatures() { + return ['selector', 'multiple', 'columns', 'delay', 'tableDataRowSelector', 'tableHeaderRowSelector', 'tableAddMissingColumns', 'verticalTable']; + } + + getItemCSSSelector() { + return 'table'; + } + + getTableHeaderRowSelector() { + // handle legacy selectors + if (this.tableHeaderRowSelector === undefined) { + return 'thead tr'; + } else { + return this.tableHeaderRowSelector; + } + } + + getTableDataRowSelector() { + // handle legacy selectors + if (this.tableDataRowSelector === undefined) { + return 'tbody tr'; + } else { + return this.tableDataRowSelector; + } + } + + static getTableHeaderRowSelectorFromTableHTML(html, verticalTable) { + let $table = $(html); + let firstRow = $table.find('tr:first-child'); + + if ($table.find('thead tr:has(td:not(:empty)), thead tr:has(th:not(:empty))').length) { + if ($table.find('thead tr').length === 1) { + return 'thead tr'; + } else { + let $rows = $table.find('thead tr'); + // first row with data + let rowIndex = $rows.index($rows.filter(':has(td:not(:empty)),:has(th:not(:empty))')[0]); + return 'thead tr:nth-of-type(' + (rowIndex + 1) + ')'; + } + } else { + if (!verticalTable) { + if (firstRow.find('th:not(:empty)').length > 1) { + return 'tr:nth-of-type(1)'; + } else if (firstRow.find('th:first-child:not(:empty)').length === 1 && firstRow.children().length > 1) { + return 'tr'; + } else if ($table.find('tr td:not(:empty), tr th:not(:empty)').length) { + let $rows = $table.find('tr'); + // first row with data + let rowIndex = $rows.index($rows.filter(':has(td:not(:empty)),:has(th:not(:empty))')[0]); + return 'tr:nth-of-type(' + (rowIndex + 1) + ')'; + } else { + return ''; + } + } else { + if (firstRow.find('th').length) { + return 'tr>th'; + } else { + return 'tr>td:nth-of-type(1)'; + } + } + } + } + + static getTableDataRowSelectorFromTableHTML(html, verticalTable) { + let $table = $(html); + if ($table.find('thead tr:has(td:not(:empty)), thead tr:has(th:not(:empty))').length) { + return 'tbody tr'; + } else { + if (!verticalTable) { + if ($table.find('tr td:not(:empty), tr th:not(:empty)').length) { + let $rows = $table.find('tr'); + // first row with data + let rowIndex = $rows.index($rows.filter(':has(td:not(:empty)),:has(th:not(:empty))')[0]); + return 'tr:nth-of-type(n+' + (rowIndex + 2) + ')'; + } + } else { + if ($table.find('th').length) return 'tr>td'; + else return 'tr>td:nth-of-type(n+2)'; + } + } + } + + /** + * Extract table header column info from html + * @param headerRowSelector + * @param html + * @param verticalTable + */ + static getTableHeaderColumnsFromHTML(headerRowSelector, html, verticalTable) { + let $table = $(html); + let $headerRowColumns = $table.find(headerRowSelector); + + let columns = []; + if (!verticalTable) { + if ($headerRowColumns.length > 1) { + $headerRowColumns = $headerRowColumns.find('th:first-child'); + } else if ($headerRowColumns.find('th').length) { + $headerRowColumns = $headerRowColumns.find('th'); + } else if ($headerRowColumns.find('td').length) { + $headerRowColumns = $headerRowColumns.find('td'); + } + } + $headerRowColumns.each(function(i, columnEl) { + let header = columnEl.innerText; + if (header) { + columns.push({ + header: header, + name: header, + extract: true, + }); + } + }); + return columns; + } +} diff --git a/src/scripts/Selector/SelectorText.js b/src/scripts/Selector/SelectorText.js new file mode 100644 index 00000000..c728d23e --- /dev/null +++ b/src/scripts/Selector/SelectorText.js @@ -0,0 +1,67 @@ +import Selector from '../Selector'; + +export default class SelectorText extends Selector { + constructor(options) { + super(options); + this.updateData(options, this.getFeatures()); + } + + canReturnMultipleRecords() { + return true; + } + + canHaveChildSelectors() { + return false; + } + + canHaveLocalChildSelectors() { + return false; + } + + canCreateNewJobs() { + return false; + } + + willReturnElements() { + return false; + } + + _getData(parentElement) { + let dfd = $.Deferred(); + + let elements = this.getDataElements(parentElement); + + let result = []; + $(elements).each( + function(k, element) { + let data = {}; + + // remove script, style tag contents from text results + let $element_clone = $(element).clone(); + $element_clone.find('script, style').remove(); + //
replace br tags with newlines + $element_clone.find('br').after('\n'); + data[this.id] = $element_clone.text(); + + result.push(data); + }.bind(this) + ); + + if (this.multiple === false && elements.length === 0) { + let data = {}; + data[this.id] = null; + result.push(data); + } + + dfd.resolve(result); + return dfd.promise(); + } + + getDataColumns() { + return [this.id]; + } + + getFeatures() { + return ['selector', 'multiple', 'delay', 'textmanipulation']; + } +} diff --git a/src/scripts/SelectorGraph.js b/src/scripts/SelectorGraph.js new file mode 100644 index 00000000..7cefe328 --- /dev/null +++ b/src/scripts/SelectorGraph.js @@ -0,0 +1,198 @@ +export default class SelectorGraph { + constructor(sitemap) { + this.sitemap = sitemap; + this.nodes = []; + this.nodes.push({ id: '_root', parentSelectors: [] }); + sitemap.selectors.forEach( + function(selector) { + this.nodes.push(JSON.parse(JSON.stringify(selector))); + }.bind(this) + ); + } + + getNodes() { + return this.nodes; + } + + getLabelAnchors() { + var labelAnchors = []; + this.nodes.forEach(function(node) { + labelAnchors.push({ node: node }); + labelAnchors.push({ node: node }); + }); + return labelAnchors; + } + + getLabelAnchorLinks() { + var labelAnchorLinks = []; + for (var i = 0; i < this.nodes.length; i++) { + labelAnchorLinks.push({ + source: i * 2, + target: i * 2 + 1, + weight: 1, + }); + } + return labelAnchorLinks; + } + + getNodeById(nodeId) { + for (var i in this.nodes) { + var node = this.nodes[i]; + if (node.id === nodeId) { + return node; + } + } + } + + getLinks() { + var links = []; + this.nodes.forEach( + function(selector) { + selector.parentSelectors.forEach( + function(parentSelectorId) { + var parentSelector = this.getNodeById(parentSelectorId); + links.push({ + source: selector, + target: parentSelector, + weight: 1, + }); + }.bind(this) + ); + }.bind(this) + ); + return links; + } + + draw(element, w, h) { + var labelDistance = 0; + + var vis = d3 + .select(element) + .append('svg:svg') + .attr('width', w) + .attr('height', h); + + var nodes = this.getNodes(); + var labelAnchors = this.getLabelAnchors(); + var labelAnchorLinks = this.getLabelAnchorLinks(); + var links = this.getLinks(); + + var force = d3.layout + .force() + .size([w, h]) + .nodes(nodes) + .links(links) + .gravity(1) + .linkDistance(50) + .charge(-3000) + .linkStrength(function(x) { + return x.weight * 10; + }); + + force.start(); + + var force2 = d3.layout + .force() + .nodes(labelAnchors) + .links(labelAnchorLinks) + .gravity(0) + .linkDistance(0) + .linkStrength(8) + .charge(-100) + .size([w, h]); + force2.start(); + + var link = vis + .selectAll('line.link') + .data(links) + .enter() + .append('svg:line') + .attr('class', 'link') + .style('stroke', '#CCC'); + + var node = vis + .selectAll('g.node') + .data(force.nodes()) + .enter() + .append('svg:g') + .attr('class', 'node'); + node.append('svg:circle') + .attr('r', 5) + .style('fill', '#555') + .style('stroke', '#FFF') + .style('stroke-width', 3); + node.call(force.drag); + + var anchorLink = vis.selectAll('line.anchorLink').data(labelAnchorLinks); //.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); + + var anchorNode = vis + .selectAll('g.anchorNode') + .data(force2.nodes()) + .enter() + .append('svg:g') + .attr('class', 'anchorNode'); + anchorNode + .append('svg:circle') + .attr('r', 0) + .style('fill', '#FFF'); + anchorNode + .append('svg:text') + .text(function(d, i) { + return i % 2 == 0 ? '' : d.node.id; + }) + .style('fill', '#555') + .style('font-family', 'Arial') + .style('font-size', 12); + + var updateLink = function() { + this.attr('x1', function(d) { + return d.source.x; + }) + .attr('y1', function(d) { + return d.source.y; + }) + .attr('x2', function(d) { + return d.target.x; + }) + .attr('y2', function(d) { + return d.target.y; + }); + }; + + var updateNode = function() { + this.attr('transform', function(d) { + return 'translate(' + d.x + ',' + d.y + ')'; + }); + }; + + force.on('tick', function() { + force2.start(); + + node.call(updateNode); + + anchorNode.each(function(d, i) { + if (i % 2 == 0) { + d.x = d.node.x; + d.y = d.node.y; + } else { + var b = this.childNodes[1].getBBox(); + + var diffX = d.x - d.node.x; + var diffY = d.y - d.node.y; + + var dist = Math.sqrt(diffX * diffX + diffY * diffY); + + var shiftX = (b.width * (diffX - dist)) / (dist * 2); + shiftX = Math.max(-b.width, Math.min(0, shiftX)); + var shiftY = 5; + this.childNodes[1].setAttribute('transform', 'translate(' + shiftX + ',' + shiftY + ')'); + } + }); + + anchorNode.call(updateNode); + + link.call(updateLink); + anchorLink.call(updateLink); + }); + } +} diff --git a/src/scripts/SelectorGraphv2.js b/src/scripts/SelectorGraphv2.js new file mode 100644 index 00000000..a361c918 --- /dev/null +++ b/src/scripts/SelectorGraphv2.js @@ -0,0 +1,234 @@ +import * as d3 from 'd3'; + +export default class SelectorGraphv2 { + constructor(sitemap) { + this.sitemap = sitemap; + + /** + * function for line drawing between two nodes + */ + this.diagonal = d3.svg.diagonal().projection(function(d) { + return [d.y, d.x]; + }); + } + + /** + * Inits d3.layout.tree + */ + initTree(w, h) { + this.tree = d3.layout.tree().size([h, w]); + this.tree.children(this.getSelectorVisibleChildren.bind(this)); + } + + getSelectorChildren(parentSelector) { + if (parentSelector.childSelectors === undefined) { + parentSelector.childSelectors = this.sitemap.selectors.getDirectChildSelectors(parentSelector.id).fullClone(); + } + + if (parentSelector.childSelectors.length === 0) { + return null; + } else { + return parentSelector.childSelectors; + } + } + + getSelectorVisibleChildren(parentSelector) { + // initially hide selector children + if (parentSelector.visibleChildren === undefined) { + parentSelector.visibleChildren = false; + } + + if (parentSelector.visibleChildren === false) { + return null; + } + + return this.getSelectorChildren(parentSelector); + } + + selectorHasChildren(parentSelector) { + var children = this.sitemap.selectors.getDirectChildSelectors(parentSelector.id); + var selectorHasChildren = children.length > 0; + return selectorHasChildren; + } + + draw(element, w, h) { + var m = [20, 120, 20, 120], + w = w - m[1] - m[3], + h = h - m[0] - m[2], + i = 0, + root, + selectorList; + + this.initTree(w, h); + + // @TODO use element + this.svg = d3 + .select(element) + .append('svg:svg') + .attr('width', w + m[1] + m[3]) + .attr('height', h + m[0] + m[2]) + .append('svg:g') + .attr('transform', 'translate(' + m[3] + ',' + m[0] + ')'); + + this.root = { + id: '_root', + x0: h / 2, + y0: 0, + i: '_root', + }; + + this.update(this.root); + } + + /** + * Color for selectors circle + * @param selector + */ + getNodeColor(selector) { + if (this.selectorHasChildren(selector) && !selector.visibleChildren) { + return 'lightsteelblue'; + } else { + return '#fff'; + } + } + + update(source) { + var duration = 500; + + // Compute the new tree layout. + var nodes = this.tree.nodes(this.root).reverse(); + + // Normalize for fixed-depth. + nodes.forEach(function(d) { + d.y = d.depth * 100; + }); + var i = 0; + // Update the nodes… + var node = this.svg.selectAll('g.node').data(nodes, function(d) { + if (d.i === undefined) { + d.i = d.id; + d.i = source.i + '/' + d.i; + } + return d.i; + }); + + // Enter any new nodes at the parent's previous position. + var nodeEnter = node + .enter() + .append('svg:g') + .attr('class', 'node') + .attr('transform', function(d) { + return 'translate(' + source.y0 + ',' + source.x0 + ')'; + }) + .on( + 'click', + function(d) { + this.toggle(d); + this.update(d); + }.bind(this) + ); + + nodeEnter + .append('svg:circle') + .attr('r', 1e-6) + .style('fill', this.getNodeColor.bind(this)); + + nodeEnter + .append('svg:text') + .attr( + 'x', + function(d) { + return this.selectorHasChildren(d) ? -10 : 10; + }.bind(this) + ) + .attr('dy', '.35em') + .attr( + 'text-anchor', + function(d) { + return this.selectorHasChildren(d) ? 'end' : 'start'; + }.bind(this) + ) + .text(function(d) { + return d.id; + }) + .style('fill-opacity', 1e-6); + + // Transition nodes to their new position. + var nodeUpdate = node + .transition() + .duration(duration) + .attr('transform', function(d) { + return 'translate(' + d.y + ',' + d.x + ')'; + }); + + nodeUpdate + .select('circle') + .attr('r', 6) + .style('fill', this.getNodeColor.bind(this)); + + nodeUpdate.select('text').style('fill-opacity', 1); + + // Transition exiting nodes to the parent's new position. + var nodeExit = node + .exit() + .transition() + .duration(duration) + .attr('transform', function(d) { + return 'translate(' + source.y + ',' + source.x + ')'; + }) + .remove(); + + nodeExit.select('circle').attr('r', 1e-6); + + nodeExit.select('text').style('fill-opacity', 1e-6); + + // Update the links… + var link = this.svg.selectAll('path.link').data(this.tree.links(nodes), function(d) { + return d.target.i; + }); + + // Enter any new links at the parent's previous position. + link.enter() + .insert('svg:path', 'g') + .attr('class', 'link') + .attr( + 'd', + function(d) { + var o = { x: source.x0, y: source.y0 }; + var res = this.diagonal({ source: o, target: o }); + return res; + }.bind(this) + ) + .transition() + .duration(duration) + .attr('d', this.diagonal); + + // Transition links to their new position. + link.transition() + .duration(duration) + .attr('d', this.diagonal); + + // Transition exiting nodes to the parent's new position. + link.exit() + .transition() + .duration(duration) + .attr( + 'd', + function(d) { + var o = { x: source.x, y: source.y }; + return this.diagonal({ source: o, target: o }); + }.bind(this) + ) + .remove(); + + // Stash the old positions for transition. + nodes.forEach(function(d) { + d.x0 = d.x; + d.y0 = d.y; + }); + } + + toggle(d) { + d.visibleChildren = !d.visibleChildren; + } +} diff --git a/src/scripts/SelectorList.js b/src/scripts/SelectorList.js new file mode 100644 index 00000000..1fcc7d85 --- /dev/null +++ b/src/scripts/SelectorList.js @@ -0,0 +1,330 @@ +import Selector from './Selector'; +import ConstantValue from './Selector/ConstantValue'; +import SelectorText from './Selector/SelectorText'; +import SelectorDocument from './Selector/SelectorDocument'; +import SelectorPopupLink from './Selector/SelectorPopupLink'; +import SelectorInputValue from './Selector/SelectorInputValue'; +import SelectorElement from './Selector/SelectorElement'; +import SelectorLink from './Selector/SelectorLink'; +import SelectorImage from './Selector/SelectorImage'; +import SelectorHTML from './Selector/SelectorHTML'; +import SelectorGroup from './Selector/SelectorGroup'; +import SelectorElementStyle from './Selector/SelectorElementStyle'; +import SelectorElementClick from './Selector/SelectorElementClick'; +import SelectorElementScroll from './Selector/SelectorElementScroll'; +import SelectorElementAttribute from './Selector/SelectorElementAttribute'; +import SelectorTable from './Selector/SelectorTable'; + +export default class SelectorList extends Array { + static createSelector(options) { + switch (options.type) { + case 'ConstantValue': + return new ConstantValue(options); + case 'SelectorDocument': + return new SelectorDocument(options); + case 'SelectorElement': + return new SelectorElement(options); + case 'SelectorElementAttribute': + return new SelectorElementAttribute(options); + case 'SelectorElementScroll': + return new SelectorElementScroll(options); + case 'SelectorElementClick': + return new SelectorElementClick(options); + case 'SelectorElementStyle': + return new SelectorElementStyle(options); + case 'SelectorGroup': + return new SelectorGroup(options); + case 'SelectorHTML': + return new SelectorHTML(options); + case 'SelectorImage': + return new SelectorImage(options); + case 'SelectorInputValue': + return new SelectorInputValue(options); + case 'SelectorLink': + return new SelectorLink(options); + case 'SelectorPopupLink': + return new SelectorPopupLink(options); + case 'SelectorTable': + return new SelectorTable(options); + case 'SelectorText': + return new SelectorText(options); + default: + return new SelectorText(options); + } + } + + constructor(selectors) { + super(); + if (selectors === undefined) { + return; + } + + for (let i = 0; i < selectors.length; i++) { + this.push(selectors[i]); + } + } + + push(selector) { + if (!this.hasSelector(selector.id)) { + if (!(selector instanceof Selector)) { + selector = SelectorList.createSelector(selector); + } + Array.prototype.push.call(this, selector); + } + } + + hasSelector(selectorId) { + if (selectorId instanceof Object) { + selectorId = selectorId.id; + } + + for (let i = 0; i < this.length; i++) { + if (this[i].id === selectorId) { + return true; + } + } + return false; + } + + /** + * Returns all selectors or recursively find and return all child selectors of a parent selector. + * @param parentSelectorId + * @returns {Array} + */ + getAllSelectors(parentSelectorId) { + if (parentSelectorId === undefined) { + return this; + } + + let getAllChildSelectors = function(parentSelectorId, resultSelectors) { + this.forEach( + function(selector) { + if (selector.hasParentSelector(parentSelectorId)) { + if (resultSelectors.indexOf(selector) === -1) { + resultSelectors.push(selector); + getAllChildSelectors(selector.id, resultSelectors); + } + } + }.bind(this) + ); + }.bind(this); + + let resultSelectors = []; + getAllChildSelectors(parentSelectorId, resultSelectors); + return resultSelectors; + } + + /** + * Returns only selectors that are directly under a parent + * @param parentSelectorId + * @returns {Array} + */ + getDirectChildSelectors(parentSelectorId) { + let resultSelectors = new SelectorList(); + this.forEach(function(selector) { + if (selector.hasParentSelector(parentSelectorId)) { + resultSelectors.push(selector); + } + }); + return resultSelectors; + } + + clone() { + let resultList = new SelectorList(); + this.forEach(function(selector) { + resultList.push(selector); + }); + return resultList; + } + + fullClone() { + let resultList = new SelectorList(); + this.forEach(function(selector) { + resultList.push(JSON.parse(JSON.stringify(selector))); + }); + return resultList; + } + + concat() { + let resultList = this.clone(); + for (let i in arguments) { + arguments[i].forEach( + function(selector) { + resultList.push(selector); + }.bind(this) + ); + } + return resultList; + } + + getSelector(selectorId) { + for (let i = 0; i < this.length; i++) { + let selector = this[i]; + if (selector.id === selectorId) { + return selector; + } + } + } + + /** + * Returns all selectors if this selectors including all parent selectors within this page + * @TODO not used any more. + * @param selectorId + * @returns {*} + */ + getOnePageSelectors(selectorId) { + let resultList = new SelectorList(); + let selector = this.getSelector(selectorId); + resultList.push(this.getSelector(selectorId)); + + // recursively find all parent selectors that could lead to the page where selectorId is used. + let findParentSelectors = function(selector) { + selector.parentSelectors.forEach( + function(parentSelectorId) { + if (parentSelectorId === '_root') return; + let parentSelector = this.getSelector(parentSelectorId); + if (resultList.indexOf(parentSelector) !== -1) return; + if (parentSelector.willReturnElements()) { + resultList.push(parentSelector); + findParentSelectors(parentSelector); + } + }.bind(this) + ); + }.bind(this); + + findParentSelectors(selector); + + // add all child selectors + resultList = resultList.concat(this.getSinglePageAllChildSelectors(selector.id)); + return resultList; + } + + /** + * Returns all child selectors of a selector which can be used within one page. + * @param parentSelectorId + */ + getSinglePageAllChildSelectors(parentSelectorId) { + let resultList = new SelectorList(); + let addChildSelectors = function(parentSelector) { + if (parentSelector.willReturnElements()) { + let childSelectors = this.getDirectChildSelectors(parentSelector.id); + childSelectors.forEach( + function(childSelector) { + if (resultList.indexOf(childSelector) === -1) { + resultList.push(childSelector); + addChildSelectors(childSelector); + } + }.bind(this) + ); + } + }.bind(this); + + let parentSelector = this.getSelector(parentSelectorId); + addChildSelectors(parentSelector); + return resultList; + } + + willReturnMultipleRecords(selectorId) { + // handle reuqested selector + let selector = this.getSelector(selectorId); + if (selector.willReturnMultipleRecords() === true) { + return true; + } + + // handle all its child selectors + let childSelectors = this.getAllSelectors(selectorId); + for (let i = 0; i < childSelectors.length; i++) { + let selector = childSelectors[i]; + if (selector.willReturnMultipleRecords() === true) { + return true; + } + } + + return false; + } + + /** + * When serializing to JSON convert to an array + * @returns {Array} + */ + toJSON() { + let result = []; + this.forEach(function(selector) { + result.push(selector); + }); + return result; + } + + getSelectorById(selectorId) { + for (let i = 0; i < this.length; i++) { + let selector = this[i]; + if (selector.id === selectorId) { + return selector; + } + } + } + + /** + * returns css selector for a given element. css selector includes all parent element selectors + * @param selectorId + * @param parentSelectorIds array of parent selector ids from devtools Breadcumb + * @returns string + */ + getCSSSelectorWithinOnePage(selectorId, parentSelectorIds) { + let CSSSelector = this.getSelector(selectorId).selector; + let parentCSSSelector = this.getParentCSSSelectorWithinOnePage(parentSelectorIds); + CSSSelector = parentCSSSelector + CSSSelector; + + return CSSSelector; + } + + /** + * returns css selector for parent selectors that are within one page + * @param parentSelectorIds array of parent selector ids from devtools Breadcumb + * @returns string + */ + getParentCSSSelectorWithinOnePage(parentSelectorIds) { + let CSSSelector = ''; + + for (let i = parentSelectorIds.length - 1; i > 0; i--) { + let parentSelectorId = parentSelectorIds[i]; + let parentSelector = this.getSelector(parentSelectorId); + if (parentSelector.willReturnElements()) { + CSSSelector = parentSelector.selector + ' ' + CSSSelector; + } else { + break; + } + } + + return CSSSelector; + } + + hasRecursiveElementSelectors() { + let RecursionFound = false; + + this.forEach( + function(topSelector) { + let visitedSelectors = []; + + let checkRecursion = function(parentSelector) { + // already visited + if (visitedSelectors.indexOf(parentSelector) !== -1) { + RecursionFound = true; + return; + } + + if (parentSelector.willReturnElements()) { + visitedSelectors.push(parentSelector); + let childSelectors = this.getDirectChildSelectors(parentSelector.id); + childSelectors.forEach(checkRecursion); + visitedSelectors.pop(); + } + }.bind(this); + + checkRecursion(topSelector); + }.bind(this) + ); + + return RecursionFound; + } +} diff --git a/src/scripts/Sitemap.js b/src/scripts/Sitemap.js new file mode 100644 index 00000000..7bca1610 --- /dev/null +++ b/src/scripts/Sitemap.js @@ -0,0 +1,270 @@ +import DatePatternSupport from './DateUtils/DatePatternSupport'; +import SelectorList from './SelectorList'; +import * as Papa from 'papaparse'; + +export default class Sitemap { + constructor(sitemapObj) { + this.initData(sitemapObj); + } + + initData(sitemapObj) { + for (let key in sitemapObj) { + this[key] = sitemapObj[key]; + } + this.selectors = new SelectorList(this.selectors); + } + + static isUrlValid(url) { + try { + new URL(url); + return true; + } catch (e) { + if (e instanceof TypeError) { + return false; + } + throw e; + } + } + + static validateStartUrls(startUrls) { + if (!Array.isArray(startUrls) || !startUrls.length) { + return false; + } + return startUrls.map(item => item.trim()).every(this.isUrlValid); + } + + /** + * Returns all selectors or recursively find and return all child selectors of a parent selector. + * @param parentSelectorId + * @returns {Array} + */ + getAllSelectors(parentSelectorId) { + return this.selectors.getAllSelectors(parentSelectorId); + } + + /** + * Returns only selectors that are directly under a parent + * @param parentSelectorId + * @returns {Array} + */ + getDirectChildSelectors(parentSelectorId) { + return this.selectors.getDirectChildSelectors(parentSelectorId); + } + + /** + * Returns all selector id parameters + * @returns {Array} + */ + getSelectorIds() { + let ids = ['_root']; + this.selectors.forEach(function(selector) { + ids.push(selector.id); + }); + return ids; + } + + /** + * Returns only selector ids which can have child selectors + * @returns {Array} + */ + getPossibleParentSelectorIds() { + let ids = ['_root']; + this.selectors.forEach( + function(selector) { + if (selector.canHaveChildSelectors()) { + ids.push(selector.id); + } + }.bind(this) + ); + return ids; + } + + getStartUrls() { + let startUrls = this.startUrls; + startUrls = DatePatternSupport.expandUrl(startUrls); + + let nextUrls = function(url) { + let urls = []; + let lpad = function(str, length) { + while (str.length < length) str = '0' + str; + return str; + }; + + let re = /^(.*?)\[(\d+)\-(\d+)(:(\d+))?\](.*)$/; + let matches = url.match(re); + if (matches) { + let startStr = matches[2]; + let endStr = matches[3]; + let start = parseInt(startStr); + let end = parseInt(endStr); + let incremental = 1; + console.log(matches[5]); + if (matches[5] !== undefined) { + incremental = parseInt(matches[5]); + } + let nextSet = nextUrls(matches[6]); + for (let i = start; i <= end; i += incremental) { + let current; + + // with zero padding + if (startStr.length === endStr.length) { + current = matches[1] + lpad(i.toString(), startStr.length); + } else { + current = matches[1] + i; + } + nextSet.forEach(function(next) { + urls.push(current + next); + }); + } + } else { + urls.push(url); + } + return urls; + }; + let urls = []; + + startUrls.forEach(function(startUrl) { + urls = urls.concat(nextUrls(startUrl)); + }); + + return urls; + } + + updateSelector(selector, selectorData) { + // selector is undefined when creating a new one + if (selector === undefined || selector.type !== selectorData.type) { + selector = SelectorList.createSelector(selectorData); + } + + // update child selectors + if (selector.id !== undefined && selector.id !== selectorData.id) { + this.selectors.forEach(function(currentSelector) { + currentSelector.renameParentSelector(selector.id, selectorData.id); + }); + + // update cyclic selector + let pos = selectorData.parentSelectors.indexOf(selector.id); + if (pos !== -1) { + selectorData.parentSelectors.splice(pos, 1, selectorData.id); + } + } + + selector.updateData(selectorData, selectorData.getFeatures()); + + let index = this.getSelectorIds().indexOf(selector.id); + if (index === -1) { + this.selectors.push(selector); + } else { + //XXX Hot fix for replacing old selector with another type. + this.selectors.splice(index - 1, 1, selector); + } + } + deleteSelector(selectorToDelete) { + this.selectors.forEach( + function(selector) { + if (selector.hasParentSelector(selectorToDelete.id)) { + selector.removeParentSelector(selectorToDelete.id); + if (selector.parentSelectors.length === 0) { + this.deleteSelector(selector); + } + } + }.bind(this) + ); + + for (let i in this.selectors) { + if (this.selectors[i].id === selectorToDelete.id) { + this.selectors.splice(i, 1); + break; + } + } + } + getDataTableId() { + return this._id.replace(/\./g, '_'); + } + exportSitemap() { + function removeEmpty(obj) { + Object.keys(obj).forEach(function(key) { + if (obj[key] && typeof obj[key] === 'object') { + removeEmpty(obj[key]); + if (Object.keys(obj[key]).length === 0) { + delete obj[key]; + } + } else if (obj[key] === false || obj[key] === [] || obj[key] === '') { + delete obj[key]; + } + }); + } + let sitemapObj = JSON.parse(JSON.stringify(this)); + delete sitemapObj._rev; + removeEmpty(sitemapObj); + return JSON.stringify(sitemapObj); + } + importSitemap(sitemapJSON) { + let sitemapObj = JSON.parse(sitemapJSON); + this.initData(sitemapObj); + } + // return a list of columns than can be exported + getDataColumns() { + let columns = []; + this.selectors.forEach(function(selector) { + columns = columns.concat(selector.getDataColumns()); + }); + + let uniqueColumns = []; + $.each(columns, function(i, e) { + if ($.inArray(e, uniqueColumns) == -1) uniqueColumns.push(e); + }); + + return uniqueColumns; + } + getDataExportCsvBlob(data, option) { + let delimiterKey = 'delimiter'; + let newlineKey = 'newline'; + let containBomKey = 'containBom'; + + let columns = this.getDataColumns(), + // default delimiter is comma + delimiter = option.hasOwnProperty(delimiterKey) ? option[delimiterKey] : ',', + // per default, new line is included at end of lines + newline = option.hasOwnProperty(newlineKey) ? (option[newlineKey] == true ? '\r\n' : '') : '\r\n', + // per default, utf8 BOM is included at the beginning. + prepend = option.hasOwnProperty(containBomKey) ? (option[containBomKey] == true ? '\ufeff' : '') : '\ufeff', // utf-8 bom char + options = { + quotes: false, + quoteChar: '"', + delimiter: delimiter, + header: true, + newline: '\r\n', // between value rows + }, + jsonData = []; + + // data + data.forEach(function(row) { + let jsonRow = {}; + columns.forEach(function(column) { + let cellData = row[column]; + if (cellData === undefined) { + cellData = ''; + } else if (typeof cellData === 'object') { + cellData = JSON.stringify(cellData); + } + + jsonRow[column] = cellData; + }); + jsonData.push(jsonRow); + }); + + return new Blob([prepend + Papa.unparse(jsonData, options) + newline], { type: 'text/csv' }); + } + getSelectorById(selectorId) { + return this.selectors.getSelectorById(selectorId); + } + /** + * Create full clone of sitemap + * @returns {Sitemap} + */ + clone() { + let clonedJSON = JSON.parse(JSON.stringify(this)); + return new Sitemap(clonedJSON); + } +} diff --git a/src/scripts/StoreDevtools.js b/src/scripts/StoreDevtools.js new file mode 100644 index 00000000..3c9f39ca --- /dev/null +++ b/src/scripts/StoreDevtools.js @@ -0,0 +1,72 @@ +import Sitemap from './Sitemap'; +import * as browser from 'webextension-polyfill'; + +/** + * From devtools panel there is no possibility to execute XHR requests. So all requests to a remote CouchDb must be + * handled through Background page. StoreDevtools is a simply a proxy store + * @constructor + */ +export default class StoreDevtools { + createSitemap(sitemap) { + var request = { + createSitemap: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + }; + + return new Promise(resolve => { + browser.runtime.sendMessage(request).then( + function(originalSitemap, newSitemap) { + originalSitemap._rev = newSitemap._rev; + resolve(originalSitemap); + }.bind(this, sitemap) + ); + }); + } + + saveSitemap(sitemap) { + return this.createSitemap(sitemap); + } + + deleteSitemap(sitemap) { + var request = { + deleteSitemap: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + }; + return browser.runtime.sendMessage(request); + } + + getAllSitemaps() { + var request = { + getAllSitemaps: true, + }; + + return new Promise(resolve => { + browser.runtime.sendMessage(request).then(function(response) { + var sitemaps = []; + + for (var i in response) { + sitemaps.push(new Sitemap(response[i])); + } + return resolve(sitemaps); + }); + }); + } + + getSitemapData(sitemap) { + var request = { + getSitemapData: true, + sitemap: JSON.parse(JSON.stringify(sitemap)), + }; + + return browser.runtime.sendMessage(request); + } + + sitemapExists(sitemapId) { + var request = { + sitemapExists: true, + sitemapId: sitemapId, + }; + + return browser.runtime.sendMessage(request); + } +} diff --git a/src/scripts/StorePouchDB.js b/src/scripts/StorePouchDB.js new file mode 100644 index 00000000..b02b0435 --- /dev/null +++ b/src/scripts/StorePouchDB.js @@ -0,0 +1,191 @@ +import PouchDB from 'pouchdb'; +import * as browser from 'webextension-polyfill'; +import Sitemap from './Sitemap'; + +/** + * Make sure all obj have the same properties + * They can differe if table selector retrieves dynamic columns + */ +let normalizeProperties = function(docs) { + // get all keys of the objects + let keys = []; + docs.forEach(function(doc) { + for (let key in doc) { + if (doc.hasOwnProperty(key) && keys.indexOf(key) === -1) { + keys.push(key); + } + } + }); + + // add missing keys to objects + docs.forEach(function(doc) { + let objKeys = Object.keys(doc); + keys.forEach(function(key) { + if (!(key in doc)) { + doc[key] = ''; + } + }); + }); +}; + +class StoreScrapeResultWriter { + constructor(db) { + this.db = db; + } + + writeDocs(docs, callback) { + if (docs.length === 0) { + callback(); + } else { + normalizeProperties(docs); + this.db.bulkDocs({ docs: docs }, function(err, response) { + if (err !== null) { + console.log('Error while persisting scraped data to db', err); + } + callback(); + }); + } + } +} + +export default class StorePouchDB { + constructor(config) { + this.config = config; + // configure couchdb + this.sitemapDb = new PouchDB(this.config.sitemapDb); + } + + sanitizeSitemapDataDbName(dbName) { + return 'sitemap-data-' + dbName.replace(/[^a-z0-9_\$\(\)\+\-/]/gi, '_'); + } + + getSitemapDataDbLocation(sitemapId) { + let dbName = this.sanitizeSitemapDataDbName(sitemapId); + return this.config.dataDb + dbName; + } + + getSitemapDataDb(sitemapId) { + let dbLocation = this.getSitemapDataDbLocation(sitemapId); + return new PouchDB(dbLocation); + } + + /** + * creates or clears a sitemap db + * @param {type} sitemapId + * @returns {undefined} + */ + initSitemapDataDb(sitemapId) { + // let dbLocation = this.getSitemapDataDbLocation(sitemapId); + let store = this; + let db = this.getSitemapDataDb(sitemapId); + + return new Promise(resolve => { + db.destroy() + .then(() => { + let db = store.getSitemapDataDb(sitemapId); + let dbWriter = new StoreScrapeResultWriter(db); + resolve(dbWriter); + }) + .catch(reason => { + console.log(reason); + resolve(); + }); + }); + } + + createSitemap(sitemap) { + let sitemapJson = JSON.parse(JSON.stringify(sitemap)); + + if (!sitemap._id) { + console.log('cannot save sitemap without an id', sitemap); + } + + return new Promise(resolve => { + this.sitemapDb.put( + sitemapJson, + function(sitemap, err, response) { + // @TODO handle err + if (response) { + sitemap._rev = response.rev; + } + // this.initSitemapDataDb(sitemap._id).then(function () { + resolve(sitemap); + // }); + }.bind(this, sitemap) + ); + }); + } + + saveSitemap(sitemap) { + // @TODO remove + return this.createSitemap(sitemap); + } + + deleteSitemap(sitemap) { + sitemap = JSON.parse(JSON.stringify(sitemap)); + return new Promise(resolve => { + this.sitemapDb.remove( + sitemap, + function(err, response) { + // @TODO handle err + + // delete sitemap data db + let dbLocation = this.getSitemapDataDbLocation(sitemap._id); + // PouchDB.destroy(dbLocation, function () { + resolve(); + // }.bind(this)); + }.bind(this) + ); + }); + } + + getAllSitemaps() { + return new Promise(resolve => { + this.sitemapDb.allDocs({ include_docs: true }, function(err, response) { + let sitemaps = []; + for (let i in response.rows) { + let sitemap = response.rows[i].doc; + if (!browser.extension) { + sitemap = new Sitemap(sitemap); + } + + sitemaps.push(sitemap); + } + resolve(sitemaps); + }); + }); + } + + getSitemapData(sitemap) { + return new Promise(resolve => { + let db = this.getSitemapDataDb(sitemap._id); + db.allDocs( + { include_docs: true }, + function(err, response) { + let responseData = []; + for (let i in response.rows) { + let doc = response.rows[i].doc; + responseData.push(doc); + } + normalizeProperties(responseData); + resolve(responseData); + }.bind(this) + ); + }); + } + + // @TODO make this call lighter + sitemapExists(sitemapId) { + return new Promise(resolve => { + this.getAllSitemaps().then(function(sitemaps) { + let sitemapFound = false; + for (let i in sitemaps) { + if (sitemaps[i]._id === sitemapId) { + sitemapFound = true; + } + } + resolve(sitemapFound); + }); + }); + } +} diff --git a/src/scripts/StoreRestApi.js b/src/scripts/StoreRestApi.js new file mode 100644 index 00000000..2f502e10 --- /dev/null +++ b/src/scripts/StoreRestApi.js @@ -0,0 +1,116 @@ +import Sitemap from './Sitemap'; +import StorePouchDB from './StorePouchDB'; + +export default class StoreRestApi { + constructor(config) { + this.base_uri = config.restUrl; + this.localDataStore = new StorePouchDB(config); + } + + createSitemap(sitemap) { + return this.saveSitemap(sitemap); + } + + saveSitemap(sitemap) { + let base_uri = this.base_uri; + return new Promise(resolve => { + this.sitemapExists(sitemap._id).then(function(exists) { + if (exists) { + //update sitemap + $.ajax({ + type: 'PUT', + url: new URL('/sitemaps/' + sitemap._id, base_uri).href, + data: new Sitemap(sitemap).exportSitemap(), + success: function() { + resolve(sitemap); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert('StoreApi: Error updating sitemap.'); + }, + contentType: 'application/json', + }); + } else { + //create new sitemap + $.ajax({ + type: 'POST', + url: new URL('/sitemaps/', base_uri).href, + data: new Sitemap(sitemap).exportSitemap(), + success: function() { + resolve(sitemap); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert('StoreApi: Error creating sitemap.'); + }, + contentType: 'application/json', + }); + } + }); + }); + } + + deleteSitemap(sitemap) { + return new Promise(resolve => { + $.ajax({ + type: 'DELETE', + url: new URL('/sitemaps/' + sitemap._id, this.base_uri).href, + success: function(response) { + resolve(response); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert('StoreApi: Error deleting sitemap.'); + }, + contentType: 'application/json', + }); + }); + } + + getAllSitemaps() { + return new Promise(resolve => { + $.ajax({ + type: 'GET', + url: new URL('/sitemaps/', this.base_uri).href, + success: function(data) { + let sitemaps = []; + for (let i in data) { + sitemaps.push(new Sitemap(data[i])); + } + resolve(sitemaps); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert('StoreApi: Could not get all sitemaps.'); + }, + contentType: 'application/json', + }); + }); + } + + sitemapExists(sitemapId) { + return new Promise(resolve => { + $.ajax({ + type: 'GET', + url: new URL('/sitemaps/', this.base_uri).href, + success: function(data) { + let exists = false; + for (let i in data) { + if (data[i]._id === sitemapId) { + exists = true; + } + } + resolve(exists); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert('StoreApi: Could not get all sitemaps.'); + }, + contentType: 'application/json', + }); + }); + } + + initSitemapDataDb(sitemapId) { + return this.localDataStore.initSitemapDataDb(sitemapId); + } + + getSitemapData(sitemap) { + return this.localDataStore.getSitemapData(sitemap); + } +} diff --git a/src/scripts/UniqueElementList.js b/src/scripts/UniqueElementList.js new file mode 100644 index 00000000..edb198fa --- /dev/null +++ b/src/scripts/UniqueElementList.js @@ -0,0 +1,117 @@ +/** + * Only Elements unique will be added to this array + * @constructor + */ +export default class UniqueElementList extends Array { + constructor(clickElementUniquenessType) { + super(); + this.clickElementUniquenessType = clickElementUniquenessType; + this.addedElements = {}; + } + + push(element) { + let getStyles = function(_elem, _style) { + let computedStyle; + if (typeof _elem.currentStyle != 'undefined') { + computedStyle = _elem.currentStyle; + } else { + computedStyle = document.defaultView.getComputedStyle(_elem, null); + } + return _style ? computedStyle[_style] : computedStyle; + }; + + let copyComputedStyle = function(src, dest) { + let styles = getStyles(src); + for (let i in styles) { + // Do not use `hasOwnProperty`, nothing will get copied + if (typeof i == 'string' && i != 'cssText' && !/\d/.test(i)) { + // The try is for setter only properties + try { + dest.style[i] = styles[i]; + // `fontSize` comes before `font` If `font` is empty, `fontSize` gets + // overwritten. So make sure to reset this property. (hackyhackhack) + // Other properties may need similar treatment + if (i == 'font') { + dest.style.fontSize = styles.fontSize; + } + } catch (e) {} + } + } + }; + + if (this.isAdded(element)) { + return false; + } else { + let elementUniqueId = this.getElementUniqueId(element); + this.addedElements[elementUniqueId] = true; + let clone = $(element).clone(true)[0]; + + // clone computed styles (to extract images from background) + let items = element.getElementsByTagName('*'); + let itemsCloned = clone.getElementsByTagName('*'); + $(items).each(function(i, item) { + copyComputedStyle(item, itemsCloned[i]); + }); + + Array.prototype.push.call(this, clone); + return true; + } + } + + getElementUniqueId(element) { + if (this.clickElementUniquenessType === 'uniqueText') { + let elementText = $(element) + .text() + .trim(); + return elementText; + } else if (this.clickElementUniquenessType === 'uniqueHTMLText') { + let elementHTML = $("
") + .append( + $(element) + .eq(0) + .clone() + ) + .html(); + return elementHTML; + } else if (this.clickElementUniquenessType === 'uniqueHTML') { + // get element without text + let $element = $(element) + .eq(0) + .clone(); + + let removeText = function($element) { + $element + .contents() + .filter(function() { + if (this.nodeType !== 3) { + removeText($(this)); + } + return this.nodeType == 3; //Node.TEXT_NODE + }) + .remove(); + }; + removeText($element); + + let elementHTML = $("
") + .append($element) + .html(); + return elementHTML; + } else if (this.clickElementUniquenessType === 'uniqueCSSSelector') { + let cs = new CssSelector({ + enableSmartTableSelector: false, + parent: $('body')[0], + enableResultStripping: false, + }); + let CSSSelector = cs.getCssSelector([element]); + return CSSSelector; + } else { + throw 'Invalid clickElementUniquenessType ' + this.clickElementUniquenessType; + } + } + + isAdded(element) { + let elementUniqueId = this.getElementUniqueId(element); + let isAdded = elementUniqueId in this.addedElements; + return isAdded; + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..fde72601 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,126 @@ +const webpack = require('webpack'); +const ejs = require('ejs'); +const path = require('path'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const ExtensionReloader = require('webpack-extension-reloader'); +const { version } = require('./package.json'); + +function transformHtml(content) { + return ejs.render(content.toString(), { + ...process.env, + }); +} + +const config = { + mode: process.env.NODE_ENV, + context: path.join(__dirname, '/src'), + entry: { + 'background/background': './background/background.js', + 'devtools/devtools': './devtools/devtools.js', + 'devtools/app': './scripts/App.js', + 'options/options': './options/options.js', + 'content_script/content_script': './content_script/content_script.js', + }, + output: { + path: path.join(__dirname, '/dist'), + filename: '[name].js', + }, + resolve: { + extensions: ['.js'], + }, + module: { + rules: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/, + }, + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, 'css-loader'], + }, + { + test: /\.scss$/, + use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], + }, + { + test: /\.sass$/, + use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader?indentedSyntax'], + }, + { + test: /\.(png|jpg|jpeg|gif|svg|ico)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: '/icons/', + emitFile: false, + }, + }, + { + test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/, + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: '/fonts/', + emitFile: false, + }, + }, + ], + }, + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery', + }), + new webpack.DefinePlugin({ + global: 'window', + }), + new MiniCssExtractPlugin({ + filename: '[name].css', + }), + new CopyWebpackPlugin([ + { from: 'icons', to: 'icons', ignore: ['icon.xcf'] }, + { from: 'devtools/views', to: 'devtools/views/', transform: transformHtml }, + { from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml }, + { from: 'options/options.html', to: 'options/options.html', transform: transformHtml }, + { from: 'devtools/panel.html', to: 'devtools/panel.html', transform: transformHtml }, + { from: 'devtools/devtools.html', to: 'devtools/devtools.html', transform: transformHtml }, + { + from: 'manifest.json', + to: 'manifest.json', + transform: content => { + const jsonContent = JSON.parse(content); + jsonContent.version = version; + + if (config.mode === 'development') { + jsonContent.content_security_policy = "script-src 'self' 'unsafe-eval'; object-src 'self'"; + } + + return JSON.stringify(jsonContent, null, 2); + }, + }, + ]), + ], +}; + +if (config.mode === 'production') { + config.plugins = (config.plugins || []).concat([ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: '"production"', + }, + }), + ]); +} + +if (process.env.HMR === 'true') { + config.plugins = (config.plugins || []).concat([ + new ExtensionReloader({ + manifest: path.join(__dirname, '/src/manifest.json'), + }), + ]); +} + +module.exports = config; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..47c7396f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6796 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/compat-data@^7.8.4": + version "7.8.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.5.tgz#d28ce872778c23551cbb9432fc68d28495b613b9" + integrity sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg== + dependencies: + browserslist "^4.8.5" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@^7.1.2": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== + dependencies: + "@babel/types" "^7.8.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-call-delegate@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" + integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-compilation-targets@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88" + integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg== + dependencies: + "@babel/compat-data" "^7.8.4" + browserslist "^4.8.5" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-regexp-features-plugin@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" + integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== + dependencies: + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.6.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== + dependencies: + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" + integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" + integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543" + integrity sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" + integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" + integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" + integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" + integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-modules-amd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" + integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" + integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" + integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" + integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== + dependencies: + "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" + integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/preset-env@^7.1.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" + integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== + dependencies: + "@babel/compat-data" "^7.8.4" + "@babel/helper-compilation-targets" "^7.8.4" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.8.4" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/plugin-transform-modules-systemjs" "^7.8.3" + "@babel/plugin-transform-modules-umd" "^7.8.3" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.4" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/types" "^7.8.3" + browserslist "^4.8.5" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/runtime-corejs3@^7.4.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz#ccc4e042e2fae419c67fa709567e5d2179ed3940" + integrity sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.2" + +"@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.4" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.0.0", "@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@types/anymatch@*": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" + integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== + +"@types/node@*": + version "12.12.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.8.tgz#dab418655af39ce2fa99286a0bed21ef8072ac9d" + integrity sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/tapable@*": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" + integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== + +"@types/uglify-js@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" + integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ== + dependencies: + source-map "^0.6.1" + +"@types/webpack-sources@*", "@types/webpack-sources@^0.1.5": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.6.tgz#3d21dfc2ec0ad0c77758e79362426a9ba7d7cbcb" + integrity sha512-FtAWR7wR5ocJ9+nP137DV81tveD/ZgB1sadnJ/axUGM3BUVfRPx8oQNMtv3JNfTeHx3VP7cXiyfR/jmtEsVHsQ== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" + +"@types/webpack@^4.39.8": + version "4.41.6" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.6.tgz#c76afbdef59159d12e3e1332dc264b75574722a2" + integrity sha512-iWRpV5Ej+8uKrgxp6jXz3v7ZTjgtuMXY+rsxQjFNU0hYCnHkpA7vtiNffgxjuxX4feFHBbz0IF76OzX2OqDYPw== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abstract-leveldown@^6.2.1, abstract-leveldown@~6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.2.tgz#677425beeb28204367c7639e264e93ea4b49971a" + integrity sha512-/a+Iwj0rn//CX0EJOasNyZJd2o8xur8Ce9C57Sznti/Ilt/cb6Qd8/k98A4ZOklXgTG+iAYYUs1OTG0s1eH+zQ== + dependencies: + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +abstract-leveldown@~6.0.0, abstract-leveldown@~6.0.1: + version "6.0.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz#b4b6159343c74b0c5197b2817854782d8f748c4a" + integrity sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q== + dependencies: + level-concat-iterator "~2.0.0" + xtend "~4.0.0" + +acorn-jsx@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" + integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== + +acorn@^6.0.7, acorn@^6.2.1: + version "6.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" + integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= + +ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + +ajv@^6.1.0: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^6.10.2, ajv@^6.5.5, ajv@^6.9.1: + version "6.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" + integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA== + dependencies: + 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@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-3.1.1.tgz#9db7819d4daf60aec10fe86b16cb9258ced66ea0" + integrity sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg== + dependencies: + archiver-utils "^2.1.0" + async "^2.6.3" + buffer-crc32 "^0.2.1" + glob "^7.1.4" + readable-stream "^3.4.0" + tar-stream "^2.1.0" + zip-stream "^2.1.2" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argsarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" + integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs= + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-differ@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-2.1.0.tgz#4b9c1c3f14b906757082925769e8ab904f4801b1" + integrity sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w== + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-find@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" + integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg= + +array-includes@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-union@^1.0.1, array-union@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +array.prototype.flat@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + +async@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + +babel-eslint@^10.0.1: + version "10.0.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" + integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-loader@^8.0.2: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== + +bl@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" + integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A== + dependencies: + readable-stream "^3.0.1" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +bluebird@^3.5.1, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +bootstrap@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.1.1.tgz#17e14ed261c0fcd9b52ea9aa6420f6d51cd5fa77" + integrity sha1-F+FO0mHA/Nm1LqmqZCD21RzV+nc= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + 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@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.8.3, browserslist@^4.8.5: + version "4.8.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.7.tgz#ec8301ff415e6a42c949d0e66b405eb539c532d0" + integrity sha512-gFOnZNYBHrEyUML0xr5NJ6edFaaKbTFX9S9kQHlYfCP0Rit/boRIz4G+Avq6/4haEKJXdGGUnoolx+5MWW2BoA== + dependencies: + caniuse-lite "^1.0.30001027" + electron-to-chromium "^1.3.349" + node-releases "^1.1.49" + +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-from@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.1.0: + version "5.4.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" + integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^12.0.2: + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^5.0.0, camelcase@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-lite@^1.0.30001027: + version "1.0.30001027" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz#283e2ef17d94889cc216a22c6f85303d78ca852d" + integrity sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +chrome-trace-event@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-buffer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +coalescy@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/coalescy/-/coalescy-1.0.0.tgz#4b065846b836361ada6c4b4a4abf4bc1cac31bf1" + integrity sha1-SwZYRrg2NhrabEtKSr9LwcrDG/E= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +colors@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +compress-commons@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610" + integrity sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^3.0.1" + normalize-path "^3.0.0" + readable-stream "^2.3.6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +confusing-browser-globals@^1.0.5: + version "1.0.9" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" + integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-webpack-plugin@^4.5.3: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + globby "^7.1.1" + is-glob "^4.0.0" + loader-utils "^1.1.0" + minimatch "^3.0.4" + p-limit "^1.0.0" + serialize-javascript "^1.4.0" + +core-js-compat@^3.6.2: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== + dependencies: + browserslist "^4.8.3" + semver "7.0.0" + +core-js-pure@^3.0.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" + integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== + +core-js@^3.0.1: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647" + integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +crc32-stream@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85" + integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w== + dependencies: + crc "^3.4.4" + readable-stream "^3.4.0" + +crc@^3.4.4: + version "3.8.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== + dependencies: + buffer "^5.1.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + 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@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + 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" + +cross-env@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.1.tgz#b2c76c1ca7add66dc874d11798466094f551b34d" + integrity sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ== + dependencies: + cross-spawn "^6.0.5" + +cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + 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-loader@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== + dependencies: + camelcase "^5.2.0" + icss-utils "^4.1.0" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.14" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^2.0.0" + postcss-value-parser "^3.3.0" + schema-utils "^1.0.0" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +d3@^3.3.8: + version "3.5.17" + resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8" + integrity sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1, debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +deferred-leveldown@~5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.0.1.tgz#1642eb18b535dfb2b6ac4d39fb10a9cbcfd13b09" + integrity sha512-BXohsvTedWOLkj2n/TY+yqVlrCWa2Zs8LSxh3uCAgFOru7/pjxKyZAexGa1j83BaKloER4PqUyQ9rGPJLt9bqA== + dependencies: + abstract-leveldown "~6.0.0" + inherits "^2.0.3" + +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== + dependencies: + abstract-leveldown "~6.2.1" + inherits "^2.0.3" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== + dependencies: + path-type "^3.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +double-ended-queue@2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ejs@^2.6.1: + version "2.7.4" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" + integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== + +electron-to-chromium@^1.3.349: + version "1.3.349" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.349.tgz#663f26a69d348a462df47b4d7ab162a2f29bbcb7" + integrity sha512-uEb2zs6EJ6OZIqaMsCSliYVgzE/f7/s1fLWqtvRtHg/v5KBF2xds974fUnyatfxIDgkqzQVwFtam5KExqywx0Q== + +elliptic@^6.0.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + 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" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== + dependencies: + abstract-leveldown "^6.2.1" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +end-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/end-stream/-/end-stream-0.1.0.tgz#32003f3f438a2b0143168137f8fa6e9866c81ed5" + integrity sha1-MgA/P0OKKwFDFoE3+PpumGbIHtU= + dependencies: + write-stream "~0.4.3" + +enhanced-resolve@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4= + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +errno@^0.1.3, errno@~0.1.1, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1: + version "1.17.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" + integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-denodeify@^0.1.1: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" + integrity sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-airbnb-base@^13.0.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz#f6ea81459ff4dec2dda200c35f1d8f7419d57943" + integrity sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w== + dependencies: + confusing-browser-globals "^1.0.5" + object.assign "^4.1.0" + object.entries "^1.1.0" + +eslint-config-prettier@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.3.0.tgz#c55c1fcac8ce4518aeb77906984e134d9eb5a4f0" + integrity sha512-sZwhSTHVVz78+kYD3t5pCWSYEdVSBR0PXnwjDRsUs8ytIrK8PLXw+6FKp8r3Z7rx4ZszdetWlXYKOHoUrrwPlA== + dependencies: + get-stdin "^6.0.0" + +eslint-friendly-formatter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/eslint-friendly-formatter/-/eslint-friendly-formatter-4.0.1.tgz#27d504dc837f7caddbf201b2e84a4ee730ba3efa" + integrity sha1-J9UE3IN/fK3b8gGy6EpO5zC6Pvo= + dependencies: + chalk "^2.0.1" + coalescy "1.0.0" + extend "^3.0.0" + minimist "^1.2.0" + strip-ansi "^4.0.0" + text-table "^0.2.0" + +eslint-import-resolver-node@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" + integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-import-resolver-webpack@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.10.1.tgz#4cbceed2c0c43e488a74775c30861e58e00fb290" + integrity sha512-RN49nnyQpBCP3TqVhct+duJjH8kaVg08fFevWvA+4Cr1xeN7OFQRse4wMvzBto9/4VmOJWvqPfdmNTEG3jc8SQ== + dependencies: + array-find "^1.0.0" + debug "^2.6.8" + enhanced-resolve "~0.9.0" + find-root "^1.1.0" + has "^1.0.1" + interpret "^1.0.0" + lodash "^4.17.4" + node-libs-browser "^1.0.0 || ^2.0.0" + resolve "^1.4.0" + semver "^5.3.0" + +eslint-loader@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337" + integrity sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg== + dependencies: + loader-fs-cache "^1.0.0" + loader-utils "^1.0.2" + object-assign "^4.0.1" + object-hash "^1.1.4" + rimraf "^2.6.1" + +eslint-module-utils@^2.4.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708" + integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.16.0: + version "2.20.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3" + integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== + dependencies: + array-includes "^3.0.3" + array.prototype.flat "^1.2.1" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.1" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.0" + read-pkg-up "^2.0.0" + resolve "^1.12.0" + +eslint-plugin-prettier@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" + integrity sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.1.0.tgz#c5c0b66f383e7656404f86b31334d72524eddb48" + integrity sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +events@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-future@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fast-future/-/fast-future-1.0.2.tgz#8435a9aaa02d79248d17d704e76259301d99280a" + integrity sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fetch-cookie@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.0.tgz#a6fc137ad8363aa89125864c6451b86ecb7de802" + integrity sha512-Mm5pGlT3agW6t71xVM7vMZPIvI7T4FaTuFW4jari6dVzYHFDb3WZZsGpN22r/o3XMdkM0E7sPd1EGeyVbH2Tgg== + dependencies: + es6-denodeify "^0.1.1" + tough-cookie "^2.3.1" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-loader@^1.1.11: + version "1.1.11" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8" + integrity sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg== + dependencies: + loader-utils "^1.0.2" + schema-utils "^0.4.5" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +get-stdin@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" + integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.4, glob@~7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + 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" + +glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + 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" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0, globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globule@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.1.tgz#90a25338f22b7fbeb527cee63c629aea754d33b9" + integrity sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g== + dependencies: + glob "~7.1.1" + lodash "~4.17.12" + minimatch "~3.0.2" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +graceful-fs@^4.1.15, graceful-fs@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4: + version "2.8.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" + integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +husky@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/husky/-/husky-2.7.0.tgz#c0a9a6a3b51146224e11bba0b46bba546e461d05" + integrity sha512-LIi8zzT6PyFpcYKdvWRCn/8X+6SuG2TgYYMrM6ckEYhlp44UcEduVymZGIZNLiwOUjrEud+78w/AsAiqJA/kRg== + dependencies: + cosmiconfig "^5.2.0" + execa "^1.0.0" + find-up "^3.0.0" + get-stdin "^7.0.0" + is-ci "^2.0.0" + pkg-dir "^4.1.0" + please-upgrade-node "^3.1.1" + read-pkg "^5.1.1" + run-node "^1.0.0" + slash "^3.0.0" + +icanhaz@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/icanhaz/-/icanhaz-0.10.3.tgz#b080e2cfb3035f7e289220ba05245f2883e4f4ba" + integrity sha1-sIDiz7MDX34okiC6BSRfKIPk9Lo= + +iconv-lite@^0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + +icss-utils@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +ignore@^3.3.5, ignore@^3.3.7: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immediate@3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + +immediate@~3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" + integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imports-loader@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.8.0.tgz#030ea51b8ca05977c40a3abfd9b4088fe0be9a69" + integrity sha512-kXWL7Scp8KQ4552ZcdVTeaQCZSLW+e6nJfp3cwUMB673T7Hr98Xjx5JK+ql7ADlJUvj1JS5O01RLbKoutN5QDQ== + dependencies: + loader-utils "^1.0.2" + source-map "^0.6.1" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@^2.0.4, inherits@~2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +interpret@1.2.0, interpret@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jquery-flexdatalist@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/jquery-flexdatalist/-/jquery-flexdatalist-2.2.4.tgz#7f7c3a6a5212f54bd3e91edce7c29e4ea9da2986" + integrity sha1-f3w6alIS9UvT6R7c58KeTqnaKYY= + dependencies: + jquery ">=1.8" + +jquery@>=1.8, jquery@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" + integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== + +js-base64@^2.1.8: + version "2.5.2" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209" + integrity sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.0, js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" + integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== + dependencies: + minimist "^1.2.0" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + dependencies: + readable-stream "^2.0.5" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +level-codec@9.0.1, level-codec@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.1.tgz#042f4aa85e56d4328ace368c950811ba802b7247" + integrity sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q== + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" + integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== + dependencies: + errno "~0.1.1" + +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" + +level-js@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-js/-/level-js-4.0.1.tgz#3bad57d8bb46ebba7b13bc7442b56f4b45c8a2e0" + integrity sha512-m5JRIyHZn5VnCCFeRegJkn5bQd3MJK5qZX12zg3Oivc8+BUIS2yFS6ANMMeHX2ieGxucNvEn6/ZnyjmZQLLUWw== + dependencies: + abstract-leveldown "~6.0.1" + immediate "~3.2.3" + inherits "^2.0.3" + ltgt "^2.1.2" + typedarray-to-buffer "~3.1.5" + +level-packager@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.0.tgz#9c01c6c8e2380d3196d61e56bd79c2eff4a9d5c3" + integrity sha512-3pbJmDgGvp/lUQNULPoYQZtUbhMI8KoViYDw7Sa0kWl1mPeHWWJF7T/9upWI/NTMuEikkEE/cd6wBvmrW1+ZnQ== + dependencies: + encoding-down "^6.3.0" + levelup "^4.3.2" + +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + +level-write-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/level-write-stream/-/level-write-stream-1.0.0.tgz#3f7fbb679a55137c0feb303dee766e12ee13c1dc" + integrity sha1-P3+7Z5pVE3wP6zA97nZuEu4Twdw= + dependencies: + end-stream "~0.1.0" + +level@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-5.0.1.tgz#8528cc1ee37ac413270129a1eab938c610be3ccb" + integrity sha512-wcak5OQeA4rURGacqS62R/xNHjCYnJSQDBOlm4KNUGJVE9bWv2B04TclqReYejN+oD65PzD4FsqeWoI5wNC5Lg== + dependencies: + level-js "^4.0.0" + level-packager "^5.0.0" + leveldown "^5.0.0" + opencollective-postinstall "^2.0.0" + +leveldown@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.0.2.tgz#c8edc2308c8abf893ffc81e66ab6536111cae92c" + integrity sha512-Ib6ygFYBleS8x2gh3C1AkVsdrUShqXpe6jSTnZ6sRycEXKhqVf+xOSkhgSnjidpPzyv0d95LJVFrYQ4NuXAqHA== + dependencies: + abstract-leveldown "~6.0.0" + fast-future "~1.0.2" + napi-macros "~1.8.1" + node-gyp-build "~3.8.0" + +leveldown@^5.0.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.4.1.tgz#83a8fdd9bb52b1ed69be2ef59822b6cdfcdb51ec" + integrity sha512-3lMPc7eU3yj5g+qF1qlALInzIYnkySIosR1AsUKFjL9D8fYbTLuENBAeDRZXIG4qeWOAyqRItOoLu2v2avWiMA== + dependencies: + abstract-leveldown "~6.2.1" + napi-macros "~2.0.0" + node-gyp-build "~4.1.0" + +levelup@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.0.2.tgz#bcb8d28d0a82ee97f1c6d00f20ea6d32c2803c5b" + integrity sha512-cx9PmLENwbGA3svWBEbeO2HazpOSOYSXH4VA+ahVpYyurvD+SDSfURl29VBY2qgyk+Vfy2dJd71SBRckj/EZVA== + dependencies: + deferred-leveldown "~5.0.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + xtend "~4.0.0" + +levelup@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.3.2.tgz#31c5b1b29f146d1d35d692e01a6da4d28fa55ebd" + integrity sha512-cRTjU4ktWo59wf13PHEiOayHC3n0dOh4i5+FHr4tv4MX9+l7mqETicNq3Aj07HKlLdk0z5muVoDL2RD+ovgiyA== + dependencies: + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-fs-cache@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz#54cedf6b727e1779fd8f01205f05f6e88706f086" + integrity sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw== + dependencies: + find-cache-dir "^0.1.1" + mkdirp "0.5.1" + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@~4.17.12: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +ltgt@2.2.1, ltgt@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= + +memory-fs@^0.4.0, memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.43.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + dependencies: + mime-db "1.43.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@^0.4.4: + version "0.4.5" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz#c99e9e78d54f3fa775633aee5933aeaa4e80719a" + integrity sha512-dqBanNfktnp2hwL2YguV9Jh91PFX7gu7nRLs4TGsbAfAG6WOtlynFRYzwDwmmeSb5uIwHo9nx1ta0f7vAZVp2w== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +mri@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" + integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multimatch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b" + integrity sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA== + dependencies: + array-differ "^2.0.3" + array-union "^1.0.2" + arrify "^1.0.1" + minimatch "^3.0.4" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +nan@^2.13.2: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nan@^2.9.2: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +napi-macros@~1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-1.8.2.tgz#299265c1d8aa401351ad0675107d751228c03eda" + integrity sha512-Tr0DNY4RzTaBG2W2m3l7ZtFuJChTH6VZhXVhkGGjF/4cZTt+i8GcM9ozD+30Lmr4mDoZ5Xx34t2o4GJqYWDGcg== + +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +neo-async@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +neo-async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.4.1.tgz#b2e38f1117b8acbedbe0524f041fb3177188255d" + integrity sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw== + +node-gyp-build@~3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.8.0.tgz#0f57efeb1971f404dfcbfab975c284de7c70f14a" + integrity sha512-bYbpIHyRqZ7sVWXxGpz8QIRug5JZc/hzZH4GbdT9HTZi6WmKCZ8GLvP8OZ9TTiIBvwPFKgtGrlWQSXDAvYdsPw== + +node-gyp-build@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" + integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== + +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +"node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.1.49: + version "1.1.49" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.49.tgz#67ba5a3fac2319262675ef864ed56798bb33b93e" + integrity sha512-xH8t0LS0disN0mtRCh+eByxFPie+msJUBL/lJDBuap53QGiYPa9joh83K4pCZgWJ+2L4b9h88vCVdXQ60NO2bg== + dependencies: + semver "^6.3.0" + +node-sass@^4.9.3: + version "4.13.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3" + integrity sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash "^4.17.15" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.13.2" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== + +npm-packlist@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-hash@^1.1.4: + version "1.3.1" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" + integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +opencollective-postinstall@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" + integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== + +optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + 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@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.0.0, p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + +p-limit@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.7.tgz#2473439021b57f1516c82f58be7275ad8ef1bb27" + integrity sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ== + +papaparse@^4.1.0: + version "4.6.3" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781" + integrity sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + 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@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= + dependencies: + find-up "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +please-upgrade-node@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-value-parser "^3.3.1" + +postcss-modules-scope@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^7.0.6" + +postcss-selector-parser@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" + integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +pouchdb@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.1.1.tgz#f5f8dcd1fc440fb76651cb26f6fc5d97a39cd6ce" + integrity sha512-8bXWclixNJZqokvxGHRsG19zehSJiaZaz4dVYlhXhhUctz7gMcNTElHjPBzBdZlKKvt9aFDndmXN1VVE53Co8g== + dependencies: + argsarray "0.0.1" + buffer-from "1.1.0" + clone-buffer "1.0.0" + double-ended-queue "2.1.0-0" + fetch-cookie "0.7.0" + immediate "3.0.6" + inherits "2.0.3" + level "5.0.1" + level-codec "9.0.1" + level-write-stream "1.0.0" + leveldown "5.0.2" + levelup "4.0.2" + ltgt "2.2.1" + node-fetch "2.4.1" + readable-stream "1.0.33" + spark-md5 "3.0.0" + through2 "3.0.1" + uuid "3.2.1" + vuvuzela "1.0.3" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^1.17.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +pretty-quick@^1.8.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-1.11.1.tgz#462ffa2b93d24c05b7a0c3a001e08601a0c55ee4" + integrity sha512-kSXCkcETfak7EQXz6WOkCeCqpbC4GIzrN/vaneTGMP/fAtD8NerA9bPhCUqHAks1geo7biZNl5uEMPceeneLuA== + dependencies: + chalk "^2.3.0" + execa "^0.8.0" + find-up "^2.1.0" + ignore "^3.3.7" + mri "^1.1.0" + multimatch "^3.0.0" + +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.4.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" + integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + 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" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read-pkg@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + 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" + +readable-stream@1.0.33: + version "1.0.33" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.33.tgz#3a360dd66c1b1d7fd4705389860eda1d0f61126c" + integrity sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@2 || 3", readable-stream@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + 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" + +readable-stream@^3.0.1, readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~0.0.2: + version "0.0.4" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-0.0.4.tgz#f32d76e3fb863344a548d79923007173665b3b8d" + integrity sha1-8y124/uGM0SlSNeZIwBxc2ZbO40= + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regenerate-unicode-properties@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + +regenerator-transform@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" + integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== + dependencies: + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpu-core@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" + integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.1.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + +regjsgen@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + +regjsparser@^0.6.0: + version "0.6.3" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.3.tgz#74192c5805d35e9f5ebe3c1fb5b40d40a8a38460" + integrity sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request@^2.87.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + 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@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" + integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + dependencies: + path-parse "^1.0.6" + +resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.4.0: + version "1.15.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@2.6.3, rimraf@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +run-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" + integrity sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A== + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.4.0: + version "6.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" + integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@^7.1.0: + version "7.3.1" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.3.1.tgz#a5bf68a04bcea1c13ff842d747150f7ab7d0d23f" + integrity sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA== + dependencies: + clone-deep "^4.0.1" + loader-utils "^1.0.1" + neo-async "^2.5.0" + pify "^4.0.1" + semver "^6.3.0" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^0.4.5: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.1: + version "2.6.4" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" + integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +serialize-javascript@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" + integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== + +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.12: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spark-md5@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef" + integrity sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + 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" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +sugar@^1.4.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sugar/-/sugar-1.5.0.tgz#d9d3fba10f7a887e06e6adfb078a27acb1fc0556" + integrity sha1-2dP7oQ96iH4G5q37B4onrLH8BVY= + +supports-color@6.1.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tapable@^0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q= + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar-stream@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" + integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== + dependencies: + bl "^3.0.0" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser@^4.1.2: + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +tmp@0.0.x, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@^2.3.1, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +typedarray-to-buffer@~3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +unique-filename@^1.1.0, unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +useragent@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== + dependencies: + lru-cache "4.1.x" + tmp "0.0.x" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +uuid@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== + +uuid@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" + integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + +val-loader@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-2.1.0.tgz#2e5f50b6d78b318a441f17fb680ec1ddc901a934" + integrity sha512-eZmzjMSDiRJygGwEqMav043IJ6TjZE7ofMSRi6CDkeN/tSeTqObC/R43NkrkRTE9jlZO8oLPPJ8pONBf9PApPw== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.6.1" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +vuvuzela@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" + integrity sha1-O+FF5YJxxzylUnndhR8SpoIRSws= + +watchpack@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +web-ext-types@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/web-ext-types/-/web-ext-types-2.3.0.tgz#3d7e62d82f272e3d6056be2e0f92e8036651f7e0" + integrity sha512-a0tUp0fQXUgGH53TuXienngvqSkiNs3xDpSIA4U5+c+AfFiniNh+YMVrVcLgFTIXRyIeFkpYZe8IzwiuULomAg== + +webextension-polyfill@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.5.0.tgz#795e0bf6a2b8eadcdb6edaecd169e9228c747519" + integrity sha512-aFrl38x43t1bTboX/paCT8I97+idzX/TY0+fuM52hrIkCpYfROEF9kSn0BXuEIi3J9LTYt2ZZKkhx9NB1qF3nA== + +webextension-polyfill@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.6.0.tgz#1afd925f3274a0d4848083579b9c0b649a5c6763" + integrity sha512-PlYwiX8e4bNZrEeBFxbFFsLtm0SMPxJliLTGdNCA0Bq2XkWrAn2ejUd+89vZm+8BnfFB1BclJyCz3iKsm2atNg== + +webpack-cli@^3.1.2: + version "3.3.11" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.11.tgz#3bf21889bf597b5d82c38f215135a411edfdc631" + integrity sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g== + dependencies: + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" + +webpack-extension-reloader@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/webpack-extension-reloader/-/webpack-extension-reloader-1.1.4.tgz#f5e5fa580e617c114cc45ddb6eb25c5d6a4dd2f6" + integrity sha512-PyssJvAiKhztc//QmhpU8yfg7LBR7Bn/cjSM7jadfQJPIDNN1Djxc+SJQRk8uHQ3GQbyWhsWu2DLCMBRcWHIPA== + dependencies: + "@types/webpack" "^4.39.8" + "@types/webpack-sources" "^0.1.5" + colors "^1.4.0" + lodash "^4.17.15" + minimist "^1.2.0" + useragent "^2.3.0" + webextension-polyfill "^0.5.0" + webpack-sources "^1.4.3" + ws "^7.2.0" + +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.20.2: + version "4.41.6" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.6.tgz#12f2f804bf6542ef166755050d4afbc8f66ba7e1" + integrity sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.2.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.1" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.3" + watchpack "^1.6.0" + webpack-sources "^1.4.1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-stream@~0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/write-stream/-/write-stream-0.4.3.tgz#83cc8c0347d0af6057a93862b4e3ae01de5c81c1" + integrity sha1-g8yMA0fQr2BXqThitOOuAd5cgcE= + dependencies: + readable-stream "~0.0.2" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^7.2.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" + integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A== + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^13.1.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + +yargs@13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + 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.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +zip-stream@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b" + integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q== + dependencies: + archiver-utils "^2.1.0" + compress-commons "^2.1.1" + readable-stream "^3.4.0"