diff --git a/.dependabot/config.yml b/.dependabot/config.yml
new file mode 100644
index 000000000..49ddd61b0
--- /dev/null
+++ b/.dependabot/config.yml
@@ -0,0 +1,11 @@
+---
+version: 1
+update_configs:
+ - package_manager: "javascript"
+ directory: "/"
+ update_schedule: "live"
+ default_reviewers:
+ - "markmcdowell"
+ commit_message:
+ prefix: "chore"
+ include_scope: true
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..9cfd3227a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,34 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+
+# Matches multiple files with brace expansion notation
+# Set default charset
+[*.{js,ts,py}]
+charset = utf-8
+
+# 4 space indentation
+[*.py]
+indent_style = space
+indent_size = 4
+
+# Tab indentation (no size specified)
+[Makefile]
+indent_style = tab
+
+# Indentation override for all JS, TS
+[*.{js,ts,tsx}]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_style = space
+indent_size = 2
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..94a82bed7
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,23 @@
+---
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 60
+
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - pinned
+ - security
+
+# Label to use when marking an issue as stale
+staleLabel: wontfix
+
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 000000000..181da289b
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,26 @@
+---
+name: Node CI
+
+on: [push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [8.x, 10.x, 12.x]
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: npm ci, build, and test
+ run: |
+ npm ci
+ npm run build --if-present
+ npm test
+ env:
+ CI: true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..09c09a023
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,66 @@
+# Logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Typescript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# build output
+dist/
+lib/
+server.js
+dump.rdb
+
+# ignore mac files
+.DS_Store
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000..e50272b0b
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "chrome",
+ "request": "launch",
+ "name": "Launch Chrome against localhost",
+ "url": "http://localhost:8000",
+ "webRoot": "${workspaceFolder}"
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..bf830bfcd
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "editor.codeActionsOnSave": {
+ "source.fixAll.tslint": true,
+ }
+}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..9cbfe6b00
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at support@reactivemarkets.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..9b7340d69
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,21 @@
+# Contributing
+
+We welcome all contributions!
+
+Before creating a PR, please raise an issue to discuss it.
+
+## Style
+
+The codebase is written in typescript, this is set to be strict with all warnings and errors turned on. We also use ts-lint with pretty much all rules turned on. Both are run as part of the build.
+
+You can run `npm run lint` to show any style issues separate from the build.
+
+### Guidelines
+
+* Use Promises instead callbacks
+* Files should be 100 lines or less
+* Everything is testable
+
+## Tests
+
+Tests are using jest, please see existing tests for recommended formatting.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..1ffc51b2f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+https://github.com/reactivemarkets/react-financial-charts
+
+Copyright (c) 2015-2018 Ragu Ramaswamy
+Copyright (c) 2016 Julien Renaux
+Copyright (c) 2019 Reactive Markets
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..b9c4da7e0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,67 @@
+# React Financial Charts
+
+Create highly customizable stock charts.
+
+Built with [React JS](http://facebook.github.io/react/) and [d3](http://d3js.org/)
+
+- integrates multiple chart types
+- over 60 technical indicators and overlays
+- drawing objects
+
+Multiple [quick start examples](https://github.com/rrag/react-stockcharts-examples2)
+
+- svg and canvas for improved performance.
+- pan and zoom, on touch devices too
+
+## Chart types
+
+- Scatter
+- Area
+- Line
+- Candlestick
+- OHLC
+- HeikenAshi
+- Renko
+- Kagi
+- Point & Figure
+
+## Indicators
+
+- EMA, SMA, WMA, TMA
+- Bollinger band
+- SAR
+- MACD
+- RSI
+- ATR
+- Stochastic (fast, slow, full)
+- ForceIndex
+- ElderRay
+- Elder Impulse
+
+## Interactive Indicators
+
+- Trendline
+- Fibonacci Retracements
+- Gann Fan
+- Channel
+- Linear regression channel
+
+---
+
+## Installation
+
+```sh
+npm install react-financial-charts
+```
+
+## Documentation
+
+TODO
+
+## Contributing
+
+Refer to [CONTRIBUTING.md](./CONTRIBUTING.md)
+
+## LICENSE
+
+[ISC](./LICENSE)
diff --git a/lerna.json b/lerna.json
new file mode 100644
index 000000000..082563770
--- /dev/null
+++ b/lerna.json
@@ -0,0 +1,13 @@
+{
+ "packages": [
+ "packages/*"
+ ],
+ "version": "0.0.0",
+ "npmClient": "npm",
+ "useWorkspaces": true,
+ "command": {
+ "bootstrap": {
+ "hoist": true
+ }
+ }
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..3ea3f9222
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,13255 @@
+{
+ "name": "root",
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/core": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz",
+ "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.5.5",
+ "@babel/helpers": "^7.5.5",
+ "@babel/parser": "^7.5.5",
+ "@babel/template": "^7.4.4",
+ "@babel/traverse": "^7.5.5",
+ "@babel/types": "^7.5.5",
+ "convert-source-map": "^1.1.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "json5": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
+ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.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
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz",
+ "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.5.5",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0",
+ "trim-right": "^1.0.1"
+ },
+ "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
+ }
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
+ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.0.0",
+ "@babel/template": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
+ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+ "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
+ "dev": true
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
+ "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.4.4"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz",
+ "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.4.4",
+ "@babel/traverse": "^7.5.5",
+ "@babel/types": "^7.5.5"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz",
+ "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==",
+ "dev": true
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz",
+ "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
+ "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.4.4",
+ "@babel/types": "^7.4.4"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz",
+ "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.5.5",
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-split-export-declaration": "^7.4.4",
+ "@babel/parser": "^7.5.5",
+ "@babel/types": "^7.5.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/types": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@cnakazawa/watch": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz",
+ "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==",
+ "dev": true,
+ "requires": {
+ "exec-sh": "^0.3.2",
+ "minimist": "^1.2.0"
+ }
+ },
+ "@evocateur/libnpmaccess": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz",
+ "integrity": "sha512-KSCAHwNWro0CF2ukxufCitT9K5LjL/KuMmNzSu8wuwN2rjyKHD8+cmOsiybK+W5hdnwc5M1SmRlVCaMHQo+3rg==",
+ "dev": true,
+ "requires": {
+ "@evocateur/npm-registry-fetch": "^4.0.0",
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.0.0",
+ "npm-package-arg": "^6.1.0"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
+ "dev": true
+ }
+ }
+ },
+ "@evocateur/libnpmpublish": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@evocateur/libnpmpublish/-/libnpmpublish-1.2.2.tgz",
+ "integrity": "sha512-MJrrk9ct1FeY9zRlyeoyMieBjGDG9ihyyD9/Ft6MMrTxql9NyoEx2hw9casTIP4CdqEVu+3nQ2nXxoJ8RCXyFg==",
+ "dev": true,
+ "requires": {
+ "@evocateur/npm-registry-fetch": "^4.0.0",
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.0.0",
+ "lodash.clonedeep": "^4.5.0",
+ "normalize-package-data": "^2.4.0",
+ "npm-package-arg": "^6.1.0",
+ "semver": "^5.5.1",
+ "ssri": "^6.0.1"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
+ "dev": true
+ }
+ }
+ },
+ "@evocateur/npm-registry-fetch": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@evocateur/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz",
+ "integrity": "sha512-k1WGfKRQyhJpIr+P17O5vLIo2ko1PFLKwoetatdduUSt/aQ4J2sJrJwwatdI5Z3SiYk/mRH9S3JpdmMFd/IK4g==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.3.4",
+ "bluebird": "^3.5.1",
+ "figgy-pudding": "^3.4.1",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^5.0.0",
+ "npm-package-arg": "^6.1.0",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "@evocateur/pacote": {
+ "version": "9.6.5",
+ "resolved": "https://registry.npmjs.org/@evocateur/pacote/-/pacote-9.6.5.tgz",
+ "integrity": "sha512-EI552lf0aG2nOV8NnZpTxNo2PcXKPmDbF9K8eCBFQdIZwHNGN/mi815fxtmUMa2wTa1yndotICIDt/V0vpEx2w==",
+ "dev": true,
+ "requires": {
+ "@evocateur/npm-registry-fetch": "^4.0.0",
+ "bluebird": "^3.5.3",
+ "cacache": "^12.0.3",
+ "chownr": "^1.1.2",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.1.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^5.0.0",
+ "minimatch": "^3.0.4",
+ "minipass": "^2.3.5",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "normalize-package-data": "^2.5.0",
+ "npm-package-arg": "^6.1.0",
+ "npm-packlist": "^1.4.4",
+ "npm-pick-manifest": "^3.0.0",
+ "osenv": "^0.1.5",
+ "promise-inflight": "^1.0.1",
+ "promise-retry": "^1.1.1",
+ "protoduck": "^5.0.1",
+ "rimraf": "^2.6.3",
+ "safe-buffer": "^5.2.0",
+ "semver": "^5.7.0",
+ "ssri": "^6.0.1",
+ "tar": "^4.4.10",
+ "unique-filename": "^1.1.1",
+ "which": "^1.3.1"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "@jest/console": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
+ "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==",
+ "dev": true,
+ "requires": {
+ "@jest/source-map": "^24.9.0",
+ "chalk": "^2.0.1",
+ "slash": "^2.0.0"
+ }
+ },
+ "@jest/core": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz",
+ "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==",
+ "dev": true,
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/reporters": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/transform": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.1.15",
+ "jest-changed-files": "^24.9.0",
+ "jest-config": "^24.9.0",
+ "jest-haste-map": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve": "^24.9.0",
+ "jest-resolve-dependencies": "^24.9.0",
+ "jest-runner": "^24.9.0",
+ "jest-runtime": "^24.9.0",
+ "jest-snapshot": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-validate": "^24.9.0",
+ "jest-watcher": "^24.9.0",
+ "micromatch": "^3.1.10",
+ "p-each-series": "^1.0.0",
+ "realpath-native": "^1.1.0",
+ "rimraf": "^2.5.4",
+ "slash": "^2.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "@jest/environment": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz",
+ "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==",
+ "dev": true,
+ "requires": {
+ "@jest/fake-timers": "^24.9.0",
+ "@jest/transform": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "jest-mock": "^24.9.0"
+ }
+ },
+ "@jest/fake-timers": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz",
+ "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-mock": "^24.9.0"
+ }
+ },
+ "@jest/reporters": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz",
+ "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==",
+ "dev": true,
+ "requires": {
+ "@jest/environment": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/transform": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "glob": "^7.1.2",
+ "istanbul-lib-coverage": "^2.0.2",
+ "istanbul-lib-instrument": "^3.0.1",
+ "istanbul-lib-report": "^2.0.4",
+ "istanbul-lib-source-maps": "^3.0.1",
+ "istanbul-reports": "^2.2.6",
+ "jest-haste-map": "^24.9.0",
+ "jest-resolve": "^24.9.0",
+ "jest-runtime": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-worker": "^24.6.0",
+ "node-notifier": "^5.4.2",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.0",
+ "string-length": "^2.0.0"
+ }
+ },
+ "@jest/source-map": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz",
+ "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0",
+ "graceful-fs": "^4.1.15",
+ "source-map": "^0.6.0"
+ }
+ },
+ "@jest/test-result": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz",
+ "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==",
+ "dev": true,
+ "requires": {
+ "@jest/console": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "@types/istanbul-lib-coverage": "^2.0.0"
+ }
+ },
+ "@jest/test-sequencer": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz",
+ "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==",
+ "dev": true,
+ "requires": {
+ "@jest/test-result": "^24.9.0",
+ "jest-haste-map": "^24.9.0",
+ "jest-runner": "^24.9.0",
+ "jest-runtime": "^24.9.0"
+ }
+ },
+ "@jest/transform": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz",
+ "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.1.0",
+ "@jest/types": "^24.9.0",
+ "babel-plugin-istanbul": "^5.1.0",
+ "chalk": "^2.0.1",
+ "convert-source-map": "^1.4.0",
+ "fast-json-stable-stringify": "^2.0.0",
+ "graceful-fs": "^4.1.15",
+ "jest-haste-map": "^24.9.0",
+ "jest-regex-util": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "micromatch": "^3.1.10",
+ "pirates": "^4.0.1",
+ "realpath-native": "^1.1.0",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.1",
+ "write-file-atomic": "2.4.1"
+ }
+ },
+ "@jest/types": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz",
+ "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==",
+ "dev": true,
+ "requires": {
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^1.1.1",
+ "@types/yargs": "^13.0.0"
+ }
+ },
+ "@lerna/add": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.16.2.tgz",
+ "integrity": "sha512-RAAaF8aODPogj2Ge9Wj3uxPFIBGpog9M+HwSuq03ZnkkO831AmasCTJDqV+GEpl1U2DvnhZQEwHpWmTT0uUeEw==",
+ "dev": true,
+ "requires": {
+ "@evocateur/pacote": "^9.6.3",
+ "@lerna/bootstrap": "3.16.2",
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/npm-conf": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "dedent": "^0.7.0",
+ "npm-package-arg": "^6.1.0",
+ "p-map": "^2.1.0",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/batch-packages": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/batch-packages/-/batch-packages-3.16.0.tgz",
+ "integrity": "sha512-7AdMkANpubY/FKFI01im01tlx6ygOBJ/0JcixMUWoWP/7Ds3SWQF22ID6fbBr38jUWptYLDs2fagtTDL7YUPuA==",
+ "dev": true,
+ "requires": {
+ "@lerna/package-graph": "3.16.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/bootstrap": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.16.2.tgz",
+ "integrity": "sha512-I+gs7eh6rv9Vyd+CwqL7sftRfOOsSzCle8cv/CGlMN7/p7EAVhxEdAw8SYoHIKHzipXszuqqy1Y3opyleD0qdA==",
+ "dev": true,
+ "requires": {
+ "@lerna/batch-packages": "3.16.0",
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/has-npm-version": "3.16.0",
+ "@lerna/npm-install": "3.16.0",
+ "@lerna/package-graph": "3.16.0",
+ "@lerna/pulse-till-done": "3.13.0",
+ "@lerna/rimraf-dir": "3.14.2",
+ "@lerna/run-lifecycle": "3.16.2",
+ "@lerna/run-parallel-batches": "3.16.0",
+ "@lerna/symlink-binary": "3.16.2",
+ "@lerna/symlink-dependencies": "3.16.2",
+ "@lerna/validation-error": "3.13.0",
+ "dedent": "^0.7.0",
+ "get-port": "^4.2.0",
+ "multimatch": "^3.0.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "p-finally": "^1.0.0",
+ "p-map": "^2.1.0",
+ "p-map-series": "^1.0.0",
+ "p-waterfall": "^1.0.0",
+ "read-package-tree": "^5.1.6",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/changed": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.16.4.tgz",
+ "integrity": "sha512-NCD7XkK744T23iW0wqKEgF4R9MYmReUbyHCZKopFnsNpQdqumc3SOIvQUAkKCP6hQJmYvxvOieoVgy/CVDpZ5g==",
+ "dev": true,
+ "requires": {
+ "@lerna/collect-updates": "3.16.0",
+ "@lerna/command": "3.16.0",
+ "@lerna/listable": "3.16.0",
+ "@lerna/output": "3.13.0",
+ "@lerna/version": "3.16.4"
+ }
+ },
+ "@lerna/check-working-tree": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-3.14.2.tgz",
+ "integrity": "sha512-7safqxM/MYoAoxZxulUDtIJIbnBIgo0PB/FHytueG+9VaX7GMnDte2Bt1EKa0dz2sAyQdmQ3Q8ZXpf/6JDjaeg==",
+ "dev": true,
+ "requires": {
+ "@lerna/collect-uncommitted": "3.14.2",
+ "@lerna/describe-ref": "3.14.2",
+ "@lerna/validation-error": "3.13.0"
+ }
+ },
+ "@lerna/child-process": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-3.14.2.tgz",
+ "integrity": "sha512-xnq+W5yQb6RkwI0p16ZQnrn6HkloH/MWTw4lGE1nKsBLAUbmSU5oTE93W1nrG0X3IMF/xWc9UYvNdUGMWvZZ4w==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.3.1",
+ "execa": "^1.0.0",
+ "strong-log-transformer": "^2.0.0"
+ }
+ },
+ "@lerna/clean": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.16.0.tgz",
+ "integrity": "sha512-5P9U5Y19WmYZr7UAMGXBpY7xCRdlR7zhHy8MAPDKVx70rFIBS6nWXn5n7Kntv74g7Lm1gJ2rsiH5tj1OPcRJgg==",
+ "dev": true,
+ "requires": {
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/prompt": "3.13.0",
+ "@lerna/pulse-till-done": "3.13.0",
+ "@lerna/rimraf-dir": "3.14.2",
+ "p-map": "^2.1.0",
+ "p-map-series": "^1.0.0",
+ "p-waterfall": "^1.0.0"
+ }
+ },
+ "@lerna/cli": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-3.13.0.tgz",
+ "integrity": "sha512-HgFGlyCZbYaYrjOr3w/EsY18PdvtsTmDfpUQe8HwDjXlPeCCUgliZjXLOVBxSjiOvPeOSwvopwIHKWQmYbwywg==",
+ "dev": true,
+ "requires": {
+ "@lerna/global-options": "3.13.0",
+ "dedent": "^0.7.0",
+ "npmlog": "^4.1.2",
+ "yargs": "^12.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.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"
+ }
+ }
+ }
+ },
+ "yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
+ "@lerna/collect-uncommitted": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-3.14.2.tgz",
+ "integrity": "sha512-4EkQu4jIOdNL2BMzy/N0ydHB8+Z6syu6xiiKXOoFl0WoWU9H1jEJCX4TH7CmVxXL1+jcs8FIS2pfQz4oew99Eg==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "chalk": "^2.3.1",
+ "figgy-pudding": "^3.5.1",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/collect-updates": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-3.16.0.tgz",
+ "integrity": "sha512-HwAIl815X2TNlmcp28zCrSdXfoZWNP7GJPEqNWYk7xDJTYLqQ+SrmKUePjb3AMGBwYAraZSEJLbHdBpJ5+cHmQ==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/describe-ref": "3.14.2",
+ "minimatch": "^3.0.4",
+ "npmlog": "^4.1.2",
+ "slash": "^2.0.0"
+ }
+ },
+ "@lerna/command": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.16.0.tgz",
+ "integrity": "sha512-u7tE4GC4/gfbPA9eQg+0ulnoJ+PMoMqomx033r/IxqZrHtmJR9+pF/37S0fsxJ2hX/RMFPC7c9Q/i8NEufSpdQ==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/package-graph": "3.16.0",
+ "@lerna/project": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "@lerna/write-log-file": "3.13.0",
+ "dedent": "^0.7.0",
+ "execa": "^1.0.0",
+ "is-ci": "^2.0.0",
+ "lodash": "^4.17.14",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/conventional-commits": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-3.16.4.tgz",
+ "integrity": "sha512-QSZJ0bC9n6FVaf+7KDIq5zMv8WnHXnwhyL5jG1Nyh3SgOg9q2uflqh7YsYB+G6FwaRfnPaKosh6obijpYg0llA==",
+ "dev": true,
+ "requires": {
+ "@lerna/validation-error": "3.13.0",
+ "conventional-changelog-angular": "^5.0.3",
+ "conventional-changelog-core": "^3.1.6",
+ "conventional-recommended-bump": "^5.0.0",
+ "fs-extra": "^8.1.0",
+ "get-stream": "^4.0.0",
+ "lodash.template": "^4.5.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "pify": "^4.0.1",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/create": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.16.0.tgz",
+ "integrity": "sha512-OZApR1Iz7awutbmj4sAArwhqCyKgcrnw9rH0aWAUrkYWrD1w4TwkvAcYAsfx5GpQGbLQwoXhoyyPwPfZRRWz3Q==",
+ "dev": true,
+ "requires": {
+ "@evocateur/pacote": "^9.6.3",
+ "@lerna/child-process": "3.14.2",
+ "@lerna/command": "3.16.0",
+ "@lerna/npm-conf": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "camelcase": "^5.0.0",
+ "dedent": "^0.7.0",
+ "fs-extra": "^8.1.0",
+ "globby": "^9.2.0",
+ "init-package-json": "^1.10.3",
+ "npm-package-arg": "^6.1.0",
+ "p-reduce": "^1.0.0",
+ "pify": "^4.0.1",
+ "semver": "^6.2.0",
+ "slash": "^2.0.0",
+ "validate-npm-package-license": "^3.0.3",
+ "validate-npm-package-name": "^3.0.0",
+ "whatwg-url": "^7.0.0"
+ },
+ "dependencies": {
+ "globby": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+ "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "array-union": "^1.0.2",
+ "dir-glob": "^2.2.2",
+ "fast-glob": "^2.2.6",
+ "glob": "^7.1.3",
+ "ignore": "^4.0.3",
+ "pify": "^4.0.1",
+ "slash": "^2.0.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "whatwg-url": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ }
+ },
+ "@lerna/create-symlink": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-3.16.2.tgz",
+ "integrity": "sha512-pzXIJp6av15P325sgiIRpsPXLFmkisLhMBCy4764d+7yjf2bzrJ4gkWVMhsv4AdF0NN3OyZ5jjzzTtLNqfR+Jw==",
+ "dev": true,
+ "requires": {
+ "@zkochan/cmd-shim": "^3.1.0",
+ "fs-extra": "^8.1.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/describe-ref": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-3.14.2.tgz",
+ "integrity": "sha512-qa5pzDRK2oBQXNjyRmRnN7E8a78NMYfQjjlRFB0KNHMsT6mCiL9+8kIS39sSE2NqT8p7xVNo2r2KAS8R/m3CoQ==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/diff": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.16.0.tgz",
+ "integrity": "sha512-QUpVs5TPl8vBIne10/vyjUxanQBQQp7Lk3iaB8MnCysKr0O+oy7trWeFVDPEkBTCD177By7yPGyW5Yey1nCBbA==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/command": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/exec": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.16.0.tgz",
+ "integrity": "sha512-mH3O5NXf/O88jBaBBTUf+d56CUkxpg782s3Jxy7HWbVuSUULt3iMRPTh+zEXO5/555etsIVVDDyUR76meklrJA==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/run-topologically": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "p-map": "^2.1.0"
+ }
+ },
+ "@lerna/filter-options": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.16.0.tgz",
+ "integrity": "sha512-InIi1fF8+PxpCwir9bIy+pGxrdE6hvN0enIs1eNGCVS1TTE8osNgiZXa838bMQ1yaEccdcnVX6Z03BNKd56kNg==",
+ "dev": true,
+ "requires": {
+ "@lerna/collect-updates": "3.16.0",
+ "@lerna/filter-packages": "3.16.0",
+ "dedent": "^0.7.0"
+ }
+ },
+ "@lerna/filter-packages": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-3.16.0.tgz",
+ "integrity": "sha512-eGFzQTx0ogkGDCnbTuXqssryR6ilp8+dcXt6B+aq1MaqL/vOJRZyqMm4TY3CUOUnzZCi9S2WWyMw3PnAJOF+kg==",
+ "dev": true,
+ "requires": {
+ "@lerna/validation-error": "3.13.0",
+ "multimatch": "^3.0.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/get-npm-exec-opts": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz",
+ "integrity": "sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw==",
+ "dev": true,
+ "requires": {
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/get-packed": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.16.0.tgz",
+ "integrity": "sha512-AjsFiaJzo1GCPnJUJZiTW6J1EihrPkc2y3nMu6m3uWFxoleklsSCyImumzVZJssxMi3CPpztj8LmADLedl9kXw==",
+ "dev": true,
+ "requires": {
+ "fs-extra": "^8.1.0",
+ "ssri": "^6.0.1",
+ "tar": "^4.4.8"
+ }
+ },
+ "@lerna/github-client": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-3.16.0.tgz",
+ "integrity": "sha512-IVJjcKjkYaUEPJsDyAblHGEFFNKCRyMagbIDm14L7Ab94ccN6i4TKOqAFEJn2SJHYvKKBdp3Zj2zNlASOMe3DA==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@octokit/plugin-enterprise-rest": "^3.6.1",
+ "@octokit/rest": "^16.28.4",
+ "git-url-parse": "^11.1.2",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/gitlab-client": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-3.15.0.tgz",
+ "integrity": "sha512-OsBvRSejHXUBMgwWQqNoioB8sgzL/Pf1pOUhHKtkiMl6aAWjklaaq5HPMvTIsZPfS6DJ9L5OK2GGZuooP/5c8Q==",
+ "dev": true,
+ "requires": {
+ "node-fetch": "^2.5.0",
+ "npmlog": "^4.1.2",
+ "whatwg-url": "^7.0.0"
+ },
+ "dependencies": {
+ "whatwg-url": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ }
+ },
+ "@lerna/global-options": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-3.13.0.tgz",
+ "integrity": "sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ==",
+ "dev": true
+ },
+ "@lerna/has-npm-version": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-3.16.0.tgz",
+ "integrity": "sha512-TIY036dA9J8OyTrZq9J+it2DVKifL65k7hK8HhkUPpitJkw6jwbMObA/8D40LOGgWNPweJWqmlrTbRSwsR7DrQ==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/import": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.16.0.tgz",
+ "integrity": "sha512-trsOmGHzw0rL/f8BLNvd+9PjoTkXq2Dt4/V2UCha254hMQaYutbxcYu8iKPxz9x86jSPlH7FpbTkkHXDsoY7Yg==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/command": "3.16.0",
+ "@lerna/prompt": "3.13.0",
+ "@lerna/pulse-till-done": "3.13.0",
+ "@lerna/validation-error": "3.13.0",
+ "dedent": "^0.7.0",
+ "fs-extra": "^8.1.0",
+ "p-map-series": "^1.0.0"
+ }
+ },
+ "@lerna/init": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.16.0.tgz",
+ "integrity": "sha512-Ybol/x5xMtBgokx4j7/Y3u0ZmNh0NiSWzBFVaOs2NOJKvuqrWimF67DKVz7yYtTYEjtaMdug64ohFF4jcT/iag==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/command": "3.16.0",
+ "fs-extra": "^8.1.0",
+ "p-map": "^2.1.0",
+ "write-json-file": "^3.2.0"
+ }
+ },
+ "@lerna/link": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.16.2.tgz",
+ "integrity": "sha512-eCPg5Lo8HT525fIivNoYF3vWghO3UgEVFdbsiPmhzwI7IQyZro5HWYzLtywSAdEog5XZpd2Bbn0CsoHWBB3gww==",
+ "dev": true,
+ "requires": {
+ "@lerna/command": "3.16.0",
+ "@lerna/package-graph": "3.16.0",
+ "@lerna/symlink-dependencies": "3.16.2",
+ "p-map": "^2.1.0",
+ "slash": "^2.0.0"
+ }
+ },
+ "@lerna/list": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.16.0.tgz",
+ "integrity": "sha512-TkvstoPsgKqqQ0KfRumpsdMXfRSEhdXqOLq519XyI5IRWYxhoqXqfi8gG37UoBPhBNoe64japn5OjphF3rOmQA==",
+ "dev": true,
+ "requires": {
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/listable": "3.16.0",
+ "@lerna/output": "3.13.0"
+ }
+ },
+ "@lerna/listable": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-3.16.0.tgz",
+ "integrity": "sha512-mtdAT2EEECqrJSDm/aXlOUFr1MRE4p6hppzY//Klp05CogQy6uGaKk+iKG5yyCLaOXFFZvG4HfO11CmoGSDWzw==",
+ "dev": true,
+ "requires": {
+ "@lerna/query-graph": "3.16.0",
+ "chalk": "^2.3.1",
+ "columnify": "^1.5.4"
+ }
+ },
+ "@lerna/log-packed": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-3.16.0.tgz",
+ "integrity": "sha512-Fp+McSNBV/P2mnLUYTaSlG8GSmpXM7krKWcllqElGxvAqv6chk2K3c2k80MeVB4WvJ9tRjUUf+i7HUTiQ9/ckQ==",
+ "dev": true,
+ "requires": {
+ "byte-size": "^5.0.1",
+ "columnify": "^1.5.4",
+ "has-unicode": "^2.0.1",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/npm-conf": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.16.0.tgz",
+ "integrity": "sha512-HbO3DUrTkCAn2iQ9+FF/eisDpWY5POQAOF1m7q//CZjdC2HSW3UYbKEGsSisFxSfaF9Z4jtrV+F/wX6qWs3CuA==",
+ "dev": true,
+ "requires": {
+ "config-chain": "^1.1.11",
+ "pify": "^4.0.1"
+ }
+ },
+ "@lerna/npm-dist-tag": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.16.0.tgz",
+ "integrity": "sha512-MQrBkqJJB9+eNphuj9w90QPMOs4NQXMuSRk9NqzeFunOmdDopPCV0Q7IThSxEuWnhJ2n3B7G0vWUP7tNMPdqIQ==",
+ "dev": true,
+ "requires": {
+ "@evocateur/npm-registry-fetch": "^4.0.0",
+ "@lerna/otplease": "3.16.0",
+ "figgy-pudding": "^3.5.1",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/npm-install": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-3.16.0.tgz",
+ "integrity": "sha512-APUOIilZCzDzce92uLEwzt1r7AEMKT/hWA1ThGJL+PO9Rn8A95Km3o2XZAYG4W0hR+P4O2nSVuKbsjQtz8CjFQ==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/get-npm-exec-opts": "3.13.0",
+ "fs-extra": "^8.1.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "signal-exit": "^3.0.2",
+ "write-pkg": "^3.1.0"
+ }
+ },
+ "@lerna/npm-publish": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.16.2.tgz",
+ "integrity": "sha512-tGMb9vfTxP57vUV5svkBQxd5Tzc+imZbu9ZYf8Mtwe0+HYfDjNiiHLIQw7G95w4YRdc5KsCE8sQ0uSj+f2soIg==",
+ "dev": true,
+ "requires": {
+ "@evocateur/libnpmpublish": "^1.2.2",
+ "@lerna/otplease": "3.16.0",
+ "@lerna/run-lifecycle": "3.16.2",
+ "figgy-pudding": "^3.5.1",
+ "fs-extra": "^8.1.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "pify": "^4.0.1",
+ "read-package-json": "^2.0.13"
+ }
+ },
+ "@lerna/npm-run-script": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-3.14.2.tgz",
+ "integrity": "sha512-LbVFv+nvAoRTYLMrJlJ8RiakHXrLslL7Jp/m1R18vYrB8LYWA3ey+nz5Tel2OELzmjUiemAKZsD9h6i+Re5egg==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "@lerna/get-npm-exec-opts": "3.13.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/otplease": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/otplease/-/otplease-3.16.0.tgz",
+ "integrity": "sha512-uqZ15wYOHC+/V0WnD2iTLXARjvx3vNrpiIeyIvVlDB7rWse9mL4egex/QSgZ+lDx1OID7l2kgvcUD9cFpbqB7Q==",
+ "dev": true,
+ "requires": {
+ "@lerna/prompt": "3.13.0",
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "@lerna/output": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/output/-/output-3.13.0.tgz",
+ "integrity": "sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg==",
+ "dev": true,
+ "requires": {
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/pack-directory": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-3.16.4.tgz",
+ "integrity": "sha512-uxSF0HZeGyKaaVHz5FroDY9A5NDDiCibrbYR6+khmrhZtY0Bgn6hWq8Gswl9iIlymA+VzCbshWIMX4o2O8C8ng==",
+ "dev": true,
+ "requires": {
+ "@lerna/get-packed": "3.16.0",
+ "@lerna/package": "3.16.0",
+ "@lerna/run-lifecycle": "3.16.2",
+ "figgy-pudding": "^3.5.1",
+ "npm-packlist": "^1.4.4",
+ "npmlog": "^4.1.2",
+ "tar": "^4.4.10",
+ "temp-write": "^3.4.0"
+ }
+ },
+ "@lerna/package": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.16.0.tgz",
+ "integrity": "sha512-2lHBWpaxcBoiNVbtyLtPUuTYEaB/Z+eEqRS9duxpZs6D+mTTZMNy6/5vpEVSCBmzvdYpyqhqaYjjSLvjjr5Riw==",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^5.3.0",
+ "npm-package-arg": "^6.1.0",
+ "write-pkg": "^3.1.0"
+ },
+ "dependencies": {
+ "load-json-file": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz",
+ "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.15",
+ "parse-json": "^4.0.0",
+ "pify": "^4.0.1",
+ "strip-bom": "^3.0.0",
+ "type-fest": "^0.3.0"
+ }
+ }
+ }
+ },
+ "@lerna/package-graph": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-3.16.0.tgz",
+ "integrity": "sha512-A2mum/gNbv7zCtAwJqoxzqv89As73OQNK2MgSX1SHWya46qoxO9a9Z2c5lOFQ8UFN5ZxqWMfFYXRCz7qzwmFXw==",
+ "dev": true,
+ "requires": {
+ "@lerna/prerelease-id-from-version": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/prerelease-id-from-version": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.16.0.tgz",
+ "integrity": "sha512-qZyeUyrE59uOK8rKdGn7jQz+9uOpAaF/3hbslJVFL1NqF9ELDTqjCPXivuejMX/lN4OgD6BugTO4cR7UTq/sZA==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/project": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.16.0.tgz",
+ "integrity": "sha512-NrKcKK1EqXqhrGvslz6Q36+ZHuK3zlDhGdghRqnxDcHxMPT01NgLcmsnymmQ+gjMljuLRmvKYYCuHrknzX8VrA==",
+ "dev": true,
+ "requires": {
+ "@lerna/package": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "cosmiconfig": "^5.1.0",
+ "dedent": "^0.7.0",
+ "dot-prop": "^4.2.0",
+ "glob-parent": "^5.0.0",
+ "globby": "^9.2.0",
+ "load-json-file": "^5.3.0",
+ "npmlog": "^4.1.2",
+ "p-map": "^2.1.0",
+ "resolve-from": "^4.0.0",
+ "write-json-file": "^3.2.0"
+ },
+ "dependencies": {
+ "globby": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+ "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "array-union": "^1.0.2",
+ "dir-glob": "^2.2.2",
+ "fast-glob": "^2.2.6",
+ "glob": "^7.1.3",
+ "ignore": "^4.0.3",
+ "pify": "^4.0.1",
+ "slash": "^2.0.0"
+ }
+ },
+ "load-json-file": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz",
+ "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.15",
+ "parse-json": "^4.0.0",
+ "pify": "^4.0.1",
+ "strip-bom": "^3.0.0",
+ "type-fest": "^0.3.0"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/prompt": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-3.13.0.tgz",
+ "integrity": "sha512-P+lWSFokdyvYpkwC3it9cE0IF2U5yy2mOUbGvvE4iDb9K7TyXGE+7lwtx2thtPvBAfIb7O13POMkv7df03HJeA==",
+ "dev": true,
+ "requires": {
+ "inquirer": "^6.2.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/publish": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.16.4.tgz",
+ "integrity": "sha512-XZY+gRuF7/v6PDQwl7lvZaGWs8CnX6WIPIu+OCcyFPSL/rdWegdN7HieKBHskgX798qRQc2GrveaY7bNoTKXAw==",
+ "dev": true,
+ "requires": {
+ "@evocateur/libnpmaccess": "^3.1.2",
+ "@evocateur/npm-registry-fetch": "^4.0.0",
+ "@evocateur/pacote": "^9.6.3",
+ "@lerna/check-working-tree": "3.14.2",
+ "@lerna/child-process": "3.14.2",
+ "@lerna/collect-updates": "3.16.0",
+ "@lerna/command": "3.16.0",
+ "@lerna/describe-ref": "3.14.2",
+ "@lerna/log-packed": "3.16.0",
+ "@lerna/npm-conf": "3.16.0",
+ "@lerna/npm-dist-tag": "3.16.0",
+ "@lerna/npm-publish": "3.16.2",
+ "@lerna/otplease": "3.16.0",
+ "@lerna/output": "3.13.0",
+ "@lerna/pack-directory": "3.16.4",
+ "@lerna/prerelease-id-from-version": "3.16.0",
+ "@lerna/prompt": "3.13.0",
+ "@lerna/pulse-till-done": "3.13.0",
+ "@lerna/run-lifecycle": "3.16.2",
+ "@lerna/run-topologically": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "@lerna/version": "3.16.4",
+ "figgy-pudding": "^3.5.1",
+ "fs-extra": "^8.1.0",
+ "npm-package-arg": "^6.1.0",
+ "npmlog": "^4.1.2",
+ "p-finally": "^1.0.0",
+ "p-map": "^2.1.0",
+ "p-pipe": "^1.2.0",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/pulse-till-done": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz",
+ "integrity": "sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA==",
+ "dev": true,
+ "requires": {
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/query-graph": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-3.16.0.tgz",
+ "integrity": "sha512-p0RO+xmHDO95ChJdWkcy9TNLysLkoDARXeRHzY5U54VCwl3Ot/2q8fMCVlA5UeGXDutEyyByl3URqEpcQCWI7Q==",
+ "dev": true,
+ "requires": {
+ "@lerna/package-graph": "3.16.0",
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "@lerna/resolve-symlink": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-3.16.0.tgz",
+ "integrity": "sha512-Ibj5e7njVHNJ/NOqT4HlEgPFPtPLWsO7iu59AM5bJDcAJcR96mLZ7KGVIsS2tvaO7akMEJvt2P+ErwCdloG3jQ==",
+ "dev": true,
+ "requires": {
+ "fs-extra": "^8.1.0",
+ "npmlog": "^4.1.2",
+ "read-cmd-shim": "^1.0.1"
+ }
+ },
+ "@lerna/rimraf-dir": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-3.14.2.tgz",
+ "integrity": "sha512-eFNkZsy44Bu9v1Hrj5Zk6omzg8O9h/7W6QYK1TTUHeyrjTEwytaNQlqF0lrTLmEvq55sviV42NC/8P3M2cvq8Q==",
+ "dev": true,
+ "requires": {
+ "@lerna/child-process": "3.14.2",
+ "npmlog": "^4.1.2",
+ "path-exists": "^3.0.0",
+ "rimraf": "^2.6.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "@lerna/run": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.16.0.tgz",
+ "integrity": "sha512-woTeLlB1OAAz4zzjdI6RyIxSGuxiUPHJZm89E1pDEPoWwtQV6HMdMgrsQd9ATsJ5Ez280HH4bF/LStAlqW8Ufg==",
+ "dev": true,
+ "requires": {
+ "@lerna/command": "3.16.0",
+ "@lerna/filter-options": "3.16.0",
+ "@lerna/npm-run-script": "3.14.2",
+ "@lerna/output": "3.13.0",
+ "@lerna/run-topologically": "3.16.0",
+ "@lerna/timer": "3.13.0",
+ "@lerna/validation-error": "3.13.0",
+ "p-map": "^2.1.0"
+ }
+ },
+ "@lerna/run-lifecycle": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.16.2.tgz",
+ "integrity": "sha512-RqFoznE8rDpyyF0rOJy3+KjZCeTkO8y/OB9orPauR7G2xQ7PTdCpgo7EO6ZNdz3Al+k1BydClZz/j78gNCmL2A==",
+ "dev": true,
+ "requires": {
+ "@lerna/npm-conf": "3.16.0",
+ "figgy-pudding": "^3.5.1",
+ "npm-lifecycle": "^3.1.2",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/run-parallel-batches": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/run-parallel-batches/-/run-parallel-batches-3.16.0.tgz",
+ "integrity": "sha512-2J/Nyv+MvogmQEfC7VcS21ifk7w0HVvzo2yOZRPvkCzGRu/rducxtB4RTcr58XCZ8h/Bt1aqQYKExu3c/3GXwg==",
+ "dev": true,
+ "requires": {
+ "p-map": "^2.1.0",
+ "p-map-series": "^1.0.0"
+ }
+ },
+ "@lerna/run-topologically": {
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-3.16.0.tgz",
+ "integrity": "sha512-4Hlpv4zDtKWa5Z0tPkeu0sK+bxZEKgkNESMGmWrUCNfj7xwvAJurcraK8+a2Y0TFYwf0qjSLY/MzX+ZbJA3Cgw==",
+ "dev": true,
+ "requires": {
+ "@lerna/query-graph": "3.16.0",
+ "figgy-pudding": "^3.5.1",
+ "p-queue": "^4.0.0"
+ }
+ },
+ "@lerna/symlink-binary": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.16.2.tgz",
+ "integrity": "sha512-kz9XVoFOGSF83gg4gBqH+mG6uxfJfTp8Uy+Cam40CvMiuzfODrGkjuBEFoM/uO2QOAwZvbQDYOBpKUa9ZxHS1Q==",
+ "dev": true,
+ "requires": {
+ "@lerna/create-symlink": "3.16.2",
+ "@lerna/package": "3.16.0",
+ "fs-extra": "^8.1.0",
+ "p-map": "^2.1.0"
+ }
+ },
+ "@lerna/symlink-dependencies": {
+ "version": "3.16.2",
+ "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.16.2.tgz",
+ "integrity": "sha512-wnZqGJQ+Jvr1I3inxrkffrFZfmQI7Ta8gySw/UWCy95QtZWF/f5yk8zVIocCAsjzD0wgb3jJE3CFJ9W5iwWk1A==",
+ "dev": true,
+ "requires": {
+ "@lerna/create-symlink": "3.16.2",
+ "@lerna/resolve-symlink": "3.16.0",
+ "@lerna/symlink-binary": "3.16.2",
+ "fs-extra": "^8.1.0",
+ "p-finally": "^1.0.0",
+ "p-map": "^2.1.0",
+ "p-map-series": "^1.0.0"
+ }
+ },
+ "@lerna/timer": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-3.13.0.tgz",
+ "integrity": "sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw==",
+ "dev": true
+ },
+ "@lerna/validation-error": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-3.13.0.tgz",
+ "integrity": "sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA==",
+ "dev": true,
+ "requires": {
+ "npmlog": "^4.1.2"
+ }
+ },
+ "@lerna/version": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.16.4.tgz",
+ "integrity": "sha512-ikhbMeIn5ljCtWTlHDzO4YvTmpGTX1lWFFIZ79Vd1TNyOr+OUuKLo/+p06mCl2WEdZu0W2s5E9oxfAAQbyDxEg==",
+ "dev": true,
+ "requires": {
+ "@lerna/check-working-tree": "3.14.2",
+ "@lerna/child-process": "3.14.2",
+ "@lerna/collect-updates": "3.16.0",
+ "@lerna/command": "3.16.0",
+ "@lerna/conventional-commits": "3.16.4",
+ "@lerna/github-client": "3.16.0",
+ "@lerna/gitlab-client": "3.15.0",
+ "@lerna/output": "3.13.0",
+ "@lerna/prerelease-id-from-version": "3.16.0",
+ "@lerna/prompt": "3.13.0",
+ "@lerna/run-lifecycle": "3.16.2",
+ "@lerna/run-topologically": "3.16.0",
+ "@lerna/validation-error": "3.13.0",
+ "chalk": "^2.3.1",
+ "dedent": "^0.7.0",
+ "minimatch": "^3.0.4",
+ "npmlog": "^4.1.2",
+ "p-map": "^2.1.0",
+ "p-pipe": "^1.2.0",
+ "p-reduce": "^1.0.0",
+ "p-waterfall": "^1.0.0",
+ "semver": "^6.2.0",
+ "slash": "^2.0.0",
+ "temp-write": "^3.4.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "@lerna/write-log-file": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-3.13.0.tgz",
+ "integrity": "sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A==",
+ "dev": true,
+ "requires": {
+ "npmlog": "^4.1.2",
+ "write-file-atomic": "^2.3.0"
+ }
+ },
+ "@mrmlnc/readdir-enhanced": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
+ "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
+ "dev": true,
+ "requires": {
+ "call-me-maybe": "^1.0.1",
+ "glob-to-regexp": "^0.3.0"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
+ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
+ "dev": true
+ },
+ "@octokit/endpoint": {
+ "version": "5.3.5",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.3.5.tgz",
+ "integrity": "sha512-f8KqzIrnzPLiezDsZZPB+K8v8YSv6aKFl7eOu59O46lmlW4HagWl1U6NWl6LmT8d1w7NsKBI3paVtzcnRGO1gw==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^3.0.0",
+ "universal-user-agent": "^4.0.0"
+ },
+ "dependencies": {
+ "is-plain-object": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
+ "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
+ "dev": true,
+ "requires": {
+ "isobject": "^4.0.0"
+ }
+ },
+ "isobject": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
+ "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==",
+ "dev": true
+ }
+ }
+ },
+ "@octokit/plugin-enterprise-rest": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-3.6.2.tgz",
+ "integrity": "sha512-3wF5eueS5OHQYuAEudkpN+xVeUsg8vYEMMenEzLphUZ7PRZ8OJtDcsreL3ad9zxXmBbaFWzLmFcdob5CLyZftA==",
+ "dev": true
+ },
+ "@octokit/request": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.1.0.tgz",
+ "integrity": "sha512-I15T9PwjFs4tbWyhtFU2Kq7WDPidYMvRB7spmxoQRZfxSmiqullG+Nz+KbSmpkfnlvHwTr1e31R5WReFRKMXjg==",
+ "dev": true,
+ "requires": {
+ "@octokit/endpoint": "^5.1.0",
+ "@octokit/request-error": "^1.0.1",
+ "deprecation": "^2.0.0",
+ "is-plain-object": "^3.0.0",
+ "node-fetch": "^2.3.0",
+ "once": "^1.4.0",
+ "universal-user-agent": "^4.0.0"
+ },
+ "dependencies": {
+ "is-plain-object": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
+ "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
+ "dev": true,
+ "requires": {
+ "isobject": "^4.0.0"
+ }
+ },
+ "isobject": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
+ "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==",
+ "dev": true
+ }
+ }
+ },
+ "@octokit/request-error": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz",
+ "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==",
+ "dev": true,
+ "requires": {
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
+ "@octokit/rest": {
+ "version": "16.28.9",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.28.9.tgz",
+ "integrity": "sha512-IKGnX+Tvzt7XHhs8f4ajqxyJvYAMNX5nWfoJm4CQj8LZToMiaJgutf5KxxpxoC3y5w7JTJpW5rnWnF4TsIvCLA==",
+ "dev": true,
+ "requires": {
+ "@octokit/request": "^5.0.0",
+ "@octokit/request-error": "^1.0.2",
+ "atob-lite": "^2.0.0",
+ "before-after-hook": "^2.0.0",
+ "btoa-lite": "^1.0.0",
+ "deprecation": "^2.0.0",
+ "lodash.get": "^4.4.2",
+ "lodash.set": "^4.3.2",
+ "lodash.uniq": "^4.5.0",
+ "octokit-pagination-methods": "^1.1.0",
+ "once": "^1.4.0",
+ "universal-user-agent": "^4.0.0"
+ }
+ },
+ "@types/anymatch": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
+ "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
+ "dev": true
+ },
+ "@types/babel__core": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
+ "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "@types/babel__generator": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz",
+ "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__template": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz",
+ "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__traverse": {
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz",
+ "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.3.0"
+ }
+ },
+ "@types/d3-format": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.1.tgz",
+ "integrity": "sha512-KAWvReOKMDreaAwOjdfQMm0HjcUMlQG47GwqdVKgmm20vTd2pucj0a70c3gUSHrnsmo6H2AMrkBsZU2UhJLq8A==",
+ "dev": true
+ },
+ "@types/d3-time-format": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.1.tgz",
+ "integrity": "sha512-tJSyXta8ZyJ52wDDHA96JEsvkbL6jl7wowGmuf45+fAkj5Y+SQOnz0N7/H68OWmPshPsAaWMQh+GAws44IzH3g==",
+ "dev": true
+ },
+ "@types/events": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
+ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
+ "dev": true
+ },
+ "@types/glob": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
+ "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
+ "dev": true,
+ "requires": {
+ "@types/events": "*",
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/istanbul-lib-coverage": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
+ "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==",
+ "dev": true
+ },
+ "@types/istanbul-lib-report": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz",
+ "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==",
+ "dev": true,
+ "requires": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "@types/istanbul-reports": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz",
+ "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==",
+ "dev": true,
+ "requires": {
+ "@types/istanbul-lib-coverage": "*",
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "@types/jest": {
+ "version": "24.0.18",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz",
+ "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==",
+ "dev": true,
+ "requires": {
+ "@types/jest-diff": "*"
+ }
+ },
+ "@types/jest-diff": {
+ "version": "20.0.1",
+ "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz",
+ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==",
+ "dev": true
+ },
+ "@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "12.7.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz",
+ "integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==",
+ "dev": true
+ },
+ "@types/prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-f8JzJNWVhKtc9dg/dyDNfliTKNOJSLa7Oht/ElZdF/UbMUmAH3rLmAk3ODNjw0mZajDEgatA03tRjB4+Dp/tzA==",
+ "dev": true
+ },
+ "@types/react": {
+ "version": "16.9.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz",
+ "integrity": "sha512-jYP2LWwlh+FTqGd9v7ynUKZzjj98T8x7Yclz479QdRhHfuW9yQ+0jjnD31eXSXutmBpppj5PYNLYLRfnZJvcfg==",
+ "dev": true,
+ "requires": {
+ "@types/prop-types": "*",
+ "csstype": "^2.2.0"
+ }
+ },
+ "@types/react-dom": {
+ "version": "16.9.0",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.0.tgz",
+ "integrity": "sha512-OL2lk7LYGjxn4b0efW3Pvf2KBVP0y1v3wip1Bp7nA79NkOpElH98q3WdCEdDj93b2b0zaeBG9DvriuKjIK5xDA==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/react-virtualized-auto-sizer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.0.tgz",
+ "integrity": "sha512-NMErdIdSnm2j/7IqMteRiRvRulpjoELnXWUwdbucYCz84xG9PHcoOrr7QfXwB/ku7wd6egiKFrzt/+QK4Imeeg==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/source-list-map": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
+ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
+ "dev": true
+ },
+ "@types/stack-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
+ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
+ "dev": true
+ },
+ "@types/tapable": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz",
+ "integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==",
+ "dev": true
+ },
+ "@types/uglify-js": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz",
+ "integrity": "sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.6.1"
+ }
+ },
+ "@types/webpack": {
+ "version": "4.39.1",
+ "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.39.1.tgz",
+ "integrity": "sha512-rgO9ihNu/l72Sjx3shqwc9r6gi+tOMsqxhMEZhOEVIZt82GFOeUyEdpTk1BO2HqEHLS/XJW8ldUTIIfIMMyYFQ==",
+ "dev": true,
+ "requires": {
+ "@types/anymatch": "*",
+ "@types/node": "*",
+ "@types/tapable": "*",
+ "@types/uglify-js": "*",
+ "@types/webpack-sources": "*",
+ "source-map": "^0.6.0"
+ }
+ },
+ "@types/webpack-sources": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz",
+ "integrity": "sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/source-list-map": "*",
+ "source-map": "^0.6.1"
+ }
+ },
+ "@types/yargs": {
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz",
+ "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==",
+ "dev": true,
+ "requires": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "@types/yargs-parser": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.0.0.tgz",
+ "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==",
+ "dev": true
+ },
+ "@webassemblyjs/ast": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
+ "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz",
+ "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-api-error": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz",
+ "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-buffer": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz",
+ "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-code-frame": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz",
+ "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/wast-printer": "1.8.5"
+ }
+ },
+ "@webassemblyjs/helper-fsm": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz",
+ "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-module-context": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz",
+ "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "mamacro": "^0.0.3"
+ }
+ },
+ "@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz",
+ "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-wasm-section": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz",
+ "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz",
+ "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==",
+ "dev": true,
+ "requires": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "@webassemblyjs/leb128": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz",
+ "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==",
+ "dev": true,
+ "requires": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/utf8": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz",
+ "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==",
+ "dev": true
+ },
+ "@webassemblyjs/wasm-edit": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz",
+ "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz",
+ "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz",
+ "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz",
+ "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz",
+ "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==",
+ "dev": true,
+ "requires": {
+ "@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": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz",
+ "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/wast-parser": "1.8.5",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "dev": true
+ },
+ "@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "dev": true
+ },
+ "@zkochan/cmd-shim": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz",
+ "integrity": "sha512-o8l0+x7C7sMZU3v9GuJIAU10qQLtwR1dtRQIOmlNMtyaqhmpXOzx1HWiYoWfmmf9HHZoAkXpc9TM9PQYF9d4Jg==",
+ "dev": true,
+ "requires": {
+ "is-windows": "^1.0.0",
+ "mkdirp-promise": "^5.0.1",
+ "mz": "^2.5.0"
+ }
+ },
+ "JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "abab": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.1.tgz",
+ "integrity": "sha512-1zSbbCuoIjafKZ3mblY5ikvAb0ODUbqBnFuUb7f6uLeQhhGJ0vEV4ntmtxKLT2WgXCO94E07BjunsIw1jOMPZw==",
+ "dev": true
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+ "dev": true
+ },
+ "acorn-globals": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.3.tgz",
+ "integrity": "sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.1",
+ "acorn-walk": "^6.0.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
+ "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+ "dev": true
+ }
+ }
+ },
+ "acorn-walk": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
+ "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
+ "dev": true
+ },
+ "agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
+ "agentkeepalive": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
+ "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
+ "dev": true,
+ "requires": {
+ "humanize-ms": "^1.2.1"
+ }
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "dev": true,
+ "requires": {
+ "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-errors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
+ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
+ "dev": true
+ },
+ "ajv-keywords": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
+ "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
+ "dev": true
+ },
+ "ansi-colors": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
+ "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true
+ },
+ "ansi-html": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
+ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dev": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "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
+ },
+ "array-differ": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-2.1.0.tgz",
+ "integrity": "sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w==",
+ "dev": true
+ },
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
+ "dev": true
+ },
+ "array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true
+ },
+ "array-flatten": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
+ "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
+ "dev": true
+ },
+ "array-ify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
+ "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=",
+ "dev": true
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dev": true,
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "dev": true
+ },
+ "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
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
+ "dev": true
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.1",
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ },
+ "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
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "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
+ },
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": 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
+ },
+ "atob-lite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
+ "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=",
+ "dev": true
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
+ "dev": true
+ },
+ "babel-jest": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz",
+ "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==",
+ "dev": true,
+ "requires": {
+ "@jest/transform": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "@types/babel__core": "^7.1.0",
+ "babel-plugin-istanbul": "^5.1.0",
+ "babel-preset-jest": "^24.9.0",
+ "chalk": "^2.4.2",
+ "slash": "^2.0.0"
+ }
+ },
+ "babel-plugin-istanbul": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz",
+ "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "find-up": "^3.0.0",
+ "istanbul-lib-instrument": "^3.3.0",
+ "test-exclude": "^5.2.3"
+ }
+ },
+ "babel-plugin-jest-hoist": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz",
+ "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==",
+ "dev": true,
+ "requires": {
+ "@types/babel__traverse": "^7.0.6"
+ }
+ },
+ "babel-preset-jest": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz",
+ "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==",
+ "dev": true,
+ "requires": {
+ "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
+ "babel-plugin-jest-hoist": "^24.9.0"
+ }
+ },
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+ "dev": true
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "before-after-hook": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz",
+ "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==",
+ "dev": true
+ },
+ "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
+ },
+ "bluebird": {
+ "version": "3.5.5",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
+ "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==",
+ "dev": true
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": true
+ }
+ }
+ },
+ "bonjour": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
+ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+ "dev": true,
+ "requires": {
+ "array-flatten": "^2.1.0",
+ "deep-equal": "^1.0.1",
+ "dns-equal": "^1.0.0",
+ "dns-txt": "^2.0.2",
+ "multicast-dns": "^6.0.1",
+ "multicast-dns-service-types": "^1.1.0"
+ }
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+ "dev": 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,
+ "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,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browser-process-hrtime": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
+ "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==",
+ "dev": true
+ },
+ "browser-resolve": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
+ "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
+ "dev": true,
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ }
+ }
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "dev": true,
+ "requires": {
+ "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": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "bser": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz",
+ "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==",
+ "dev": true,
+ "requires": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "btoa-lite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
+ "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=",
+ "dev": true
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "buffer-indexof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
+ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
+ "dev": true
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "builtins": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
+ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
+ "dev": true
+ },
+ "byline": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
+ "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=",
+ "dev": true
+ },
+ "byte-size": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz",
+ "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+ "dev": true
+ },
+ "cacache": {
+ "version": "12.0.3",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
+ "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "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,
+ "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"
+ }
+ },
+ "call-me-maybe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
+ "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
+ "dev": true
+ },
+ "caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "dev": true,
+ "requires": {
+ "callsites": "^2.0.0"
+ },
+ "dependencies": {
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true
+ }
+ }
+ },
+ "caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "dev": true,
+ "requires": {
+ "caller-callsite": "^2.0.0"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
+ "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^4.1.0",
+ "map-obj": "^2.0.0",
+ "quick-lru": "^1.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ }
+ }
+ },
+ "capture-exit": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
+ "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==",
+ "dev": true,
+ "requires": {
+ "rsvp": "^4.8.4"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "chownr": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
+ "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==",
+ "dev": true
+ },
+ "chrome-trace-event": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
+ "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.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,
+ "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,
+ "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"
+ }
+ },
+ "clean-webpack-plugin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
+ "integrity": "sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A==",
+ "dev": true,
+ "requires": {
+ "@types/webpack": "^4.4.31",
+ "del": "^4.1.1"
+ }
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+ "dev": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "columnify": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz",
+ "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=",
+ "dev": true,
+ "requires": {
+ "strip-ansi": "^3.0.0",
+ "wcwidth": "^1.0.0"
+ }
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "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
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "compare-func": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz",
+ "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=",
+ "dev": true,
+ "requires": {
+ "array-ify": "^1.0.0",
+ "dot-prop": "^3.0.0"
+ },
+ "dependencies": {
+ "dot-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz",
+ "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=",
+ "dev": true,
+ "requires": {
+ "is-obj": "^1.0.0"
+ }
+ }
+ }
+ },
+ "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
+ },
+ "compressible": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
+ "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
+ "dev": true,
+ "requires": {
+ "mime-db": ">= 1.40.0 < 2"
+ }
+ },
+ "compression": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+ "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.5",
+ "bytes": "3.0.0",
+ "compressible": "~2.0.16",
+ "debug": "2.6.9",
+ "on-headers": "~1.0.2",
+ "safe-buffer": "5.1.2",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": 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==",
+ "dev": true
+ }
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "config-chain": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
+ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "connect-history-api-fallback": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
+ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
+ "dev": true
+ },
+ "console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "dev": true,
+ "requires": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ },
+ "dependencies": {
+ "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==",
+ "dev": true
+ }
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "dev": true
+ },
+ "conventional-changelog-angular": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz",
+ "integrity": "sha512-YD1xzH7r9yXQte/HF9JBuEDfvjxxwDGGwZU1+ndanbY0oFgA+Po1T9JDSpPLdP0pZT6MhCAsdvFKC4TJ4MTJTA==",
+ "dev": true,
+ "requires": {
+ "compare-func": "^1.3.1",
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-core": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz",
+ "integrity": "sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ==",
+ "dev": true,
+ "requires": {
+ "conventional-changelog-writer": "^4.0.6",
+ "conventional-commits-parser": "^3.0.3",
+ "dateformat": "^3.0.0",
+ "get-pkg-repo": "^1.0.0",
+ "git-raw-commits": "2.0.0",
+ "git-remote-origin-url": "^2.0.0",
+ "git-semver-tags": "^2.0.3",
+ "lodash": "^4.2.1",
+ "normalize-package-data": "^2.3.5",
+ "q": "^1.5.1",
+ "read-pkg": "^3.0.0",
+ "read-pkg-up": "^3.0.0",
+ "through2": "^3.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ },
+ "read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ }
+ },
+ "through2": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+ "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "2 || 3"
+ }
+ }
+ }
+ },
+ "conventional-changelog-preset-loader": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.2.0.tgz",
+ "integrity": "sha512-zXB+5vF7D5Y3Cb/rJfSyCCvFphCVmF8mFqOdncX3BmjZwAtGAPfYrBcT225udilCKvBbHgyzgxqz2GWDB5xShQ==",
+ "dev": true
+ },
+ "conventional-changelog-writer": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.7.tgz",
+ "integrity": "sha512-p/wzs9eYaxhFbrmX/mCJNwJuvvHR+j4Fd0SQa2xyAhYed6KBiZ780LvoqUUvsayP4R1DtC27czalGUhKV2oabw==",
+ "dev": true,
+ "requires": {
+ "compare-func": "^1.3.1",
+ "conventional-commits-filter": "^2.0.2",
+ "dateformat": "^3.0.0",
+ "handlebars": "^4.1.2",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.2.1",
+ "meow": "^4.0.0",
+ "semver": "^6.0.0",
+ "split": "^1.0.0",
+ "through2": "^3.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "through2": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+ "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "2 || 3"
+ }
+ }
+ }
+ },
+ "conventional-commits-filter": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz",
+ "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==",
+ "dev": true,
+ "requires": {
+ "lodash.ismatch": "^4.4.0",
+ "modify-values": "^1.0.0"
+ }
+ },
+ "conventional-commits-parser": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.3.tgz",
+ "integrity": "sha512-KaA/2EeUkO4bKjinNfGUyqPTX/6w9JGshuQRik4r/wJz7rUw3+D3fDG6sZSEqJvKILzKXFQuFkpPLclcsAuZcg==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.4",
+ "is-text-path": "^2.0.0",
+ "lodash": "^4.2.1",
+ "meow": "^4.0.0",
+ "split2": "^2.0.0",
+ "through2": "^3.0.0",
+ "trim-off-newlines": "^1.0.0"
+ },
+ "dependencies": {
+ "through2": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+ "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "2 || 3"
+ }
+ }
+ }
+ },
+ "conventional-recommended-bump": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-5.0.1.tgz",
+ "integrity": "sha512-RVdt0elRcCxL90IrNP0fYCpq1uGt2MALko0eyeQ+zQuDVWtMGAy9ng6yYn3kax42lCj9+XBxQ8ZN6S9bdKxDhQ==",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^2.0.0",
+ "conventional-changelog-preset-loader": "^2.1.1",
+ "conventional-commits-filter": "^2.0.2",
+ "conventional-commits-parser": "^3.0.3",
+ "git-raw-commits": "2.0.0",
+ "git-semver-tags": "^2.0.3",
+ "meow": "^4.0.0",
+ "q": "^1.5.1"
+ },
+ "dependencies": {
+ "concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ }
+ }
+ },
+ "convert-source-map": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ },
+ "dependencies": {
+ "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==",
+ "dev": true
+ }
+ }
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+ "dev": true
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "dev": true
+ },
+ "copy-concurrently": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
+ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ }
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "css-loader": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.2.0.tgz",
+ "integrity": "sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "cssesc": "^3.0.0",
+ "icss-utils": "^4.1.1",
+ "loader-utils": "^1.2.3",
+ "normalize-path": "^3.0.0",
+ "postcss": "^7.0.17",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^3.0.2",
+ "postcss-modules-scope": "^2.1.0",
+ "postcss-modules-values": "^3.0.0",
+ "postcss-value-parser": "^4.0.0",
+ "schema-utils": "^2.0.0"
+ }
+ },
+ "css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ }
+ },
+ "css-what": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
+ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
+ "dev": true
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "cssom": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+ "dev": true
+ },
+ "cssstyle": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
+ "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
+ "dev": true,
+ "requires": {
+ "cssom": "0.3.x"
+ }
+ },
+ "csstype": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.6.tgz",
+ "integrity": "sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==",
+ "dev": true
+ },
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "requires": {
+ "array-find-index": "^1.0.1"
+ }
+ },
+ "cyclist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
+ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
+ "dev": true
+ },
+ "d3-array": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+ "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+ },
+ "d3-collection": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
+ "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
+ },
+ "d3-color": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.3.0.tgz",
+ "integrity": "sha512-NHODMBlj59xPAwl2BDiO2Mog6V+PrGRtBfWKqKRrs9MCqlSkIEb0Z/SfY7jW29ReHTDC/j+vwXhnZcXI3+3fbg=="
+ },
+ "d3-dispatch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz",
+ "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g=="
+ },
+ "d3-force": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz",
+ "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==",
+ "requires": {
+ "d3-collection": "1",
+ "d3-dispatch": "1",
+ "d3-quadtree": "1",
+ "d3-timer": "1"
+ }
+ },
+ "d3-format": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.2.tgz",
+ "integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ=="
+ },
+ "d3-interpolate": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz",
+ "integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==",
+ "requires": {
+ "d3-color": "1"
+ }
+ },
+ "d3-path": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.8.tgz",
+ "integrity": "sha512-J6EfUNwcMQ+aM5YPOB8ZbgAZu6wc82f/0WFxrxwV6Ll8wBwLaHLKCqQ5Imub02JriCVVdPjgI+6P3a4EWJCxAg=="
+ },
+ "d3-quadtree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.6.tgz",
+ "integrity": "sha512-NUgeo9G+ENQCQ1LsRr2qJg3MQ4DJvxcDNCiohdJGHt5gRhBW6orIB5m5FJ9kK3HNL8g9F4ERVoBzcEwQBfXWVA=="
+ },
+ "d3-scale": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz",
+ "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==",
+ "requires": {
+ "d3-array": "^1.2.0",
+ "d3-collection": "1",
+ "d3-color": "1",
+ "d3-format": "1",
+ "d3-interpolate": "1",
+ "d3-time": "1",
+ "d3-time-format": "2"
+ }
+ },
+ "d3-selection": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz",
+ "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg=="
+ },
+ "d3-shape": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz",
+ "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==",
+ "requires": {
+ "d3-path": "1"
+ }
+ },
+ "d3-time": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
+ "integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
+ },
+ "d3-time-format": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz",
+ "integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==",
+ "requires": {
+ "d3-time": "1"
+ }
+ },
+ "d3-timer": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz",
+ "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg=="
+ },
+ "dargs": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz",
+ "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "data-urls": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
+ "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+ "dev": true,
+ "requires": {
+ "abab": "^2.0.0",
+ "whatwg-mimetype": "^2.2.0",
+ "whatwg-url": "^7.0.0"
+ },
+ "dependencies": {
+ "whatwg-url": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ }
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "debuglog": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
+ "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "dependencies": {
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ }
+ }
+ },
+ "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
+ },
+ "dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
+ "dev": true
+ },
+ "deep-equal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.0.tgz",
+ "integrity": "sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==",
+ "dev": true,
+ "requires": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ }
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "default-gateway": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
+ "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
+ "dev": true,
+ "requires": {
+ "execa": "^1.0.0",
+ "ip-regex": "^2.1.0"
+ }
+ },
+ "defaults": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "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,
+ "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,
+ "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,
+ "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,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "del": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
+ "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "globby": "^6.1.0",
+ "is-path-cwd": "^2.0.0",
+ "is-path-in-cwd": "^2.0.0",
+ "p-map": "^2.0.0",
+ "pify": "^4.0.1",
+ "rimraf": "^2.6.3"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true
+ },
+ "deprecation": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
+ "dev": true
+ },
+ "des.js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+ "dev": true
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+ "dev": true
+ },
+ "detect-indent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz",
+ "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=",
+ "dev": true
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+ "dev": true
+ },
+ "detect-node": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+ "dev": true
+ },
+ "dezalgo": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
+ "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
+ "dev": true,
+ "requires": {
+ "asap": "^2.0.0",
+ "wrappy": "1"
+ }
+ },
+ "diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "dev": true
+ },
+ "diff-sequences": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz",
+ "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==",
+ "dev": true
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "dir-glob": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+ "dev": true,
+ "requires": {
+ "path-type": "^3.0.0"
+ }
+ },
+ "dns-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
+ "dev": true
+ },
+ "dns-packet": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
+ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+ "dev": true,
+ "requires": {
+ "ip": "^1.1.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "dns-txt": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
+ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+ "dev": true,
+ "requires": {
+ "buffer-indexof": "^1.0.0"
+ }
+ },
+ "dom-converter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
+ "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==",
+ "dev": true,
+ "requires": {
+ "utila": "~0.4"
+ }
+ },
+ "dom-serializer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
+ "integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
+ "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==",
+ "dev": true
+ }
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "domexception": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
+ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+ "dev": true,
+ "requires": {
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "dot-prop": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
+ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
+ "dev": true,
+ "requires": {
+ "is-obj": "^1.0.0"
+ }
+ },
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+ "dev": true
+ },
+ "duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "elliptic": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz",
+ "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
+ "dev": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "~0.4.13"
+ }
+ },
+ "end-of-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz",
+ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.4.0",
+ "tapable": "^1.0.0"
+ }
+ },
+ "entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
+ "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==",
+ "dev": true
+ },
+ "env-paths": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
+ "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
+ "dev": true
+ },
+ "err-code": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
+ "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
+ "dev": true
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "dev": true,
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.1.tgz",
+ "integrity": "sha512-cp/Tb1oA/rh2X7vqeSOvM+TSo3UkJLX70eNihgVEvnzwAgikjkTFr/QVgRCaxjm0knCNQzNoxxxcw2zO2LJdZA==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.0",
+ "is-callable": "^1.1.4",
+ "is-regex": "^1.0.4",
+ "object-inspect": "^1.6.0",
+ "object-keys": "^1.1.1",
+ "string.prototype.trimleft": "^2.0.0",
+ "string.prototype.trimright": "^2.0.0"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+ "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+ "dev": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "dev": true
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+ "dev": true,
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "escodegen": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz",
+ "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==",
+ "dev": true,
+ "requires": {
+ "esprima": "^3.1.3",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ }
+ },
+ "eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+ "dev": true
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "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
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "dev": true
+ },
+ "eventemitter3": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
+ "dev": true
+ },
+ "events": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
+ "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==",
+ "dev": true
+ },
+ "eventsource": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
+ "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
+ "dev": true,
+ "requires": {
+ "original": "^1.0.0"
+ }
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "exec-sh": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz",
+ "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==",
+ "dev": true
+ },
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "requires": {
+ "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"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "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,
+ "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": {
+ "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"
+ }
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "expect": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz",
+ "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "ansi-styles": "^3.2.0",
+ "jest-get-type": "^24.9.0",
+ "jest-matcher-utils": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-regex-util": "^24.9.0"
+ }
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": 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==",
+ "dev": true
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": 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,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": 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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
+ "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==",
+ "dev": true,
+ "requires": {
+ "@mrmlnc/readdir-enhanced": "^2.2.1",
+ "@nodelib/fs.stat": "^1.1.2",
+ "glob-parent": "^3.1.0",
+ "is-glob": "^4.0.0",
+ "merge2": "^1.2.3",
+ "micromatch": "^3.1.10"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "faye-websocket": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "dev": true,
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "fb-watchman": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
+ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
+ "dev": true,
+ "requires": {
+ "bser": "^2.0.0"
+ }
+ },
+ "figgy-pudding": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
+ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
+ "dev": true
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-loader": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz",
+ "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.2.3",
+ "schema-utils": "^2.0.0"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": 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,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+ "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "follow-redirects": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.1.tgz",
+ "integrity": "sha512-micCIbldHioIegeKs41DoH0KS3AXfFzgS30qVkM6z/XOE/GJgvmsoc839NUqa1B9udYe9dQxgv7KFwng6+p/dw==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "dev": true
+ },
+ "from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs-minipass": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
+ "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
+ "dev": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs-write-stream-atomic": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
+ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "iferr": "^0.1.5",
+ "imurmurhash": "^0.1.4",
+ "readable-stream": "1 || 2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "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
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": 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"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "genfun": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
+ "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-pkg-repo": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz",
+ "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "meow": "^3.3.0",
+ "normalize-package-data": "^2.3.0",
+ "parse-github-repo-url": "^1.3.0",
+ "through2": "^2.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^2.0.0",
+ "map-obj": "^1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "indent-string": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "dev": true,
+ "requires": {
+ "repeating": "^2.0.0"
+ }
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ },
+ "meow": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "dev": true,
+ "requires": {
+ "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"
+ }
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ }
+ },
+ "redent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "dev": true,
+ "requires": {
+ "indent-string": "^2.1.0",
+ "strip-indent": "^1.0.1"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "strip-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^4.0.1"
+ }
+ },
+ "trim-newlines": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+ "dev": true
+ }
+ }
+ },
+ "get-port": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz",
+ "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==",
+ "dev": true
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "git-raw-commits": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz",
+ "integrity": "sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg==",
+ "dev": true,
+ "requires": {
+ "dargs": "^4.0.1",
+ "lodash.template": "^4.0.2",
+ "meow": "^4.0.0",
+ "split2": "^2.0.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "git-remote-origin-url": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz",
+ "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=",
+ "dev": true,
+ "requires": {
+ "gitconfiglocal": "^1.0.0",
+ "pify": "^2.3.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ }
+ }
+ },
+ "git-semver-tags": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.3.tgz",
+ "integrity": "sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA==",
+ "dev": true,
+ "requires": {
+ "meow": "^4.0.0",
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "git-up": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.1.tgz",
+ "integrity": "sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw==",
+ "dev": true,
+ "requires": {
+ "is-ssh": "^1.3.0",
+ "parse-url": "^5.0.0"
+ }
+ },
+ "git-url-parse": {
+ "version": "11.1.2",
+ "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz",
+ "integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==",
+ "dev": true,
+ "requires": {
+ "git-up": "^4.0.0"
+ }
+ },
+ "gitconfiglocal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz",
+ "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.2"
+ }
+ },
+ "glob": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+ "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+ "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-parent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
+ "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "glob-to-regexp": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
+ "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
+ "dev": true
+ },
+ "global-modules": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+ "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^3.0.0"
+ },
+ "dependencies": {
+ "global-prefix": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+ "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.5",
+ "kind-of": "^6.0.2",
+ "which": "^1.3.1"
+ }
+ }
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "dev": true,
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
+ "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
+ "dev": true
+ },
+ "growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+ "dev": true
+ },
+ "handle-thing": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
+ "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==",
+ "dev": true
+ },
+ "handlebars": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz",
+ "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==",
+ "dev": true,
+ "requires": {
+ "neo-async": "^2.6.0",
+ "optimist": "^0.6.1",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+ "dev": true
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": 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,
+ "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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz",
+ "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==",
+ "dev": true
+ },
+ "hpack.js": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "obuf": "^1.0.0",
+ "readable-stream": "^2.0.1",
+ "wbuf": "^1.1.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "dev": true,
+ "requires": {
+ "whatwg-encoding": "^1.0.1"
+ }
+ },
+ "html-entities": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
+ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "html-webpack-plugin": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
+ "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=",
+ "dev": true,
+ "requires": {
+ "html-minifier": "^3.2.3",
+ "loader-utils": "^0.2.16",
+ "lodash": "^4.17.3",
+ "pretty-error": "^2.0.2",
+ "tapable": "^1.0.0",
+ "toposort": "^1.0.0",
+ "util.promisify": "1.0.0"
+ },
+ "dependencies": {
+ "big.js": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
+ "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
+ "dev": true
+ },
+ "json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "dev": true
+ },
+ "loader-utils": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
+ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
+ "dev": true,
+ "requires": {
+ "big.js": "^3.1.3",
+ "emojis-list": "^2.0.0",
+ "json5": "^0.5.0",
+ "object-assign": "^4.0.1"
+ }
+ }
+ }
+ },
+ "html-webpack-template": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/html-webpack-template/-/html-webpack-template-6.2.0.tgz",
+ "integrity": "sha512-wyzIjbe9yXGyQ6yAeFjWmku7YOlW85w1dxqLnAQ564uRNNoBhpZVTQl7ouROoyQrfZUSoPUJiw7oWn31NDiuQQ==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ }
+ }
+ },
+ "http-cache-semantics": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
+ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+ "dev": true
+ },
+ "http-deceiver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "dev": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ }
+ }
+ },
+ "http-parser-js": {
+ "version": "0.4.10",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
+ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
+ "dev": true
+ },
+ "http-proxy": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
+ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^3.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
+ "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "4",
+ "debug": "3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "http-proxy-middleware": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
+ "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
+ "dev": true,
+ "requires": {
+ "http-proxy": "^1.17.0",
+ "is-glob": "^4.0.0",
+ "lodash": "^4.17.11",
+ "micromatch": "^3.1.10"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "https-proxy-agent": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
+ "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+ "dev": true,
+ "requires": {
+ "ms": "^2.0.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "icss-utils": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
+ "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.14"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
+ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
+ "dev": true
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+ "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+ "dev": true,
+ "requires": {
+ "import-from": "^2.1.0"
+ }
+ },
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "dev": true,
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+ "dev": true,
+ "requires": {
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "import-local": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
+ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
+ "dev": true,
+ "requires": {
+ "pkg-dir": "^3.0.0",
+ "resolve-cwd": "^2.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+ "dev": true
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+ "dev": true
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "init-package-json": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz",
+ "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.1",
+ "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0",
+ "promzard": "^0.3.0",
+ "read": "~1.0.1",
+ "read-package-json": "1 || 2",
+ "semver": "2.x || 3.x || 4 || 5",
+ "validate-npm-package-license": "^3.0.1",
+ "validate-npm-package-name": "^3.0.0"
+ }
+ },
+ "inquirer": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+ "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ }
+ }
+ }
+ }
+ },
+ "internal-ip": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
+ "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
+ "dev": true,
+ "requires": {
+ "default-gateway": "^4.2.0",
+ "ipaddr.js": "^1.9.0"
+ }
+ },
+ "interpret": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "invert-kv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
+ "dev": true
+ },
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
+ "dev": true
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
+ "dev": true
+ },
+ "ipaddr.js": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
+ "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==",
+ "dev": true
+ },
+ "is-absolute-url": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.1.tgz",
+ "integrity": "sha512-c2QjUwuMxLsld90sj3xYzpFYWJtuxkIn1f5ua9RTEYJt/vV2IsM+Py00/6qjV7qExgifUvt7qfyBGBBKm+2iBg==",
+ "dev": true
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arguments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
+ "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
+ "dev": true
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "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,
+ "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
+ },
+ "is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+ "dev": true
+ },
+ "is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "dev": true,
+ "requires": {
+ "ci-info": "^2.0.0"
+ }
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+ "dev": true
+ },
+ "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,
+ "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
+ }
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true
+ },
+ "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
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-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-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "is-generator-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": 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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
+ "dev": true
+ },
+ "is-path-cwd": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
+ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
+ "dev": true
+ },
+ "is-path-in-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
+ "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
+ "dev": true,
+ "requires": {
+ "is-path-inside": "^2.1.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
+ "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
+ "dev": true,
+ "requires": {
+ "path-is-inside": "^1.0.2"
+ }
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-ssh": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz",
+ "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==",
+ "dev": true,
+ "requires": {
+ "protocols": "^1.1.0"
+ }
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true
+ },
+ "is-symbol": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
+ "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.0"
+ }
+ },
+ "is-text-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz",
+ "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==",
+ "dev": true,
+ "requires": {
+ "text-extensions": "^2.0.0"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "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
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "istanbul-lib-coverage": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+ "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
+ "dev": true
+ },
+ "istanbul-lib-instrument": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
+ "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
+ "dev": true,
+ "requires": {
+ "@babel/generator": "^7.4.0",
+ "@babel/parser": "^7.4.3",
+ "@babel/template": "^7.4.0",
+ "@babel/traverse": "^7.4.3",
+ "@babel/types": "^7.4.0",
+ "istanbul-lib-coverage": "^2.0.5",
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz",
+ "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "^2.0.5",
+ "make-dir": "^2.1.0",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz",
+ "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^2.0.5",
+ "make-dir": "^2.1.0",
+ "rimraf": "^2.6.3",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz",
+ "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==",
+ "dev": true,
+ "requires": {
+ "handlebars": "^4.1.2"
+ }
+ },
+ "jest": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz",
+ "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==",
+ "dev": true,
+ "requires": {
+ "import-local": "^2.0.0",
+ "jest-cli": "^24.9.0"
+ },
+ "dependencies": {
+ "jest-cli": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz",
+ "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==",
+ "dev": true,
+ "requires": {
+ "@jest/core": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "import-local": "^2.0.0",
+ "is-ci": "^2.0.0",
+ "jest-config": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-validate": "^24.9.0",
+ "prompts": "^2.0.1",
+ "realpath-native": "^1.1.0",
+ "yargs": "^13.3.0"
+ }
+ }
+ }
+ },
+ "jest-changed-files": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz",
+ "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "execa": "^1.0.0",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-config": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz",
+ "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.1.0",
+ "@jest/test-sequencer": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "babel-jest": "^24.9.0",
+ "chalk": "^2.0.1",
+ "glob": "^7.1.1",
+ "jest-environment-jsdom": "^24.9.0",
+ "jest-environment-node": "^24.9.0",
+ "jest-get-type": "^24.9.0",
+ "jest-jasmine2": "^24.9.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-validate": "^24.9.0",
+ "micromatch": "^3.1.10",
+ "pretty-format": "^24.9.0",
+ "realpath-native": "^1.1.0"
+ }
+ },
+ "jest-diff": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz",
+ "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1",
+ "diff-sequences": "^24.9.0",
+ "jest-get-type": "^24.9.0",
+ "pretty-format": "^24.9.0"
+ }
+ },
+ "jest-docblock": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz",
+ "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==",
+ "dev": true,
+ "requires": {
+ "detect-newline": "^2.1.0"
+ }
+ },
+ "jest-each": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz",
+ "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.0.1",
+ "jest-get-type": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "pretty-format": "^24.9.0"
+ }
+ },
+ "jest-environment-jsdom": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz",
+ "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==",
+ "dev": true,
+ "requires": {
+ "@jest/environment": "^24.9.0",
+ "@jest/fake-timers": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "jest-mock": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jsdom": "^11.5.1"
+ }
+ },
+ "jest-environment-node": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz",
+ "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==",
+ "dev": true,
+ "requires": {
+ "@jest/environment": "^24.9.0",
+ "@jest/fake-timers": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "jest-mock": "^24.9.0",
+ "jest-util": "^24.9.0"
+ }
+ },
+ "jest-get-type": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz",
+ "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==",
+ "dev": true
+ },
+ "jest-haste-map": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz",
+ "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "anymatch": "^2.0.0",
+ "fb-watchman": "^2.0.0",
+ "fsevents": "^1.2.7",
+ "graceful-fs": "^4.1.15",
+ "invariant": "^2.2.4",
+ "jest-serializer": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-worker": "^24.9.0",
+ "micromatch": "^3.1.10",
+ "sane": "^4.0.3",
+ "walker": "^1.0.7"
+ }
+ },
+ "jest-jasmine2": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz",
+ "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==",
+ "dev": true,
+ "requires": {
+ "@babel/traverse": "^7.1.0",
+ "@jest/environment": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.0.1",
+ "co": "^4.6.0",
+ "expect": "^24.9.0",
+ "is-generator-fn": "^2.0.0",
+ "jest-each": "^24.9.0",
+ "jest-matcher-utils": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-runtime": "^24.9.0",
+ "jest-snapshot": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "pretty-format": "^24.9.0",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-leak-detector": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz",
+ "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==",
+ "dev": true,
+ "requires": {
+ "jest-get-type": "^24.9.0",
+ "pretty-format": "^24.9.0"
+ }
+ },
+ "jest-matcher-utils": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz",
+ "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1",
+ "jest-diff": "^24.9.0",
+ "jest-get-type": "^24.9.0",
+ "pretty-format": "^24.9.0"
+ }
+ },
+ "jest-message-util": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
+ "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "@types/stack-utils": "^1.0.1",
+ "chalk": "^2.0.1",
+ "micromatch": "^3.1.10",
+ "slash": "^2.0.0",
+ "stack-utils": "^1.0.1"
+ }
+ },
+ "jest-mock": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz",
+ "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0"
+ }
+ },
+ "jest-pnp-resolver": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz",
+ "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==",
+ "dev": true
+ },
+ "jest-regex-util": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz",
+ "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==",
+ "dev": true
+ },
+ "jest-resolve": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz",
+ "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "browser-resolve": "^1.11.3",
+ "chalk": "^2.0.1",
+ "jest-pnp-resolver": "^1.2.1",
+ "realpath-native": "^1.1.0"
+ }
+ },
+ "jest-resolve-dependencies": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz",
+ "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-snapshot": "^24.9.0"
+ }
+ },
+ "jest-runner": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz",
+ "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==",
+ "dev": true,
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/environment": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.4.2",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.1.15",
+ "jest-config": "^24.9.0",
+ "jest-docblock": "^24.3.0",
+ "jest-haste-map": "^24.9.0",
+ "jest-jasmine2": "^24.9.0",
+ "jest-leak-detector": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-resolve": "^24.9.0",
+ "jest-runtime": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-worker": "^24.6.0",
+ "source-map-support": "^0.5.6",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-runtime": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz",
+ "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==",
+ "dev": true,
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/environment": "^24.9.0",
+ "@jest/source-map": "^24.3.0",
+ "@jest/transform": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "@types/yargs": "^13.0.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.1.15",
+ "jest-config": "^24.9.0",
+ "jest-haste-map": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-mock": "^24.9.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve": "^24.9.0",
+ "jest-snapshot": "^24.9.0",
+ "jest-util": "^24.9.0",
+ "jest-validate": "^24.9.0",
+ "realpath-native": "^1.1.0",
+ "slash": "^2.0.0",
+ "strip-bom": "^3.0.0",
+ "yargs": "^13.3.0"
+ }
+ },
+ "jest-serializer": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz",
+ "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==",
+ "dev": true
+ },
+ "jest-snapshot": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz",
+ "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0",
+ "@jest/types": "^24.9.0",
+ "chalk": "^2.0.1",
+ "expect": "^24.9.0",
+ "jest-diff": "^24.9.0",
+ "jest-get-type": "^24.9.0",
+ "jest-matcher-utils": "^24.9.0",
+ "jest-message-util": "^24.9.0",
+ "jest-resolve": "^24.9.0",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^24.9.0",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "jest-util": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz",
+ "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==",
+ "dev": true,
+ "requires": {
+ "@jest/console": "^24.9.0",
+ "@jest/fake-timers": "^24.9.0",
+ "@jest/source-map": "^24.9.0",
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "callsites": "^3.0.0",
+ "chalk": "^2.0.1",
+ "graceful-fs": "^4.1.15",
+ "is-ci": "^2.0.0",
+ "mkdirp": "^0.5.1",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "jest-validate": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz",
+ "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "camelcase": "^5.3.1",
+ "chalk": "^2.0.1",
+ "jest-get-type": "^24.9.0",
+ "leven": "^3.1.0",
+ "pretty-format": "^24.9.0"
+ }
+ },
+ "jest-watcher": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz",
+ "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==",
+ "dev": true,
+ "requires": {
+ "@jest/test-result": "^24.9.0",
+ "@jest/types": "^24.9.0",
+ "@types/yargs": "^13.0.0",
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.1",
+ "jest-util": "^24.9.0",
+ "string-length": "^2.0.0"
+ }
+ },
+ "jest-worker": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
+ "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
+ "dev": true,
+ "requires": {
+ "merge-stream": "^2.0.0",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ }
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "jsdom": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
+ "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "dev": true,
+ "requires": {
+ "abab": "^2.0.0",
+ "acorn": "^5.5.3",
+ "acorn-globals": "^4.1.0",
+ "array-equal": "^1.0.0",
+ "cssom": ">= 0.3.2 < 0.4.0",
+ "cssstyle": "^1.0.0",
+ "data-urls": "^1.0.0",
+ "domexception": "^1.0.1",
+ "escodegen": "^1.9.1",
+ "html-encoding-sniffer": "^1.0.2",
+ "left-pad": "^1.3.0",
+ "nwsapi": "^2.0.7",
+ "parse5": "4.0.0",
+ "pn": "^1.1.0",
+ "request": "^2.87.0",
+ "request-promise-native": "^1.0.5",
+ "sax": "^1.2.4",
+ "symbol-tree": "^3.2.2",
+ "tough-cookie": "^2.3.4",
+ "w3c-hr-time": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "whatwg-encoding": "^1.0.3",
+ "whatwg-mimetype": "^2.1.0",
+ "whatwg-url": "^6.4.1",
+ "ws": "^5.2.0",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "json3": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
+ "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
+ "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"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "dev": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "killable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
+ "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==",
+ "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
+ },
+ "kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true
+ },
+ "lcid": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+ "dev": true,
+ "requires": {
+ "invert-kv": "^2.0.0"
+ }
+ },
+ "left-pad": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
+ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==",
+ "dev": true
+ },
+ "lerna": {
+ "version": "3.16.4",
+ "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.16.4.tgz",
+ "integrity": "sha512-0HfwXIkqe72lBLZcNO9NMRfylh5Ng1l8tETgYQ260ZdHRbPuaLKE3Wqnd2YYRRkWfwPyEyZO8mZweBR+slVe1A==",
+ "dev": true,
+ "requires": {
+ "@lerna/add": "3.16.2",
+ "@lerna/bootstrap": "3.16.2",
+ "@lerna/changed": "3.16.4",
+ "@lerna/clean": "3.16.0",
+ "@lerna/cli": "3.13.0",
+ "@lerna/create": "3.16.0",
+ "@lerna/diff": "3.16.0",
+ "@lerna/exec": "3.16.0",
+ "@lerna/import": "3.16.0",
+ "@lerna/init": "3.16.0",
+ "@lerna/link": "3.16.2",
+ "@lerna/list": "3.16.0",
+ "@lerna/publish": "3.16.4",
+ "@lerna/run": "3.16.0",
+ "@lerna/version": "3.16.4",
+ "import-local": "^2.0.0",
+ "npmlog": "^4.1.2"
+ }
+ },
+ "leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "loader-runner": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
+ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "dev": true
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
+ "dev": true
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+ "dev": true
+ },
+ "lodash.flattendeep": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
+ },
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "dev": true
+ },
+ "lodash.ismatch": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
+ "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
+ "dev": true
+ },
+ "lodash.set": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
+ "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
+ "dev": true
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+ "dev": true
+ },
+ "lodash.template": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+ "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+ "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "^3.0.0"
+ }
+ },
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
+ "dev": true
+ },
+ "loglevel": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz",
+ "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==",
+ "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==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "requires": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.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
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "macos-release": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz",
+ "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==",
+ "dev": true
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "make-fetch-happen": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.0.tgz",
+ "integrity": "sha512-nFr/vpL1Jc60etMVKeaLOqfGjMMb3tAHFVJWxHOFCFS04Zmd7kGlMxo0l1tzfhoQje0/UPnd0X8OeGUiXXnfPA==",
+ "dev": true,
+ "requires": {
+ "agentkeepalive": "^3.4.1",
+ "cacache": "^12.0.0",
+ "http-cache-semantics": "^3.8.1",
+ "http-proxy-agent": "^2.1.0",
+ "https-proxy-agent": "^2.2.1",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "node-fetch-npm": "^2.0.2",
+ "promise-retry": "^1.1.1",
+ "socks-proxy-agent": "^4.0.0",
+ "ssri": "^6.0.0"
+ }
+ },
+ "makeerror": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+ "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
+ "dev": true,
+ "requires": {
+ "tmpl": "1.0.x"
+ }
+ },
+ "mamacro": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
+ "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==",
+ "dev": true
+ },
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "dev": true,
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
+ "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
+ "dev": 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,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true
+ },
+ "mem": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
+ "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
+ "dev": true,
+ "requires": {
+ "map-age-cleaner": "^0.1.1",
+ "mimic-fn": "^2.0.0",
+ "p-is-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ }
+ }
+ },
+ "memory-fs": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+ "dev": true,
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "meow": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz",
+ "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==",
+ "dev": true,
+ "requires": {
+ "camelcase-keys": "^4.0.0",
+ "decamelize-keys": "^1.0.0",
+ "loud-rejection": "^1.0.0",
+ "minimist": "^1.1.3",
+ "minimist-options": "^3.0.1",
+ "normalize-package-data": "^2.3.4",
+ "read-pkg-up": "^3.0.0",
+ "redent": "^2.0.0",
+ "trim-newlines": "^2.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ },
+ "read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ }
+ }
+ }
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "dev": true
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "merge2": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.4.tgz",
+ "integrity": "sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==",
+ "dev": true
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": 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"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ },
+ "mini-css-extract-plugin": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz",
+ "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "normalize-url": "1.9.1",
+ "schema-utils": "^1.0.0",
+ "webpack-sources": "^1.1.0"
+ },
+ "dependencies": {
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ }
+ }
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "minimist-options": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz",
+ "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0"
+ }
+ },
+ "minipass": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.5.0.tgz",
+ "integrity": "sha512-9FwMVYhn6ERvMR8XFdOavRz4QK/VJV8elU1x50vYexf9lslDcWe/f4HBRxCPd185ekRSjU6CfYyJCECa/CQy7Q==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+ "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mississippi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
+ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+ "dev": true,
+ "requires": {
+ "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": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": 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,
+ "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"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ }
+ }
+ },
+ "mkdirp-promise": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz",
+ "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=",
+ "dev": true,
+ "requires": {
+ "mkdirp": "*"
+ }
+ },
+ "modify-values": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
+ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
+ "dev": true
+ },
+ "move-concurrently": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "multicast-dns": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+ "dev": true,
+ "requires": {
+ "dns-packet": "^1.3.1",
+ "thunky": "^1.0.2"
+ }
+ },
+ "multicast-dns-service-types": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
+ "dev": true
+ },
+ "multimatch": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-3.0.0.tgz",
+ "integrity": "sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA==",
+ "dev": true,
+ "requires": {
+ "array-differ": "^2.0.3",
+ "array-union": "^1.0.2",
+ "arrify": "^1.0.1",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "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,
+ "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"
+ }
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true
+ },
+ "neo-async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "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.6.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+ "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
+ "dev": true
+ },
+ "node-fetch-npm": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
+ "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
+ "dev": true,
+ "requires": {
+ "encoding": "^0.1.11",
+ "json-parse-better-errors": "^1.0.0",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node-forge": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
+ "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==",
+ "dev": true
+ },
+ "node-gyp": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.0.3.tgz",
+ "integrity": "sha512-z/JdtkFGUm0QaQUusvloyYuGDub3nUbOo5de1Fz57cM++osBTvQatBUSTlF1k/w8vFHPxxXW6zxGvkxXSpaBkQ==",
+ "dev": true,
+ "requires": {
+ "env-paths": "^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",
+ "request": "^2.87.0",
+ "rimraf": "2",
+ "semver": "~5.3.0",
+ "tar": "^4.4.8",
+ "which": "1"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "semver": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "dev": true
+ }
+ }
+ },
+ "node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
+ "dev": true
+ },
+ "node-libs-browser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": 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,
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ }
+ }
+ },
+ "node-modules-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
+ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=",
+ "dev": true
+ },
+ "node-notifier": {
+ "version": "5.4.3",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz",
+ "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==",
+ "dev": true,
+ "requires": {
+ "growly": "^1.3.0",
+ "is-wsl": "^1.1.0",
+ "semver": "^5.5.0",
+ "shellwords": "^0.1.1",
+ "which": "^1.3.0"
+ }
+ },
+ "nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
+ "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
+ "dev": true
+ },
+ "npm-bundled": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
+ "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
+ "dev": true
+ },
+ "npm-lifecycle": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.3.tgz",
+ "integrity": "sha512-M0QmmqbEHBXxDrmc6X3+eKjW9+F7Edg1ENau92WkYw1sox6wojHzEZJIRm1ItljEiaigZlKL8mXni/4ylAy1Dg==",
+ "dev": true,
+ "requires": {
+ "byline": "^5.0.0",
+ "graceful-fs": "^4.1.15",
+ "node-gyp": "^5.0.2",
+ "resolve-from": "^4.0.0",
+ "slide": "^1.1.6",
+ "uid-number": "0.0.6",
+ "umask": "^1.1.0",
+ "which": "^1.3.1"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ }
+ }
+ },
+ "npm-package-arg": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz",
+ "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.7.1",
+ "osenv": "^0.1.5",
+ "semver": "^5.6.0",
+ "validate-npm-package-name": "^3.0.0"
+ }
+ },
+ "npm-packlist": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
+ "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
+ "dev": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npm-pick-manifest": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz",
+ "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==",
+ "dev": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1",
+ "npm-package-arg": "^6.0.0",
+ "semver": "^5.4.1"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dev": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "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
+ },
+ "nwsapi": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz",
+ "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": 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,
+ "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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-inspect": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
+ "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
+ "dev": true
+ },
+ "object-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz",
+ "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=",
+ "dev": true
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
+ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.5.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,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "obuf": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
+ "dev": true
+ },
+ "octokit-pagination-methods": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz",
+ "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==",
+ "dev": true
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "opn": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+ "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+ "dev": true,
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
+ "dev": true
+ }
+ }
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "dev": true
+ }
+ }
+ },
+ "original": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
+ "dev": true,
+ "requires": {
+ "url-parse": "^1.4.3"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "os-locale": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+ "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+ "dev": true,
+ "requires": {
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
+ }
+ },
+ "os-name": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz",
+ "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==",
+ "dev": true,
+ "requires": {
+ "macos-release": "^2.2.0",
+ "windows-release": "^3.1.0"
+ }
+ },
+ "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
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
+ "dev": true
+ },
+ "p-each-series": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
+ "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=",
+ "dev": true,
+ "requires": {
+ "p-reduce": "^1.0.0"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true
+ },
+ "p-is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+ "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+ "dev": true
+ },
+ "p-map-series": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz",
+ "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=",
+ "dev": true,
+ "requires": {
+ "p-reduce": "^1.0.0"
+ }
+ },
+ "p-pipe": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz",
+ "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=",
+ "dev": true
+ },
+ "p-queue": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-4.0.0.tgz",
+ "integrity": "sha512-3cRXXn3/O0o3+eVmUroJPSj/esxoEFIm0ZOno/T+NzG/VZgPOqQ8WKmlNqubSEpZmCIngEy34unkHGg83ZIBmg==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^3.1.0"
+ }
+ },
+ "p-reduce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz",
+ "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=",
+ "dev": true
+ },
+ "p-retry": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
+ "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==",
+ "dev": true,
+ "requires": {
+ "retry": "^0.12.0"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+ "dev": true
+ }
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "p-waterfall": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-1.0.0.tgz",
+ "integrity": "sha1-ftlLPOszMngjU69qrhGqn8I1uwA=",
+ "dev": true,
+ "requires": {
+ "p-reduce": "^1.0.0"
+ }
+ },
+ "pako": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+ "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
+ "dev": true
+ },
+ "parallel-transform": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
+ "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
+ "dev": true,
+ "requires": {
+ "cyclist": "^1.0.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.1.5"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "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-asn1": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
+ "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==",
+ "dev": true,
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "parse-github-repo-url": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz",
+ "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+ "dev": true
+ },
+ "parse-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.1.tgz",
+ "integrity": "sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA==",
+ "dev": true,
+ "requires": {
+ "is-ssh": "^1.3.0",
+ "protocols": "^1.4.0"
+ }
+ },
+ "parse-url": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz",
+ "integrity": "sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg==",
+ "dev": true,
+ "requires": {
+ "is-ssh": "^1.3.0",
+ "normalize-url": "^3.3.0",
+ "parse-path": "^4.0.0",
+ "protocols": "^1.4.0"
+ }
+ },
+ "parse5": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
+ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==",
+ "dev": true
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "pbkdf2": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
+ "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
+ "dev": true
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pirates": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
+ "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
+ "dev": true,
+ "requires": {
+ "node-modules-regexp": "^1.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "pn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
+ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
+ "dev": true
+ },
+ "portfinder": {
+ "version": "1.0.23",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz",
+ "integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==",
+ "dev": true,
+ "requires": {
+ "async": "^1.5.2",
+ "debug": "^2.2.0",
+ "mkdirp": "0.5.x"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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
+ },
+ "postcss": {
+ "version": "7.0.17",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz",
+ "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "postcss-load-config": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz",
+ "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^5.0.0",
+ "import-cwd": "^2.0.0"
+ }
+ },
+ "postcss-loader": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
+ "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "postcss": "^7.0.0",
+ "postcss-load-config": "^2.0.0",
+ "schema-utils": "^1.0.0"
+ },
+ "dependencies": {
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
+ }
+ },
+ "postcss-modules-extract-imports": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
+ "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.5"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz",
+ "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^4.1.1",
+ "postcss": "^7.0.16",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.0.0"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz",
+ "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.6",
+ "postcss-selector-parser": "^6.0.0"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz",
+ "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^4.0.0",
+ "postcss": "^7.0.6"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz",
+ "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz",
+ "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+ "dev": true
+ },
+ "pretty-error": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
+ "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=",
+ "dev": true,
+ "requires": {
+ "renderkid": "^2.0.1",
+ "utila": "~0.4"
+ }
+ },
+ "pretty-format": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz",
+ "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.9.0",
+ "ansi-regex": "^4.0.0",
+ "ansi-styles": "^3.2.0",
+ "react-is": "^16.8.4"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ }
+ }
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "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
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
+ "dev": true
+ },
+ "promise-retry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
+ "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
+ "dev": true,
+ "requires": {
+ "err-code": "^1.0.0",
+ "retry": "^0.10.0"
+ }
+ },
+ "prompts": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz",
+ "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==",
+ "dev": true,
+ "requires": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.3"
+ }
+ },
+ "promzard": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz",
+ "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=",
+ "dev": true,
+ "requires": {
+ "read": "1"
+ }
+ },
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+ "dev": true
+ },
+ "protocols": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz",
+ "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==",
+ "dev": true
+ },
+ "protoduck": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
+ "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
+ "dev": true,
+ "requires": {
+ "genfun": "^5.0.0"
+ }
+ },
+ "proxy-addr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
+ "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
+ "dev": true,
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.0"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "dev": true
+ },
+ "psl": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.1.tgz",
+ "integrity": "sha512-2KLd5fKOdAfShtY2d/8XDWVRnmp3zp40Qt6ge2zBPFARLXOGUf2fHD5eg+TV/5oxBtQKVhjUaKFsAaE4HnwfSA==",
+ "dev": true
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "dev": true,
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "querystringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
+ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
+ "dev": true
+ },
+ "quick-lru": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
+ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true
+ }
+ }
+ },
+ "react": {
+ "version": "16.9.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz",
+ "integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2"
+ }
+ },
+ "react-dom": {
+ "version": "16.9.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.9.0.tgz",
+ "integrity": "sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2",
+ "scheduler": "^0.15.0"
+ }
+ },
+ "react-financial-charts": {
+ "version": "file:packages/react-financial-charts",
+ "requires": {
+ "d3-array": "^1.2.1",
+ "d3-collection": "^1.0.7",
+ "d3-force": "^1.1.0",
+ "d3-format": "^1.2.1",
+ "d3-interpolate": "^1.1.6",
+ "d3-path": "^1.0.8",
+ "d3-scale": "^1.0.7",
+ "d3-selection": "^1.2.0",
+ "d3-shape": "^1.2.0",
+ "d3-time": "^1.0.11",
+ "d3-time-format": "^2.1.3",
+ "debug": "^4.1.1",
+ "lodash.flattendeep": "^4.4.0",
+ "prop-types": "^15.7.2",
+ "save-svg-as-png": "^1.4.14"
+ }
+ },
+ "react-financial-charts-examples": {
+ "version": "file:packages/react-financial-charts-examples",
+ "requires": {
+ "d3-format": "^1.2.1",
+ "d3-scale": "^1.0.7",
+ "d3-time-format": "^2.1.3",
+ "react": "^16.9.0",
+ "react-dom": "^16.9.0",
+ "react-financial-charts": "file:packages/react-financial-charts",
+ "react-virtualized-auto-sizer": "^1.0.2"
+ }
+ },
+ "react-is": {
+ "version": "16.9.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz",
+ "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw=="
+ },
+ "react-virtualized-auto-sizer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz",
+ "integrity": "sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg=="
+ },
+ "read": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+ "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+ "dev": true,
+ "requires": {
+ "mute-stream": "~0.0.4"
+ }
+ },
+ "read-cmd-shim": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.4.tgz",
+ "integrity": "sha512-Pqpl3qJ/QdOIjRYA0q5DND/gLvGOfpIz/fYVDGYpOXfW/lFrIttmLsBnd6IkyK10+JHU9zhsaudfvrQTBB9YFQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "read-package-json": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.0.tgz",
+ "integrity": "sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.1",
+ "graceful-fs": "^4.1.2",
+ "json-parse-better-errors": "^1.0.1",
+ "normalize-package-data": "^2.0.0",
+ "slash": "^1.0.0"
+ },
+ "dependencies": {
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+ "dev": true
+ }
+ }
+ },
+ "read-package-tree": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz",
+ "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==",
+ "dev": true,
+ "requires": {
+ "read-package-json": "^2.0.0",
+ "readdir-scoped-modules": "^1.0.0",
+ "util-promisify": "^2.1.0"
+ }
+ },
+ "read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz",
+ "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0",
+ "read-pkg": "^3.0.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "readdir-scoped-modules": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz",
+ "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
+ "dev": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "dezalgo": "^1.0.0",
+ "graceful-fs": "^4.1.2",
+ "once": "^1.3.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,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "realpath-native": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
+ "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==",
+ "dev": true,
+ "requires": {
+ "util.promisify": "^1.0.0"
+ }
+ },
+ "redent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
+ "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=",
+ "dev": true,
+ "requires": {
+ "indent-string": "^3.0.0",
+ "strip-indent": "^2.0.0"
+ }
+ },
+ "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,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexp.prototype.flags": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz",
+ "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2"
+ }
+ },
+ "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
+ },
+ "renderkid": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz",
+ "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==",
+ "dev": true,
+ "requires": {
+ "css-select": "^1.1.0",
+ "dom-converter": "^0.2",
+ "htmlparser2": "^3.3.0",
+ "strip-ansi": "^3.0.0",
+ "utila": "^0.4.0"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "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"
+ }
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "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.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
+ "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "request-promise-native": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
+ "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
+ "dev": true,
+ "requires": {
+ "request-promise-core": "1.1.2",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+ "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+ "dev": true,
+ "requires": {
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ },
+ "dependencies": {
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ }
+ }
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true
+ },
+ "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
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "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
+ },
+ "retry": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
+ "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
+ "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "rsvp": {
+ "version": "4.8.5",
+ "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
+ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
+ "dev": true
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "dev": true,
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "run-queue": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
+ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.1.1"
+ }
+ },
+ "rxjs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
+ "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "sane": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz",
+ "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==",
+ "dev": true,
+ "requires": {
+ "@cnakazawa/watch": "^1.0.3",
+ "anymatch": "^2.0.0",
+ "capture-exit": "^2.0.0",
+ "exec-sh": "^0.3.2",
+ "execa": "^1.0.0",
+ "fb-watchman": "^2.0.0",
+ "micromatch": "^3.1.4",
+ "minimist": "^1.1.1",
+ "walker": "~1.0.5"
+ }
+ },
+ "save-svg-as-png": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/save-svg-as-png/-/save-svg-as-png-1.4.14.tgz",
+ "integrity": "sha512-hJqOFSdRvhBVD2pQSM+mJStvQGfnvQCCF6ULtAxdjF4lDwXYfWZ9Eug0fcRl05YyPL2yknCDBEOpbO4Fkw5qmg=="
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ },
+ "scheduler": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
+ "integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "schema-utils": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.2.0.tgz",
+ "integrity": "sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.10.2",
+ "ajv-keywords": "^3.4.1"
+ }
+ },
+ "select-hose": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
+ "dev": true
+ },
+ "selfsigned": {
+ "version": "1.10.4",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz",
+ "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==",
+ "dev": true,
+ "requires": {
+ "node-forge": "0.7.5"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "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"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ }
+ }
+ },
+ "serialize-javascript": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
+ "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
+ "dev": true
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "dev": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+ "dev": true
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "dev": true,
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+ "dev": true
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "dev": true
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "sisteransi": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz",
+ "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==",
+ "dev": true
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true
+ },
+ "slide": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
+ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=",
+ "dev": true
+ },
+ "smart-buffer": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz",
+ "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==",
+ "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,
+ "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": {
+ "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"
+ }
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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
+ }
+ }
+ },
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "sockjs": {
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
+ "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
+ "dev": true,
+ "requires": {
+ "faye-websocket": "^0.10.0",
+ "uuid": "^3.0.1"
+ }
+ },
+ "sockjs-client": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz",
+ "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.2.5",
+ "eventsource": "^1.0.7",
+ "faye-websocket": "~0.11.1",
+ "inherits": "^2.0.3",
+ "json3": "^3.3.2",
+ "url-parse": "^1.4.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "faye-websocket": {
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
+ "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
+ "dev": true,
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ }
+ }
+ },
+ "socks": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz",
+ "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==",
+ "dev": true,
+ "requires": {
+ "ip": "^1.1.5",
+ "smart-buffer": "4.0.2"
+ }
+ },
+ "socks-proxy-agent": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
+ "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "~4.2.1",
+ "socks": "~2.3.2"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
+ "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ }
+ }
+ },
+ "sort-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
+ "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ },
+ "source-list-map": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+ "dev": true
+ },
+ "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,
+ "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-support": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.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
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
+ "spdy": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz",
+ "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "handle-thing": "^2.0.0",
+ "http-deceiver": "^1.2.7",
+ "select-hose": "^2.0.0",
+ "spdy-transport": "^3.0.0"
+ }
+ },
+ "spdy-transport": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "detect-node": "^2.0.4",
+ "hpack.js": "^2.1.6",
+ "obuf": "^1.1.2",
+ "readable-stream": "^3.0.6",
+ "wbuf": "^1.7.3"
+ }
+ },
+ "split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ },
+ "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,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "split2": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
+ "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
+ "dev": true,
+ "requires": {
+ "through2": "^2.0.2"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "ssri": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "dev": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "stack-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
+ "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==",
+ "dev": true
+ },
+ "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,
+ "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,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "dev": true
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
+ "dev": true
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "stream-each": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
+ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
+ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
+ "dev": true
+ },
+ "strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
+ "dev": true
+ },
+ "string-length": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
+ "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=",
+ "dev": true,
+ "requires": {
+ "astral-regex": "^1.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "string.prototype.trimleft": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.0.0.tgz",
+ "integrity": "sha1-aLaqjhYsaoDnbjqKDC50cYbicf8=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.0.2"
+ }
+ },
+ "string.prototype.trimright": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.0.0.tgz",
+ "integrity": "sha1-q0pW2AKgH75yk+EehPJNyBZGYd0=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.0.2"
+ }
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.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"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true
+ },
+ "strip-indent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
+ "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
+ "dev": true
+ },
+ "strong-log-transformer": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz",
+ "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==",
+ "dev": true,
+ "requires": {
+ "duplexer": "^0.1.1",
+ "minimist": "^1.2.0",
+ "through": "^2.3.4"
+ }
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true
+ },
+ "tapable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
+ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+ "dev": true
+ },
+ "tar": {
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
+ "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
+ "dev": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.5",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ }
+ },
+ "temp-dir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz",
+ "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=",
+ "dev": true
+ },
+ "temp-write": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-3.4.0.tgz",
+ "integrity": "sha1-jP9jD7fp2gXwR8dM5M5NaFRX1JI=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "is-stream": "^1.1.0",
+ "make-dir": "^1.0.0",
+ "pify": "^3.0.0",
+ "temp-dir": "^1.0.0",
+ "uuid": "^3.0.1"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "terser": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-4.2.1.tgz",
+ "integrity": "sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.12"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+ "dev": true
+ }
+ }
+ },
+ "terser-webpack-plugin": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz",
+ "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==",
+ "dev": true,
+ "requires": {
+ "cacache": "^12.0.2",
+ "find-cache-dir": "^2.1.0",
+ "is-wsl": "^1.1.0",
+ "schema-utils": "^1.0.0",
+ "serialize-javascript": "^1.7.0",
+ "source-map": "^0.6.1",
+ "terser": "^4.1.2",
+ "webpack-sources": "^1.4.0",
+ "worker-farm": "^1.7.0"
+ },
+ "dependencies": {
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
+ }
+ },
+ "test-exclude": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
+ "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3",
+ "minimatch": "^3.0.4",
+ "read-pkg-up": "^4.0.0",
+ "require-main-filename": "^2.0.0"
+ }
+ },
+ "text-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz",
+ "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==",
+ "dev": true
+ },
+ "thenify": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
+ "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+ "dev": true,
+ "requires": {
+ "thenify": ">= 3.1.0 < 4"
+ }
+ },
+ "throat": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz",
+ "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "thunky": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz",
+ "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==",
+ "dev": true
+ },
+ "timers-browserify": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
+ "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
+ "dev": true,
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "tmpl": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
+ "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=",
+ "dev": true
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "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,
+ "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,
+ "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,
+ "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,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "dev": true
+ },
+ "toposort": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
+ "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
+ "dev": true
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "trim-newlines": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
+ "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=",
+ "dev": true
+ },
+ "trim-off-newlines": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz",
+ "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=",
+ "dev": true
+ },
+ "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
+ },
+ "ts-loader": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.0.4.tgz",
+ "integrity": "sha512-p2zJYe7OtwR+49kv4gs7v4dMrfYD1IPpOtqiSPCbe8oR+4zEBtdHwzM7A7M91F+suReqgzZrlClk4LRSSp882g==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.3.0",
+ "enhanced-resolve": "^4.0.0",
+ "loader-utils": "^1.0.2",
+ "micromatch": "^4.0.0",
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
+ "tslib": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
+ "dev": true
+ },
+ "tslint": {
+ "version": "5.19.0",
+ "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz",
+ "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "builtin-modules": "^1.1.1",
+ "chalk": "^2.3.0",
+ "commander": "^2.12.1",
+ "diff": "^3.2.0",
+ "glob": "^7.1.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "resolve": "^1.3.2",
+ "semver": "^5.3.0",
+ "tslib": "^1.8.0",
+ "tsutils": "^2.29.0"
+ }
+ },
+ "tsutils": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+ "dev": true
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-fest": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
+ "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==",
+ "dev": true
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dev": true,
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "typescript": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
+ "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
+ "dev": true
+ },
+ "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
+ }
+ }
+ },
+ "uid-number": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
+ "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=",
+ "dev": true
+ },
+ "umask": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz",
+ "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=",
+ "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,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "dev": true,
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "dev": true,
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "universal-user-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
+ "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
+ "dev": true,
+ "requires": {
+ "os-name": "^3.1.0"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true
+ },
+ "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,
+ "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,
+ "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,
+ "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
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": 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
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "url-parse": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
+ "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
+ "dev": true,
+ "requires": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "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
+ },
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "util-promisify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz",
+ "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=",
+ "dev": true,
+ "requires": {
+ "object.getownpropertydescriptors": "^2.0.3"
+ }
+ },
+ "util.promisify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
+ "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "object.getownpropertydescriptors": "^2.0.3"
+ }
+ },
+ "utila": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
+ "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
+ "dev": true
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
+ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
+ "dev": true
+ },
+ "v8-compile-cache": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
+ "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==",
+ "dev": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "validate-npm-package-name": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
+ "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+ "dev": true,
+ "requires": {
+ "builtins": "^1.0.3"
+ }
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "dev": true
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "vm-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz",
+ "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==",
+ "dev": true
+ },
+ "w3c-hr-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
+ "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
+ "dev": true,
+ "requires": {
+ "browser-process-hrtime": "^0.1.2"
+ }
+ },
+ "walker": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+ "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
+ "dev": true,
+ "requires": {
+ "makeerror": "1.0.x"
+ }
+ },
+ "watchpack": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
+ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^2.0.2",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0"
+ }
+ },
+ "wbuf": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+ "dev": true,
+ "requires": {
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+ "dev": true,
+ "requires": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
+ "webpack": {
+ "version": "4.39.3",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.3.tgz",
+ "integrity": "sha512-BXSI9M211JyCVc3JxHWDpze85CvjC842EvpRsVTc/d15YJGlox7GIDd38kJgWrb3ZluyvIjgenbLDMBQPDcxYQ==",
+ "dev": true,
+ "requires": {
+ "@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.1",
+ "watchpack": "^1.6.0",
+ "webpack-sources": "^1.4.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
+ "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ }
+ }
+ },
+ "webpack-cli": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.7.tgz",
+ "integrity": "sha512-OhTUCttAsr+IZSMVwGROGRHvT+QAs8H6/mHIl4SvhAwYywjiylYjpwybGx7WQ9Hkb45FhjtsymkwiRRbGJ1SZQ==",
+ "dev": true,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "yargs": {
+ "version": "13.2.4",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
+ "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
+ "dev": true,
+ "requires": {
+ "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"
+ }
+ }
+ }
+ },
+ "webpack-dev-middleware": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.1.tgz",
+ "integrity": "sha512-5MWu9SH1z3hY7oHOV6Kbkz5x7hXbxK56mGHNqHTe6d+ewxOwKUxoUJBs7QIaJb33lPjl9bJZ3X0vCoooUzC36A==",
+ "dev": true,
+ "requires": {
+ "memory-fs": "^0.4.1",
+ "mime": "^2.4.4",
+ "mkdirp": "^0.5.1",
+ "range-parser": "^1.2.1",
+ "webpack-log": "^2.0.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
+ "dev": true
+ }
+ }
+ },
+ "webpack-dev-server": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz",
+ "integrity": "sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==",
+ "dev": true,
+ "requires": {
+ "ansi-html": "0.0.7",
+ "bonjour": "^3.5.0",
+ "chokidar": "^2.1.6",
+ "compression": "^1.7.4",
+ "connect-history-api-fallback": "^1.6.0",
+ "debug": "^4.1.1",
+ "del": "^4.1.1",
+ "express": "^4.17.1",
+ "html-entities": "^1.2.1",
+ "http-proxy-middleware": "^0.19.1",
+ "import-local": "^2.0.0",
+ "internal-ip": "^4.3.0",
+ "ip": "^1.1.5",
+ "is-absolute-url": "^3.0.0",
+ "killable": "^1.0.1",
+ "loglevel": "^1.6.3",
+ "opn": "^5.5.0",
+ "p-retry": "^3.0.1",
+ "portfinder": "^1.0.21",
+ "schema-utils": "^1.0.0",
+ "selfsigned": "^1.10.4",
+ "semver": "^6.3.0",
+ "serve-index": "^1.9.1",
+ "sockjs": "0.3.19",
+ "sockjs-client": "1.3.0",
+ "spdy": "^4.0.1",
+ "strip-ansi": "^3.0.1",
+ "supports-color": "^6.1.0",
+ "url": "^0.11.0",
+ "webpack-dev-middleware": "^3.7.0",
+ "webpack-log": "^2.0.0",
+ "ws": "^6.2.1",
+ "yargs": "12.0.5"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "ws": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
+ "webpack-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
+ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "webpack-sources": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
+ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+ "dev": true,
+ "requires": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
+ "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
+ "dev": true,
+ "requires": {
+ "http-parser-js": ">=0.4.0 <0.4.11",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
+ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
+ "dev": true
+ },
+ "whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
+ "dev": true
+ },
+ "whatwg-url": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
+ "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "windows-release": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz",
+ "integrity": "sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==",
+ "dev": true,
+ "requires": {
+ "execa": "^1.0.0"
+ }
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ },
+ "worker-farm": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
+ "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+ "dev": true,
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "write-file-atomic": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
+ "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "write-json-file": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz",
+ "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==",
+ "dev": true,
+ "requires": {
+ "detect-indent": "^5.0.0",
+ "graceful-fs": "^4.1.15",
+ "make-dir": "^2.1.0",
+ "pify": "^4.0.1",
+ "sort-keys": "^2.0.0",
+ "write-file-atomic": "^2.4.2"
+ },
+ "dependencies": {
+ "write-file-atomic": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
+ "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ }
+ }
+ },
+ "write-pkg": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz",
+ "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==",
+ "dev": true,
+ "requires": {
+ "sort-keys": "^2.0.0",
+ "write-json-file": "^2.2.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ },
+ "write-json-file": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz",
+ "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=",
+ "dev": true,
+ "requires": {
+ "detect-indent": "^5.0.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^1.0.0",
+ "pify": "^3.0.0",
+ "sort-keys": "^2.0.0",
+ "write-file-atomic": "^2.0.0"
+ }
+ }
+ }
+ },
+ "ws": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
+ "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
+ "dev": true,
+ "requires": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "13.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
+ "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..8d09fbc69
--- /dev/null
+++ b/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "root",
+ "private": true,
+ "scripts": {
+ "postinstall": "npm run bootstrap",
+ "bootstrap": "lerna bootstrap",
+ "build": "lerna run build",
+ "clean": "lerna run clean && lerna clean --yes",
+ "convert": "lerna link convert && npm run bootstrap",
+ "lint": "lerna run lint",
+ "start": "lerna run start --stream",
+ "test": "lerna run test --stream",
+ "minor": "lerna version minor --conventional-commits --no-git-tag-version --no-push --no-changelog --yes",
+ "patch": "lerna version patch --conventional-commits --no-git-tag-version --no-push --no-changelog --yes",
+ "prepublishOnly": "npm run build",
+ "publish": "lerna publish from-package --no-git-reset --yes"
+ },
+ "workspaces": [
+ "packages/*"
+ ],
+ "devDependencies": {
+ "@types/d3-format": "^1.3.1",
+ "@types/d3-time-format": "^2.1.1",
+ "@types/jest": "^24.0.18",
+ "@types/react": "^16.9.2",
+ "@types/react-dom": "^16.9.0",
+ "@types/react-virtualized-auto-sizer": "^1.0.0",
+ "clean-webpack-plugin": "^3.0.0",
+ "css-loader": "^3.2.0",
+ "file-loader": "^4.2.0",
+ "html-webpack-plugin": "^3.2.0",
+ "html-webpack-template": "^6.2.0",
+ "jest": "^24.9.0",
+ "lerna": "^3.14.1",
+ "mini-css-extract-plugin": "^0.8.0",
+ "postcss-loader": "^3.0.0",
+ "react": "^16.9.0",
+ "react-dom": "^16.9.0",
+ "rimraf": "^3.0.0",
+ "ts-loader": "^6.0.4",
+ "tslint": "^5.19.0",
+ "typescript": "^3.6.2",
+ "webpack": "^4.39.3",
+ "webpack-cli": "^3.3.7",
+ "webpack-dev-server": "^3.8.0"
+ },
+ "dependencies": {
+ "react-financial-charts": "file:packages/react-financial-charts",
+ "react-financial-charts-examples": "file:packages/react-financial-charts-examples"
+ }
+}
diff --git a/packages/react-financial-charts-examples/LICENSE b/packages/react-financial-charts-examples/LICENSE
new file mode 100644
index 000000000..1ffc51b2f
--- /dev/null
+++ b/packages/react-financial-charts-examples/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+https://github.com/reactivemarkets/react-financial-charts
+
+Copyright (c) 2015-2018 Ragu Ramaswamy
+Copyright (c) 2016 Julien Renaux
+Copyright (c) 2019 Reactive Markets
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/packages/react-financial-charts-examples/README.md b/packages/react-financial-charts-examples/README.md
new file mode 100644
index 000000000..87321e1b9
--- /dev/null
+++ b/packages/react-financial-charts-examples/README.md
@@ -0,0 +1,12 @@
+# Test UI
+
+Test UI loads up all the tiles and uses the default App.
+
+## Quick Start
+
+Install dependencies and start the server.
+
+```bash
+npm ci
+npm start:test-ui
+```
diff --git a/packages/react-financial-charts-examples/package.json b/packages/react-financial-charts-examples/package.json
new file mode 100644
index 000000000..b7bb73052
--- /dev/null
+++ b/packages/react-financial-charts-examples/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "react-financial-charts-examples",
+ "version": "0.1.0",
+ "description": "Example charts",
+ "private": true,
+ "author": "reactivemarkets",
+ "license": "MIT",
+ "scripts": {
+ "clean": "rimraf dist",
+ "build": "webpack --config webpack.config.js",
+ "start": "webpack-dev-server --progress --config webpack.config.js"
+ },
+ "dependencies": {
+ "d3-format": "^1.2.1",
+ "d3-scale": "^1.0.7",
+ "d3-time-format": "^2.1.3",
+ "react": "^16.9.0",
+ "react-dom": "^16.9.0",
+ "react-financial-charts": "file:../react-financial-charts",
+ "react-virtualized-auto-sizer": "^1.0.2"
+ }
+}
diff --git a/packages/react-financial-charts-examples/src/@types/d3-scale.d.ts b/packages/react-financial-charts-examples/src/@types/d3-scale.d.ts
new file mode 100644
index 000000000..09eb2668b
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/@types/d3-scale.d.ts
@@ -0,0 +1 @@
+declare module 'd3-scale';
diff --git a/packages/react-financial-charts-examples/src/components/index.ts b/packages/react-financial-charts-examples/src/components/index.ts
new file mode 100644
index 000000000..67fb34209
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/components/index.ts
@@ -0,0 +1 @@
+export * from "./responsiveStockChart";
diff --git a/packages/react-financial-charts-examples/src/components/responsiveStockChart.tsx b/packages/react-financial-charts-examples/src/components/responsiveStockChart.tsx
new file mode 100644
index 000000000..2d0c9abf6
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/components/responsiveStockChart.tsx
@@ -0,0 +1,131 @@
+import * as React from "react";
+import AutoSizer from "react-virtualized-auto-sizer";
+import StockChart from "./stockChart";
+
+export class ResponsiveStockChart extends React.Component {
+ public render() {
+
+ const data = [
+ {
+ close: 1.10294,
+ high: 1.10301,
+ low: 1.10286,
+ open: 1.10291,
+ time: new Date(1567715580000),
+ },
+ {
+ close: 1.10292,
+ high: 1.10297,
+ low: 1.10287,
+ open: 1.10294,
+ time: new Date(1567715640000),
+ },
+ {
+ close: 1.10291,
+ high: 1.10299,
+ low: 1.10285,
+ open: 1.10293,
+ time: new Date(1567715700000),
+ },
+ {
+ close: 1.10292,
+ high: 1.10296,
+ low: 1.10282,
+ open: 1.10291,
+ time: new Date(1567715760000),
+ },
+ {
+ close: 1.10293,
+ high: 1.10298,
+ low: 1.10288,
+ open: 1.10288,
+ time: new Date(1567715820000),
+ },
+ {
+ close: 1.10289,
+ high: 1.10294,
+ low: 1.10286,
+ open: 1.10288,
+ time: new Date(1567715880000),
+ },
+ {
+ close: 1.10293,
+ high: 1.10295,
+ low: 1.10283,
+ open: 1.10288,
+ time: new Date(1567715940000),
+ },
+ {
+ close: 1.10288,
+ high: 1.10299,
+ low: 1.10287,
+ open: 1.10293,
+ time: new Date(1567716000000),
+ },
+ {
+ close: 1.10292,
+ high: 1.10302,
+ low: 1.10286,
+ open: 1.1029,
+ time: new Date(1567716060000),
+ },
+ {
+ close: 1.10295,
+ high: 1.10295,
+ low: 1.10282,
+ open: 1.10293,
+ time: new Date(1567716120000),
+ },
+ {
+ close: 1.10286,
+ high: 1.10298,
+ low: 1.10283,
+ open: 1.10297,
+ time: new Date(1567716180000),
+ },
+ {
+ close: 1.10294,
+ high: 1.10296,
+ low: 1.10286,
+ open: 1.10289,
+ time: new Date(1567716240000),
+ },
+ {
+ close: 1.10289,
+ high: 1.10296,
+ low: 1.10284,
+ open: 1.10294,
+ time: new Date(1567716300000),
+ },
+ {
+ close: 1.10285,
+ high: 1.10302,
+ low: 1.10285,
+ open: 1.10289,
+ time: new Date(1567716360000),
+ },
+ {
+ close: 1.10281,
+ high: 1.10285,
+ low: 1.10281,
+ open: 1.10284,
+ time: new Date(1567716420000),
+ },
+ ];
+
+ return (
+
+
+ {({ height, width }) => {
+ return (
+
+ );
+ }}
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts-examples/src/components/stockChart.tsx b/packages/react-financial-charts-examples/src/components/stockChart.tsx
new file mode 100644
index 000000000..0a382b2da
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/components/stockChart.tsx
@@ -0,0 +1,77 @@
+// @ts-ignore
+import { format } from "d3-format";
+import { scaleTime } from "d3-scale";
+import { timeFormat } from "d3-time-format";
+import * as React from "react";
+import { Chart, ChartCanvas } from "react-financial-charts";
+import { XAxis, YAxis } from "react-financial-charts/lib/axes";
+import { CrossHairCursor, EdgeIndicator, MouseCoordinateX, MouseCoordinateY } from "react-financial-charts/lib/coordinates";
+import { CandlestickSeries } from "react-financial-charts/lib/series";
+import { last } from "react-financial-charts/lib/utils";
+import { IOHLCData } from "../stores";
+import withDimensions from "./withDimensions";
+
+interface StockChartProps {
+ readonly data: any[];
+ readonly height: number;
+ readonly width: number;
+ readonly ratio: number;
+}
+
+class StockChart extends React.Component {
+ public render() {
+
+ const {
+ data,
+ height,
+ ratio,
+ width,
+ } = this.props;
+
+ const xAccessor = (d: IOHLCData) => d.time;
+
+ const start = xAccessor(last(data));
+ const end = xAccessor(data[0]);
+ const xExtents = [start, end];
+
+ const yExtents = [(d: IOHLCData) => [d.high, d.low]];
+
+ return (
+
+
+
+
+
+
+
+ d.close} />
+
+
+
+ );
+ }
+}
+
+export default withDimensions(StockChart);
diff --git a/packages/react-financial-charts-examples/src/components/withDimensions.tsx b/packages/react-financial-charts-examples/src/components/withDimensions.tsx
new file mode 100644
index 000000000..1ed4fa054
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/components/withDimensions.tsx
@@ -0,0 +1,96 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+
+export default function withDimensions(WrappedComponent, props: any = {}) {
+
+ const {
+ minWidth = 100,
+ minHeight = 100,
+ ratio,
+ width,
+ height,
+ } = props;
+
+ function getDimensions(el) {
+ const w = el.parentNode.clientWidth;
+ const h = el.parentNode.clientHeight;
+
+ return {
+ width: width !== undefined ? width : Math.max(w, minWidth),
+ height: height !== undefined ? height : Math.max(h, minHeight),
+ };
+ }
+
+ class ResponsiveComponent extends React.Component {
+ private node;
+ private testCanvas;
+ constructor(props: any) {
+ super(props);
+ this.handleWindowResize = this.handleWindowResize.bind(this);
+ this.getWrappedInstance = this.getWrappedInstance.bind(this);
+ this.saveNode = this.saveNode.bind(this);
+ this.setTestCanvas = this.setTestCanvas.bind(this);
+ this.state = {};
+ }
+ public saveNode(node) {
+ this.node = node;
+ }
+ public setTestCanvas(node) {
+ this.testCanvas = node;
+ }
+ public getRatio() {
+ if (this.testCanvas !== undefined) {
+ const context = this.testCanvas.getContext("2d");
+
+ const devicePixelRatio = window.devicePixelRatio || 1;
+ const backingStoreRatio = context.webkitBackingStorePixelRatio ||
+ context.mozBackingStorePixelRatio ||
+ context.msBackingStorePixelRatio ||
+ context.oBackingStorePixelRatio ||
+ context.backingStorePixelRatio || 1;
+
+ return devicePixelRatio / backingStoreRatio;
+
+ }
+ return 1;
+ }
+ public componentDidMount() {
+ window.addEventListener("resize", this.handleWindowResize);
+ const dimensions = getDimensions(this.node);
+
+ this.setState({
+ ...dimensions,
+ ratio: ratio !== undefined ? ratio : this.getRatio(),
+ });
+ }
+ public componentWillUnmount() {
+ window.removeEventListener("resize", this.handleWindowResize);
+ }
+ public handleWindowResize() {
+ const node = ReactDOM.findDOMNode(this.node);
+ this.setState(getDimensions(node));
+ }
+ public getWrappedInstance() {
+ return this.node;
+ }
+ public render() {
+ const ref = { ref: this.saveNode };
+
+ if (this.state.width) {
+ return ;
+ } else {
+ return
+
+
;
+ }
+ }
+ }
+
+ return ResponsiveComponent;
+}
diff --git a/packages/react-financial-charts-examples/src/index.tsx b/packages/react-financial-charts-examples/src/index.tsx
new file mode 100644
index 000000000..3ce9c9565
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/index.tsx
@@ -0,0 +1,11 @@
+import * as React from "react";
+import { render } from "react-dom";
+import { ResponsiveStockChart } from "./components";
+
+const app = (
+
+);
+
+const containerElement = document.getElementById("app");
+
+render(app, containerElement);
diff --git a/packages/react-financial-charts-examples/src/stores/iOHLCData.ts b/packages/react-financial-charts-examples/src/stores/iOHLCData.ts
new file mode 100644
index 000000000..a1ccda38a
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/stores/iOHLCData.ts
@@ -0,0 +1,7 @@
+export interface IOHLCData {
+ readonly close: number;
+ readonly high: number;
+ readonly low: number;
+ readonly open: number;
+ readonly time: Date;
+}
diff --git a/packages/react-financial-charts-examples/src/stores/index.ts b/packages/react-financial-charts-examples/src/stores/index.ts
new file mode 100644
index 000000000..6f5df441c
--- /dev/null
+++ b/packages/react-financial-charts-examples/src/stores/index.ts
@@ -0,0 +1 @@
+export * from "./iOHLCData";
diff --git a/packages/react-financial-charts-examples/tsconfig.json b/packages/react-financial-charts-examples/tsconfig.json
new file mode 100644
index 000000000..011dd597c
--- /dev/null
+++ b/packages/react-financial-charts-examples/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "lib": [
+ "esnext.array",
+ "esnext.asynciterable",
+ "esnext",
+ "dom"
+ ],
+ "moduleResolution": "node",
+ "module": "esnext",
+ "noImplicitAny": false,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "outDir": "./dist/",
+ "sourceMap": true,
+ "strict": false,
+ "target": "es2017",
+ "baseUrl": "../.."
+ },
+ "include": [
+ "src"
+ ],
+ "exclude": [
+ "node_modules",
+ "lib",
+ "dist",
+ "**/__tests__/**"
+ ]
+}
diff --git a/packages/react-financial-charts-examples/tslint.yaml b/packages/react-financial-charts-examples/tslint.yaml
new file mode 100644
index 000000000..7325d2a01
--- /dev/null
+++ b/packages/react-financial-charts-examples/tslint.yaml
@@ -0,0 +1,10 @@
+---
+extends: "tslint:recommended"
+rules:
+ completed-docs: false
+ interface-name: false
+ object-literal-sort-keys: false
+ only-arrow-functions: false
+ space-before-function-paren: false
+ max-line-length:
+ options: [140]
diff --git a/packages/react-financial-charts-examples/webpack.config.js b/packages/react-financial-charts-examples/webpack.config.js
new file mode 100644
index 000000000..e52840291
--- /dev/null
+++ b/packages/react-financial-charts-examples/webpack.config.js
@@ -0,0 +1,103 @@
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const HtmlWebpackPlugin = require("html-webpack-plugin");
+const HtmlWebpackTemplate = require("html-webpack-template");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+const path = require("path");
+
+module.exports = {
+ devtool: "source-map",
+ devServer: {
+ compress: true,
+ contentBase: "./dist",
+ historyApiFallback: true,
+ inline: true,
+ watchContentBase: true,
+ port: 8000,
+ },
+ mode: "development",
+ entry: {
+ main: "./src/index.tsx",
+ },
+ output: {
+ filename: "[name].[chunkhash:8].js",
+ chunkFilename: "[name].[chunkhash:8].js",
+ devtoolModuleFilenameTemplate: "[absolute-resource-path]",
+ path: path.join(__dirname, "dist"),
+ publicPath: "/"
+ },
+ resolve: {
+ extensions: [".ts", ".tsx", ".js"]
+ },
+ module: {
+ rules: [{
+ test: /\.tsx?$/,
+ use: "ts-loader",
+ exclude: /node_modules/,
+ }, {
+ test: /\.(css)$/,
+ use: [{
+ loader: MiniCssExtractPlugin.loader
+ }, {
+ loader: "css-loader"
+ }, {
+ loader: "postcss-loader",
+ }]
+ }, {
+ test: /\.(png|jpe?g|gif|woff2?|ttf|eot|ico|mp4)$/,
+ use: [{
+ loader: "file-loader",
+ options: {
+ name: "[name].[hash:8].[ext]"
+ }
+ }]
+ }]
+ },
+ node: {
+ dgram: "empty",
+ fs: "empty",
+ net: "empty",
+ tls: "empty",
+ child_process: "empty",
+ },
+ optimization: {
+ splitChunks: {
+ chunks: "all",
+ },
+ runtimeChunk: true,
+ },
+ plugins: [
+ new CleanWebpackPlugin(),
+ new MiniCssExtractPlugin({
+ filename: "[name].[contenthash:8].css",
+ chunkFilename: '[name].[contenthash:8].chunk.css',
+ }),
+ new HtmlWebpackPlugin({
+ inject: false,
+ template: HtmlWebpackTemplate,
+ appMountId: "app",
+ headHtmlSnippet: "",
+ bodyHtmlSnippet: "",
+ lang: "en",
+ meta: [{
+ name: 'viewport',
+ content: 'width=device-width,initial-scale=1,minimum-scale=1'
+ }, {
+ name: "description",
+ content: "React Financial Charts"
+ }],
+ minify: {
+ removeComments: true,
+ collapseWhitespace: true,
+ removeRedundantAttributes: true,
+ useShortDoctype: true,
+ removeEmptyAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ keepClosingSlash: true,
+ minifyJS: true,
+ minifyCSS: true,
+ minifyURLs: true,
+ },
+ title: "React Financial Charts"
+ }),
+ ]
+};
diff --git a/packages/react-financial-charts/LICENSE b/packages/react-financial-charts/LICENSE
new file mode 100644
index 000000000..1ffc51b2f
--- /dev/null
+++ b/packages/react-financial-charts/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+https://github.com/reactivemarkets/react-financial-charts
+
+Copyright (c) 2015-2018 Ragu Ramaswamy
+Copyright (c) 2016 Julien Renaux
+Copyright (c) 2019 Reactive Markets
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/packages/react-financial-charts/jest.config.js b/packages/react-financial-charts/jest.config.js
new file mode 100644
index 000000000..157ec0878
--- /dev/null
+++ b/packages/react-financial-charts/jest.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+ preset: 'ts-jest',
+ collectCoverage: true,
+ coverageReporters: ["text-summary"],
+ errorOnDeprecated: true,
+ testMatch: [
+ "**/__tests__/**/*.+(ts|tsx)"
+ ],
+};
diff --git a/packages/react-financial-charts/package.json b/packages/react-financial-charts/package.json
new file mode 100644
index 000000000..c93ad98ee
--- /dev/null
+++ b/packages/react-financial-charts/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "react-financial-charts",
+ "version": "0.1.0",
+ "description": "React charts specific to finance.",
+ "main": "./lib/index.js",
+ "typings": "./lib/index.d.ts",
+ "files": [
+ "lib"
+ ],
+ "sideEffects": false,
+ "author": "reactivemarkets",
+ "keywords": [
+ "charts",
+ "charting",
+ "stockcharts",
+ "finance",
+ "finanical",
+ "finance-chart",
+ "react",
+ "d3"
+ ],
+ "license": "MIT",
+ "scripts": {
+ "build": "npm run clean && npm run compile",
+ "clean": "rimraf lib",
+ "compile": "tsc -p tsconfig.json",
+ "lint": "tslint -p tsconfig.json -c tslint.yaml",
+ "test": "jest",
+ "watch": "tsc -p tsconfig.json --watch --preserveWatchOutput"
+ },
+ "dependencies": {
+ "d3-array": "^1.2.1",
+ "d3-collection": "^1.0.7",
+ "d3-force": "^1.1.0",
+ "d3-format": "^1.2.1",
+ "d3-interpolate": "^1.1.6",
+ "d3-path": "^1.0.8",
+ "d3-scale": "^1.0.7",
+ "d3-selection": "^1.2.0",
+ "d3-shape": "^1.2.0",
+ "d3-time": "^1.0.11",
+ "d3-time-format": "^2.1.3",
+ "debug": "^4.1.1",
+ "lodash.flattendeep": "^4.4.0",
+ "prop-types": "^15.7.2",
+ "save-svg-as-png": "^1.4.14"
+ },
+ "peerDependencies": {
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
+ }
+}
diff --git a/packages/react-financial-charts/src/BackgroundText.tsx b/packages/react-financial-charts/src/BackgroundText.tsx
new file mode 100644
index 000000000..5e69b74c0
--- /dev/null
+++ b/packages/react-financial-charts/src/BackgroundText.tsx
@@ -0,0 +1,96 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import { hexToRGBA, isDefined } from "./utils";
+import { PureComponent } from "./utils/PureComponent";
+
+interface BackgroundTextProps {
+ x: number;
+ y: number;
+ fontFamily?: string;
+ fontSize?: number;
+ fill?: string;
+ stroke?: string;
+ opacity?: number;
+ strokeOpacity?: number;
+ textAnchor?: string;
+ children: (interval: number) => string;
+}
+
+class BackgroundText extends PureComponent {
+
+ public static defaultProps = {
+ opacity: 0.3,
+ fill: "#9E7523",
+ stroke: "#9E7523",
+ strokeOpacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ textAnchor: "middle",
+ };
+
+ public static contextTypes = {
+ interval: PropTypes.string.isRequired,
+ getCanvasContexts: PropTypes.func,
+ chartCanvasType: PropTypes.string,
+ };
+
+ public componentDidMount() {
+ if (this.context.chartCanvasType !== "svg" && isDefined(this.context.getCanvasContexts)) {
+ const contexts = this.context.getCanvasContexts();
+ if (contexts) {
+ this.drawOnCanvas(contexts.bg, this.props, this.context, this.props.children);
+ }
+ }
+ }
+
+ public componentDidUpdate() {
+ this.componentDidMount();
+ }
+
+ public render() {
+ const { chartCanvasType, interval } = this.context;
+
+ if (chartCanvasType !== "svg") {
+ return null;
+ }
+
+ const { x, y, fill, opacity, stroke, strokeOpacity, fontFamily, fontSize, textAnchor } = this.props;
+
+ const props = { x, y, fill, opacity, stroke, strokeOpacity, fontFamily, fontSize, textAnchor };
+
+ return (
+
+ {this.props.children(interval)}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, props, { interval }, getText) => {
+ ctx.clearRect(-1, -1, ctx.canvas.width + 2, ctx.canvas.height + 2);
+ ctx.save();
+
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.translate(0.5, 0.5);
+
+ const { x, y, fill, opacity, stroke, strokeOpacity, fontFamily, fontSize, textAnchor } = props;
+
+ const text = getText(interval);
+
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor;
+
+ if (stroke !== "none") {
+ ctx.strokeText(text, x, y);
+ }
+
+ ctx.fillText(text, x, y);
+
+ ctx.restore();
+ }
+}
+
+export default BackgroundText;
diff --git a/packages/react-financial-charts/src/CanvasContainer.tsx b/packages/react-financial-charts/src/CanvasContainer.tsx
new file mode 100644
index 000000000..c72dd8f37
--- /dev/null
+++ b/packages/react-financial-charts/src/CanvasContainer.tsx
@@ -0,0 +1,68 @@
+import * as React from "react";
+
+import { isDefined } from "./utils";
+
+interface CanvasContainerProps {
+ readonly width: number;
+ readonly height: number;
+ readonly type: string;
+ readonly zIndex?: number;
+ readonly ratio: number;
+}
+
+class CanvasContainer extends React.Component {
+
+ private drawCanvas: any;
+
+ public constructor(props: CanvasContainerProps) {
+ super(props);
+ this.setDrawCanvas = this.setDrawCanvas.bind(this);
+ this.drawCanvas = {};
+ }
+
+ public setDrawCanvas(node) {
+ if (isDefined(node)) {
+ this.drawCanvas[node.id] = node.getContext("2d");
+ } else {
+ this.drawCanvas = {};
+ }
+ }
+
+ public getCanvasContexts() {
+ if (isDefined(this.drawCanvas.axes)) {
+ return this.drawCanvas;
+ }
+ }
+
+ public render() {
+ const { height, width, type, zIndex, ratio } = this.props;
+ if (type === "svg") {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+export default CanvasContainer;
diff --git a/packages/react-financial-charts/src/Chart.tsx b/packages/react-financial-charts/src/Chart.tsx
new file mode 100644
index 000000000..dc8c67409
--- /dev/null
+++ b/packages/react-financial-charts/src/Chart.tsx
@@ -0,0 +1,109 @@
+import { scaleLinear } from "d3-scale";
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import {
+ find,
+ noop,
+} from "./utils";
+import { PureComponent } from "./utils/PureComponent";
+
+interface ChartProps {
+ height?: number;
+ origin?: number[] | any; // func
+ id: number | string;
+ yExtents?: number[] | any; // func
+ yExtentsCalculator?: any; // func
+ onContextMenu?: (props: any, event: React.MouseEvent) => void;
+ yScale?: any; // func
+ flipYScale?: boolean;
+ padding?: number | { top: number; bottom: number; };
+}
+
+export class Chart extends PureComponent {
+
+ public static defaultProps = {
+ id: 0,
+ origin: [0, 0],
+ padding: 0,
+ yScale: scaleLinear(),
+ flipYScale: false,
+ yPan: true,
+ yPanEnabled: false,
+ onContextMenu: noop,
+ };
+
+ public static contextTypes = {
+ chartConfig: PropTypes.array,
+ subscribe: PropTypes.func.isRequired,
+ unsubscribe: PropTypes.func.isRequired,
+ };
+
+ public static childContextTypes = {
+ chartConfig: PropTypes.object.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
+ };
+
+ constructor(props: ChartProps, context) {
+ super(props, context);
+
+ this.yScale = this.yScale.bind(this);
+ this.listener = this.listener.bind(this);
+ }
+
+ public componentDidMount() {
+ const { id } = this.props;
+ const { subscribe } = this.context;
+
+ subscribe(`chart_${id}`, {
+ listener: this.listener,
+ });
+ }
+
+ public componentWillUnmount() {
+ const { id } = this.props;
+ const { unsubscribe } = this.context;
+
+ unsubscribe(`chart_${id}`);
+ }
+
+ public listener(type, moreProps, state, e) {
+ const { id, onContextMenu } = this.props;
+
+ if (type === "contextmenu") {
+ const { currentCharts } = moreProps;
+ if (currentCharts.indexOf(id) > -1) {
+ if (onContextMenu !== undefined) {
+ onContextMenu(moreProps, e);
+ }
+ }
+ }
+ }
+
+ public yScale() {
+ const chartConfig = find(this.context.chartConfig, (each) => each.id === this.props.id);
+ return chartConfig.yScale.copy();
+ }
+
+ public getChildContext() {
+ const { id: chartId } = this.props;
+
+ const chartConfig = find(this.context.chartConfig, (each) => each.id === chartId);
+
+ return {
+ chartId,
+ chartConfig,
+ };
+ }
+
+ public render() {
+ const { origin } = find(this.context.chartConfig, (each) => each.id === this.props.id);
+ const [x, y] = origin;
+
+ return (
+
+ {this.props.children}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/ChartCanvas.tsx b/packages/react-financial-charts/src/ChartCanvas.tsx
new file mode 100644
index 000000000..89605c886
--- /dev/null
+++ b/packages/react-financial-charts/src/ChartCanvas.tsx
@@ -0,0 +1,1253 @@
+import { extent as d3Extent, max, min } from "d3-array";
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import {
+ clearCanvas,
+ functor,
+ head,
+ identity,
+ isDefined,
+ isNotDefined,
+ last,
+ noop,
+ shallowEqual,
+} from "./utils";
+
+import {
+ // @ts-ignore
+ lastVisibleItemBasedZoomAnchor,
+ mouseBasedZoomAnchor,
+ // @ts-ignore
+ rightDomainBasedZoomAnchor,
+} from "./utils/zoomBehavior";
+
+import { getChartConfigWithUpdatedYScales, getCurrentCharts, getCurrentItem, getNewChartConfig } from "./utils/ChartDataUtil";
+
+import { EventCapture } from "./EventCapture";
+
+import CanvasContainer from "./CanvasContainer";
+import evaluator from "./scale/evaluator";
+
+const CANDIDATES_FOR_RESET = [
+ "seriesName",
+];
+
+function shouldResetChart(thisProps, nextProps) {
+ return !CANDIDATES_FOR_RESET.every((key) => {
+ const result = shallowEqual(thisProps[key], nextProps[key]);
+ // console.log(key, result);
+ return result;
+ });
+}
+
+function getCursorStyle() {
+ const tooltipStyle = `
+ .react-stockcharts-grabbing-cursor {
+ pointer-events: all;
+ cursor: -moz-grabbing;
+ cursor: -webkit-grabbing;
+ cursor: grabbing;
+ }
+ .react-stockcharts-crosshair-cursor {
+ pointer-events: all;
+ cursor: crosshair;
+ }
+ .react-stockcharts-tooltip-hover {
+ pointer-events: all;
+ cursor: pointer;
+ }
+ .react-stockcharts-avoid-interaction {
+ pointer-events: none;
+ }
+ .react-stockcharts-enable-interaction {
+ pointer-events: all;
+ }
+ .react-stockcharts-tooltip {
+ pointer-events: all;
+ cursor: pointer;
+ }
+ .react-stockcharts-default-cursor {
+ cursor: default;
+ }
+ .react-stockcharts-move-cursor {
+ cursor: move;
+ }
+ .react-stockcharts-pointer-cursor {
+ cursor: pointer;
+ }
+ .react-stockcharts-ns-resize-cursor {
+ cursor: ns-resize;
+ }
+ .react-stockcharts-ew-resize-cursor {
+ cursor: ew-resize;
+ }`;
+ return ();
+}
+
+function getDimensions(props) {
+ return {
+ height: props.height - props.margin.top - props.margin.bottom,
+ width: props.width - props.margin.left - props.margin.right,
+ };
+}
+
+function getXScaleDirection(flipXScale) {
+ return flipXScale ? -1 : 1;
+}
+
+function calculateFullData(props) {
+ const { data: fullData, plotFull, xScale, clamp, pointsPerPxThreshold, flipXScale } = props;
+ const { xAccessor, displayXAccessor, minPointsPerPxThreshold } = props;
+
+ const useWholeData = isDefined(plotFull)
+ ? plotFull
+ : xAccessor === identity;
+
+ const { filterData } = evaluator({
+ xScale,
+ useWholeData,
+ clamp,
+ pointsPerPxThreshold,
+ minPointsPerPxThreshold,
+ flipXScale,
+ });
+
+ return {
+ xAccessor,
+ displayXAccessor: displayXAccessor || xAccessor,
+ xScale: xScale.copy(),
+ fullData,
+ filterData,
+ };
+}
+function resetChart(props, firstCalculation = false) {
+
+ const state = calculateState(props);
+ const { xAccessor, displayXAccessor, fullData } = state;
+ const { plotData: initialPlotData, xScale } = state;
+ const { postCalculator, children } = props;
+
+ const plotData = postCalculator(initialPlotData);
+
+ const dimensions = getDimensions(props);
+
+ // @ts-ignore
+ const chartConfig = getChartConfigWithUpdatedYScales(
+ getNewChartConfig(dimensions, children),
+ { plotData, xAccessor, displayXAccessor, fullData },
+ xScale.domain(),
+ );
+
+ return {
+ ...state,
+ xScale,
+ plotData,
+ chartConfig,
+ };
+}
+
+function updateChart(
+ newState,
+ initialXScale,
+ props,
+ lastItemWasVisible,
+ initialChartConfig,
+) {
+
+ const { fullData, xScale, xAccessor, displayXAccessor, filterData } = newState;
+
+ const lastItem = last(fullData);
+ const [start, end] = initialXScale.domain();
+
+ const { postCalculator, children, padding, flipXScale } = props;
+ const { maintainPointsPerPixelOnResize } = props;
+ const direction = getXScaleDirection(flipXScale);
+ const dimensions = getDimensions(props);
+
+ const updatedXScale = setXRange(xScale, dimensions, padding, direction);
+
+ // console.log("lastItemWasVisible =", lastItemWasVisible, end, xAccessor(lastItem), end >= xAccessor(lastItem));
+ let initialPlotData;
+ if (!lastItemWasVisible || end >= xAccessor(lastItem)) {
+ // resize comes here...
+ // get plotData between [start, end] and do not change the domain
+ const [rangeStart, rangeEnd] = initialXScale.range();
+ const [newRangeStart, newRangeEnd] = updatedXScale.range();
+ const newDomainExtent = ((newRangeEnd - newRangeStart) / (rangeEnd - rangeStart)) * (end - start);
+ const newStart = maintainPointsPerPixelOnResize
+ ? end - newDomainExtent
+ : start;
+
+ const lastItemX = initialXScale(xAccessor(lastItem));
+ // console.log("pointsPerPixel => ", newStart, start, end, updatedXScale(end));
+ const response = filterData(
+ fullData, [newStart, end], xAccessor, updatedXScale,
+ { fallbackStart: start, fallbackEnd: { lastItem, lastItemX } },
+ );
+ initialPlotData = response.plotData;
+ updatedXScale.domain(response.domain);
+ // console.log("HERE!!!!!", start, end);
+ } else if (lastItemWasVisible
+ && end < xAccessor(lastItem)) {
+ // this is when a new item is added and last item was visible
+ // so slide over and show the new item also
+
+ // get plotData between [xAccessor(l) - (end - start), xAccessor(l)] and DO change the domain
+ const dx = initialXScale(xAccessor(lastItem)) - initialXScale.range()[1];
+ const [newStart, newEnd] = initialXScale.range().map((x) => x + dx).map(initialXScale.invert);
+
+ const response = filterData(fullData, [newStart, newEnd], xAccessor, updatedXScale);
+ initialPlotData = response.plotData;
+ updatedXScale.domain(response.domain); // if last item was visible, then shift
+ }
+ // plotData = getDataOfLength(fullData, showingInterval, plotData.length)
+ const plotData = postCalculator(initialPlotData);
+
+ // @ts-ignore
+ const chartConfig = getChartConfigWithUpdatedYScales(
+ getNewChartConfig(dimensions, children, initialChartConfig),
+ { plotData, xAccessor, displayXAccessor, fullData },
+ updatedXScale.domain(),
+ );
+
+ return {
+ xScale: updatedXScale,
+ xAccessor,
+ chartConfig,
+ plotData,
+ fullData,
+ filterData,
+ };
+}
+
+function calculateState(props) {
+
+ const {
+ xAccessor: inputXAccesor, xExtents: xExtentsProp, data, padding, flipXScale,
+ } = props;
+
+ if (process.env.NODE_ENV !== "production" && isDefined(props.xScale.invert)) {
+ for (let i = 1; i < data.length; i++) {
+ const prev = data[i - 1];
+ const curr = data[i];
+ if (inputXAccesor(prev) > inputXAccesor(curr)) {
+ throw new Error("'data' is not sorted on 'xAccessor', send 'data' sorted in ascending order of 'xAccessor'");
+ }
+ }
+ }
+
+ const direction = getXScaleDirection(flipXScale);
+ const dimensions = getDimensions(props);
+
+ const extent = typeof xExtentsProp === "function"
+ ? xExtentsProp(data)
+ : d3Extent(xExtentsProp.map((d) => functor(d)).map((each) => each(data, inputXAccesor)));
+
+ const { xAccessor, displayXAccessor, xScale, fullData, filterData } = calculateFullData(props);
+ const updatedXScale = setXRange(xScale, dimensions, padding, direction);
+
+ const { plotData, domain } = filterData(fullData, extent, inputXAccesor, updatedXScale);
+
+ if (process.env.NODE_ENV !== "production" && plotData.length <= 1) {
+ throw new Error(`Showing ${plotData.length} datapoints, review the 'xExtents' prop of ChartCanvas`);
+ }
+ return {
+ plotData,
+ xScale: updatedXScale.domain(domain),
+ xAccessor,
+ displayXAccessor,
+ fullData,
+ filterData,
+ };
+}
+
+function setXRange(xScale, dimensions, padding, direction = 1) {
+ if (xScale.rangeRoundPoints) {
+ if (isNaN(padding)) { throw new Error("padding has to be a number for ordinal scale"); }
+ xScale.rangeRoundPoints([0, dimensions.width], padding);
+ } else if (xScale.padding) {
+ if (isNaN(padding)) { throw new Error("padding has to be a number for ordinal scale"); }
+ xScale.range([0, dimensions.width]);
+ xScale.padding(padding / 2);
+ } else {
+ const { left, right } = isNaN(padding)
+ ? padding
+ : { left: padding, right: padding };
+ if (direction > 0) {
+ xScale.range([left, dimensions.width - right]);
+ } else {
+ xScale.range([dimensions.width - right, left]);
+ }
+ }
+ return xScale;
+}
+
+function pinchCoordinates(pinch) {
+ const { touch1Pos, touch2Pos } = pinch;
+
+ return {
+ topLeft: [Math.min(touch1Pos[0], touch2Pos[0]), Math.min(touch1Pos[1], touch2Pos[1])],
+ bottomRight: [Math.max(touch1Pos[0], touch2Pos[0]), Math.max(touch1Pos[1], touch2Pos[1])],
+ };
+}
+
+function isInteractionEnabled(xScale, xAccessor, data) {
+ const interaction = !isNaN(xScale(xAccessor(head(data)))) && isDefined(xScale.invert);
+ return interaction;
+}
+
+interface ChartCanvasProps {
+ width: number;
+ height: number;
+ margin?: {
+ bottom: number;
+ left: number;
+ right: number;
+ top: number;
+ };
+ ratio: number;
+ type: "svg" | "hybrid";
+ pointsPerPxThreshold?: number;
+ minPointsPerPxThreshold?: number;
+ data: any[];
+ xAccessor?: any; // func
+ xExtents?: any[] | any; // func
+ zoomAnchor?: any; // func
+ className?: string;
+ seriesName: string;
+ zIndex?: number;
+ xScale: any; // func
+ postCalculator?: any; // func
+ flipXScale?: boolean;
+ useCrossHairStyleCursor?: boolean;
+ padding?: number | {
+ bottom: number;
+ left: number;
+ right: number;
+ top: number;
+ };
+ defaultFocus?: boolean;
+ zoomMultiplier?: number;
+ onLoadMore?: any; // func
+ displayXAccessor: any; // func
+ mouseMoveEvent?: boolean;
+ panEvent?: boolean;
+ clamp?: string | boolean | any; // func
+ zoomEvent?: boolean;
+ onSelect?: any; // func
+ maintainPointsPerPixelOnResize?: boolean;
+ disableInteraction?: boolean;
+}
+
+interface ChartCanvasState {
+ xAccessor?: any;
+ displayXAccessor?: any;
+ filterData?: any;
+ chartConfig?: any;
+ plotData?: any;
+ xScale?: any;
+}
+
+export class ChartCanvas extends React.Component {
+
+ public static defaultProps = {
+ margin: { top: 20, right: 30, bottom: 30, left: 80 },
+ type: "hybrid",
+ pointsPerPxThreshold: 2,
+ minPointsPerPxThreshold: 1 / 100,
+ className: "react-stockchart",
+ zIndex: 1,
+ xExtents: [min, max],
+ postCalculator: identity,
+ padding: 0,
+ xAccessor: identity,
+ flipXScale: false,
+ useCrossHairStyleCursor: true,
+ defaultFocus: true,
+ onLoadMore: noop,
+ onSelect: noop,
+ mouseMoveEvent: true,
+ panEvent: true,
+ zoomEvent: true,
+ zoomMultiplier: 1.1,
+ clamp: false,
+ zoomAnchor: mouseBasedZoomAnchor,
+ maintainPointsPerPixelOnResize: true,
+ disableInteraction: false,
+ };
+
+ public static childContextTypes = {
+ plotData: PropTypes.array,
+ fullData: PropTypes.array,
+ chartConfig: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
+ origin: PropTypes.arrayOf(PropTypes.number).isRequired,
+ padding: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.shape({
+ top: PropTypes.number,
+ bottom: PropTypes.number,
+ }),
+ ]),
+ yExtents: PropTypes.arrayOf(PropTypes.func),
+ yExtentsProvider: PropTypes.func,
+ yScale: PropTypes.func.isRequired,
+ mouseCoordinates: PropTypes.shape({
+ at: PropTypes.string,
+ format: PropTypes.func,
+ }),
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ }),
+ ).isRequired,
+ xScale: PropTypes.func.isRequired,
+ xAccessor: PropTypes.func.isRequired,
+ displayXAccessor: PropTypes.func.isRequired,
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ chartCanvasType: PropTypes.oneOf(["svg", "hybrid"]).isRequired,
+ margin: PropTypes.object.isRequired,
+ ratio: PropTypes.number.isRequired,
+ getCanvasContexts: PropTypes.func,
+ xAxisZoom: PropTypes.func,
+ yAxisZoom: PropTypes.func,
+ amIOnTop: PropTypes.func,
+ redraw: PropTypes.func,
+ subscribe: PropTypes.func,
+ unsubscribe: PropTypes.func,
+ setCursorClass: PropTypes.func,
+ generateSubscriptionId: PropTypes.func,
+ getMutableState: PropTypes.func,
+ };
+
+ public static ohlcv = (d) => ({ date: d.date, open: d.open, high: d.high, low: d.low, close: d.close, volume: d.volume });
+
+ private canvasContainerNode;
+ private eventCaptureNode;
+ private finalPinch?: boolean;
+ private fullData;
+ private lastSubscriptionId;
+ private mutableState;
+ private panInProgress: boolean;
+ private prevMouseXY;
+ private subscriptions;
+ private waitingForPinchZoomAnimationFrame?: boolean;
+ private waitingForPanAnimationFrame?: boolean;
+ private waitingForMouseMoveAnimationFrame?: boolean;
+
+ // tslint:disable-next-line: variable-name
+ private hackyWayToStopPanBeyondBounds__plotData;
+ // tslint:disable-next-line: variable-name
+ private hackyWayToStopPanBeyondBounds__domain;
+
+ constructor(props: ChartCanvasProps) {
+ super(props);
+
+ this.getDataInfo = this.getDataInfo.bind(this);
+ this.getCanvasContexts = this.getCanvasContexts.bind(this);
+
+ this.handleMouseMove = this.handleMouseMove.bind(this);
+ this.handleMouseEnter = this.handleMouseEnter.bind(this);
+ this.handleMouseLeave = this.handleMouseLeave.bind(this);
+ this.handleZoom = this.handleZoom.bind(this);
+ this.handlePinchZoom = this.handlePinchZoom.bind(this);
+ this.handlePinchZoomEnd = this.handlePinchZoomEnd.bind(this);
+ this.handlePan = this.handlePan.bind(this);
+ this.handlePanEnd = this.handlePanEnd.bind(this);
+ this.handleClick = this.handleClick.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handleDoubleClick = this.handleDoubleClick.bind(this);
+ this.handleContextMenu = this.handleContextMenu.bind(this);
+ this.handleDragStart = this.handleDragStart.bind(this);
+ this.handleDrag = this.handleDrag.bind(this);
+ this.handleDragEnd = this.handleDragEnd.bind(this);
+
+ this.panHelper = this.panHelper.bind(this);
+ this.pinchZoomHelper = this.pinchZoomHelper.bind(this);
+ this.xAxisZoom = this.xAxisZoom.bind(this);
+ this.yAxisZoom = this.yAxisZoom.bind(this);
+ this.resetYDomain = this.resetYDomain.bind(this);
+ this.calculateStateForDomain = this.calculateStateForDomain.bind(this);
+ this.generateSubscriptionId = this.generateSubscriptionId.bind(this);
+ this.draw = this.draw.bind(this);
+ this.redraw = this.redraw.bind(this);
+ this.getAllPanConditions = this.getAllPanConditions.bind(this);
+
+ this.subscriptions = [];
+ this.subscribe = this.subscribe.bind(this);
+ this.unsubscribe = this.unsubscribe.bind(this);
+ this.amIOnTop = this.amIOnTop.bind(this);
+ this.saveEventCaptureNode = this.saveEventCaptureNode.bind(this);
+ this.saveCanvasContainerNode = this.saveCanvasContainerNode.bind(this);
+ this.setCursorClass = this.setCursorClass.bind(this);
+ this.getMutableState = this.getMutableState.bind(this);
+
+ this.panInProgress = false;
+ this.state = {};
+ this.mutableState = {};
+ this.lastSubscriptionId = 0;
+
+ const { fullData, ...state } = resetChart(props, true);
+ this.state = state;
+ this.fullData = fullData;
+ }
+
+ public saveEventCaptureNode(node) {
+ this.eventCaptureNode = node;
+ }
+
+ public saveCanvasContainerNode(node) {
+ this.canvasContainerNode = node;
+ }
+
+ public getMutableState() {
+ return this.mutableState;
+ }
+
+ public getDataInfo() {
+ return {
+ ...this.state,
+ fullData: this.fullData,
+ };
+ }
+ public getCanvasContexts() {
+ if (this.canvasContainerNode) {
+ return this.canvasContainerNode.getCanvasContexts();
+ }
+ }
+ public generateSubscriptionId() {
+ this.lastSubscriptionId++;
+ return this.lastSubscriptionId;
+ }
+ public clearBothCanvas() {
+ const canvases = this.getCanvasContexts();
+ if (canvases && canvases.axes) {
+ clearCanvas([
+ canvases.axes,
+ // canvases.hover,
+ canvases.mouseCoord,
+ ], this.props.ratio);
+ }
+ }
+ public clearMouseCanvas() {
+ const canvases = this.getCanvasContexts();
+ if (canvases && canvases.mouseCoord) {
+ clearCanvas([
+ canvases.mouseCoord,
+ // canvases.hover,
+ ], this.props.ratio);
+ }
+ }
+ public clearThreeCanvas() {
+ const canvases = this.getCanvasContexts();
+ if (canvases && canvases.axes) {
+ clearCanvas([
+ canvases.axes,
+ // canvases.hover,
+ canvases.mouseCoord,
+ canvases.bg,
+ ], this.props.ratio);
+ }
+ }
+ public subscribe(id, rest) {
+ const { getPanConditions = functor({
+ draggable: false,
+ panEnabled: true,
+ }) } = rest;
+ this.subscriptions = this.subscriptions.concat({
+ id,
+ ...rest,
+ getPanConditions,
+ });
+ }
+ public unsubscribe(id) {
+ this.subscriptions = this.subscriptions.filter((each) => each.id !== id);
+ }
+ public getAllPanConditions() {
+ return this.subscriptions
+ .map((each) => each.getPanConditions());
+ }
+ public setCursorClass(className) {
+ if (this.eventCaptureNode != null) {
+ this.eventCaptureNode.setCursorClass(className);
+ }
+ }
+ public amIOnTop(id) {
+ const dragableComponents = this.subscriptions
+ .filter((each) => each.getPanConditions().draggable);
+
+ return dragableComponents.length > 0
+ && last(dragableComponents).id === id;
+ }
+ public handleContextMenu(mouseXY, e) {
+ const { xAccessor, chartConfig, plotData, xScale } = this.state;
+
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+
+ this.triggerEvent("contextmenu", {
+ mouseXY,
+ currentItem,
+ currentCharts,
+ }, e);
+ }
+ public calculateStateForDomain(newDomain) {
+ const {
+ xAccessor,
+ displayXAccessor,
+ xScale: initialXScale,
+ chartConfig: initialChartConfig,
+ plotData: initialPlotData,
+ } = this.state;
+
+ const { filterData } = this.state;
+ const { fullData } = this;
+ const { postCalculator } = this.props;
+
+ const { plotData: beforePlotData, domain } = filterData(
+ fullData,
+ newDomain,
+ xAccessor,
+ initialXScale,
+ {
+ currentPlotData: initialPlotData,
+ currentDomain: initialXScale.domain(),
+ },
+ );
+
+ const plotData = postCalculator(beforePlotData);
+ const updatedScale = initialXScale.copy().domain(domain);
+
+ // @ts-ignore
+ const chartConfig = getChartConfigWithUpdatedYScales(
+ initialChartConfig,
+ { plotData, xAccessor, displayXAccessor, fullData },
+ updatedScale.domain(),
+ );
+
+ return {
+ xScale: updatedScale,
+ plotData,
+ chartConfig,
+ };
+ }
+ public pinchZoomHelper(initialPinch, finalPinch) {
+ const { xScale: initialPinchXScale } = initialPinch;
+
+ const {
+ xScale: initialXScale,
+ chartConfig: initialChartConfig,
+ plotData: initialPlotData,
+ xAccessor,
+ displayXAccessor,
+ } = this.state;
+ const { filterData } = this.state;
+ const { fullData } = this;
+ const { postCalculator } = this.props;
+
+ const { topLeft: iTL, bottomRight: iBR } = pinchCoordinates(initialPinch);
+ const { topLeft: fTL, bottomRight: fBR } = pinchCoordinates(finalPinch);
+
+ const e = initialPinchXScale.range()[1];
+
+ const xDash = Math.round(-(iBR[0] * fTL[0] - iTL[0] * fBR[0]) / (iTL[0] - iBR[0]));
+ const yDash = Math.round(e + ((e - iBR[0]) * (e - fTL[0]) - (e - iTL[0]) * (e - fBR[0])) / ((e - iTL[0]) - (e - iBR[0])));
+
+ const x = Math.round(-xDash * iTL[0] / (-xDash + fTL[0]));
+ const y = Math.round(e - (yDash - e) * (e - iTL[0]) / (yDash + (e - fTL[0])));
+
+ const newDomain = [x, y].map(initialPinchXScale.invert);
+ // var domainR = initial.right + right;
+
+ const { plotData: beforePlotData, domain } = filterData(
+ fullData,
+ newDomain,
+ xAccessor,
+ initialPinchXScale,
+ {
+ currentPlotData: initialPlotData,
+ currentDomain: initialXScale.domain(),
+ },
+ );
+
+ const plotData = postCalculator(beforePlotData);
+ const updatedScale = initialXScale.copy().domain(domain);
+
+ const mouseXY = finalPinch.touch1Pos;
+
+ // @ts-ignore
+ const chartConfig = getChartConfigWithUpdatedYScales(
+ initialChartConfig,
+ { plotData, xAccessor, displayXAccessor, fullData },
+ updatedScale.domain(),
+ );
+ const currentItem = getCurrentItem(updatedScale, xAccessor, mouseXY, plotData);
+
+ return {
+ chartConfig,
+ xScale: updatedScale,
+ plotData,
+ mouseXY,
+ currentItem,
+ };
+ }
+
+ public cancelDrag() {
+ this.eventCaptureNode.cancelDrag();
+ this.triggerEvent("dragcancel");
+ }
+
+ public handlePinchZoom(initialPinch, finalPinch, e) {
+ if (!this.waitingForPinchZoomAnimationFrame) {
+ this.waitingForPinchZoomAnimationFrame = true;
+ const state = this.pinchZoomHelper(initialPinch, finalPinch);
+
+ this.triggerEvent("pinchzoom", state, e);
+
+ this.finalPinch = finalPinch;
+
+ requestAnimationFrame(() => {
+ this.clearBothCanvas();
+ this.draw({ trigger: "pinchzoom" });
+ this.waitingForPinchZoomAnimationFrame = false;
+ });
+ }
+ }
+ public handlePinchZoomEnd(initialPinch, e) {
+ const { xAccessor } = this.state;
+
+ if (this.finalPinch) {
+ const state = this.pinchZoomHelper(initialPinch, this.finalPinch);
+ const { xScale } = state;
+ this.triggerEvent("pinchzoom", state, e);
+
+ this.finalPinch = undefined;
+
+ this.clearThreeCanvas();
+
+ const { fullData } = this;
+ const firstItem = head(fullData);
+
+ const start = head(xScale.domain());
+ const end = xAccessor(firstItem);
+ const { onLoadMore } = this.props;
+
+ this.setState(state, () => {
+ if (start < end) {
+ onLoadMore(start, end);
+ }
+ });
+ }
+ }
+ public handleZoom(zoomDirection, mouseXY, e) {
+ if (this.panInProgress) {
+ return;
+ }
+ // console.log("zoomDirection ", zoomDirection, " mouseXY ", mouseXY);
+ const { xAccessor, xScale: initialXScale, plotData: initialPlotData } = this.state;
+ const {
+ zoomMultiplier = ChartCanvas.defaultProps.zoomMultiplier,
+ zoomAnchor,
+ } = this.props;
+ const { fullData } = this;
+ const item = zoomAnchor({
+ xScale: initialXScale,
+ xAccessor,
+ mouseXY,
+ plotData: initialPlotData,
+ fullData,
+ });
+
+ const cx = initialXScale(item);
+ const c = zoomDirection > 0 ? 1 * zoomMultiplier : 1 / zoomMultiplier;
+ const newDomain = initialXScale.range().map((x) => cx + (x - cx) * c).map(initialXScale.invert);
+
+ const { xScale, plotData, chartConfig } = this.calculateStateForDomain(newDomain);
+
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+
+ this.clearThreeCanvas();
+
+ const firstItem = head(fullData);
+
+ const start = head(xScale.domain());
+ const end = xAccessor(firstItem);
+ const { onLoadMore } = this.props;
+
+ this.mutableState = {
+ mouseXY,
+ currentItem,
+ currentCharts,
+ };
+
+ this.triggerEvent("zoom", {
+ xScale,
+ plotData,
+ chartConfig,
+ mouseXY,
+ currentCharts,
+ currentItem,
+ show: true,
+ }, e);
+
+ this.setState({
+ xScale,
+ plotData,
+ chartConfig,
+ }, () => {
+ if (start < end) {
+ onLoadMore(start, end);
+ }
+ });
+ }
+ public xAxisZoom(newDomain) {
+ const { xScale, plotData, chartConfig } = this.calculateStateForDomain(newDomain);
+ this.clearThreeCanvas();
+
+ const { xAccessor } = this.state;
+ const { fullData } = this;
+ const firstItem = head(fullData);
+ const start = head(xScale.domain());
+ const end = xAccessor(firstItem);
+ const { onLoadMore } = this.props;
+
+ this.setState({
+ xScale,
+ plotData,
+ chartConfig,
+ }, () => {
+ if (start < end) { onLoadMore(start, end); }
+ });
+ }
+ public yAxisZoom(chartId, newDomain) {
+ this.clearThreeCanvas();
+ const { chartConfig: initialChartConfig } = this.state;
+ const chartConfig = initialChartConfig
+ .map((each) => {
+ if (each.id === chartId) {
+ const { yScale } = each;
+ return {
+ ...each,
+ yScale: yScale.copy().domain(newDomain),
+ yPanEnabled: true,
+ };
+ } else {
+ return each;
+ }
+ });
+
+ this.setState({
+ chartConfig,
+ });
+ }
+
+ public triggerEvent(type, props?, e?) {
+
+ this.subscriptions.forEach((each) => {
+ const state = {
+ ...this.state,
+ fullData: this.fullData,
+ subscriptions: this.subscriptions,
+ };
+ each.listener(type, props, state, e);
+ });
+ }
+
+ public draw(props) {
+ this.subscriptions.forEach((each) => {
+ if (isDefined(each.draw)) {
+ each.draw(props);
+ }
+ });
+ }
+ public redraw() {
+ this.clearThreeCanvas();
+ this.draw({ force: true });
+ }
+ public panHelper(mouseXY, initialXScale, { dx, dy }, chartsToPan) {
+ const { xAccessor, displayXAccessor, chartConfig: initialChartConfig } = this.state;
+ const { filterData } = this.state;
+ const { fullData } = this;
+ const { postCalculator } = this.props;
+
+ // console.log(dx, dy);
+ if (isNotDefined(initialXScale.invert)) {
+ throw new Error("xScale provided does not have an invert() method."
+ + "You are likely using an ordinal scale. This scale does not support zoom, pan");
+ }
+
+ const newDomain = initialXScale.range().map((x) => x - dx).map(initialXScale.invert);
+
+ const { plotData: beforePlotData, domain } = filterData(
+ fullData,
+ newDomain,
+ xAccessor,
+ initialXScale,
+ {
+ currentPlotData: this.hackyWayToStopPanBeyondBounds__plotData,
+ currentDomain: this.hackyWayToStopPanBeyondBounds__domain,
+ },
+ );
+
+ const updatedScale = initialXScale.copy().domain(domain);
+ const plotData = postCalculator(beforePlotData);
+ // console.log(last(plotData));
+
+ const currentItem = getCurrentItem(updatedScale, xAccessor, mouseXY, plotData);
+ const chartConfig = getChartConfigWithUpdatedYScales(
+ initialChartConfig,
+ { plotData, xAccessor, displayXAccessor, fullData },
+ updatedScale.domain(),
+ dy,
+ chartsToPan,
+ );
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+
+ // console.log(initialXScale.domain(), newDomain, updatedScale.domain());
+ return {
+ xScale: updatedScale,
+ plotData,
+ chartConfig,
+ mouseXY,
+ currentCharts,
+ currentItem,
+ };
+ }
+ public handlePan(mousePosition, panStartXScale, dxdy, chartsToPan, e) {
+ if (!this.waitingForPanAnimationFrame) {
+ this.waitingForPanAnimationFrame = true;
+
+ this.hackyWayToStopPanBeyondBounds__plotData = this.hackyWayToStopPanBeyondBounds__plotData || this.state.plotData;
+ this.hackyWayToStopPanBeyondBounds__domain = this.hackyWayToStopPanBeyondBounds__domain || this.state.xScale.domain();
+
+ const state = this.panHelper(mousePosition, panStartXScale, dxdy, chartsToPan);
+
+ this.hackyWayToStopPanBeyondBounds__plotData = state.plotData;
+ this.hackyWayToStopPanBeyondBounds__domain = state.xScale.domain();
+
+ this.panInProgress = true;
+ // console.log(panStartXScale.domain(), state.xScale.domain());
+
+ this.triggerEvent("pan", state, e);
+
+ this.mutableState = {
+ mouseXY: state.mouseXY,
+ currentItem: state.currentItem,
+ currentCharts: state.currentCharts,
+ };
+ requestAnimationFrame(() => {
+ this.waitingForPanAnimationFrame = false;
+ this.clearBothCanvas();
+ this.draw({ trigger: "pan" });
+ });
+ }
+ }
+ public handlePanEnd(mousePosition, panStartXScale, dxdy, chartsToPan, e) {
+ const state = this.panHelper(mousePosition, panStartXScale, dxdy, chartsToPan);
+ // console.log(this.canvasDrawCallbackList.map(d => d.type));
+ this.hackyWayToStopPanBeyondBounds__plotData = null;
+ this.hackyWayToStopPanBeyondBounds__domain = null;
+
+ this.panInProgress = false;
+
+ // console.log("PANEND", panEnd++);
+ const {
+ xScale,
+ plotData,
+ chartConfig,
+ } = state;
+
+ this.triggerEvent("panend", state, e);
+
+ requestAnimationFrame(() => {
+ const { xAccessor } = this.state;
+ const { fullData } = this;
+
+ const firstItem = head(fullData);
+ const start = head(xScale.domain());
+ const end = xAccessor(firstItem);
+ // console.log(start, end, start < end ? "Load more" : "I have it");
+
+ const { onLoadMore } = this.props;
+
+ this.clearThreeCanvas();
+
+ this.setState({
+ xScale,
+ plotData,
+ chartConfig,
+ }, () => {
+ if (start < end) { onLoadMore(start, end); }
+ });
+ });
+ }
+ public handleMouseDown(mousePosition, currentCharts, e) {
+ this.triggerEvent("mousedown", this.mutableState, e);
+ }
+ public handleMouseEnter(e) {
+ this.triggerEvent("mouseenter", {
+ show: true,
+ }, e);
+ }
+ public handleMouseMove(mouseXY, inputType, e) {
+ if (!this.waitingForMouseMoveAnimationFrame) {
+ this.waitingForMouseMoveAnimationFrame = true;
+
+ const { chartConfig, plotData, xScale, xAccessor } = this.state;
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+ this.triggerEvent("mousemove", {
+ show: true,
+ mouseXY,
+ // prevMouseXY is used in interactive components
+ prevMouseXY: this.prevMouseXY,
+ currentItem,
+ currentCharts,
+ }, e);
+
+ this.prevMouseXY = mouseXY;
+ this.mutableState = {
+ mouseXY,
+ currentItem,
+ currentCharts,
+ };
+
+ requestAnimationFrame(() => {
+ this.clearMouseCanvas();
+ this.draw({ trigger: "mousemove" });
+ this.waitingForMouseMoveAnimationFrame = false;
+ });
+ }
+ }
+ public handleMouseLeave(e) {
+ this.triggerEvent("mouseleave", { show: false }, e);
+ this.clearMouseCanvas();
+ this.draw({ trigger: "mouseleave" });
+ }
+ public handleDragStart({ startPos }, e) {
+ this.triggerEvent("dragstart", { startPos }, e);
+ }
+ public handleDrag({ startPos, mouseXY }, e) {
+ const { chartConfig, plotData, xScale, xAccessor } = this.state;
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+
+ this.triggerEvent("drag", {
+ startPos,
+ mouseXY,
+ currentItem,
+ currentCharts,
+ }, e);
+
+ this.mutableState = {
+ mouseXY,
+ currentItem,
+ currentCharts,
+ };
+
+ requestAnimationFrame(() => {
+ this.clearMouseCanvas();
+ this.draw({ trigger: "drag" });
+ });
+ }
+ public handleDragEnd({ mouseXY }, e) {
+ this.triggerEvent("dragend", { mouseXY }, e);
+
+ requestAnimationFrame(() => {
+ this.clearMouseCanvas();
+ this.draw({ trigger: "dragend" });
+ });
+ }
+ public handleClick(mousePosition, e) {
+ this.triggerEvent("click", this.mutableState, e);
+
+ requestAnimationFrame(() => {
+ this.clearMouseCanvas();
+ this.draw({ trigger: "click" });
+ });
+ }
+ public handleDoubleClick(mousePosition, e) {
+ this.triggerEvent("dblclick", {}, e);
+ }
+ public getChildContext() {
+ const dimensions = getDimensions(this.props);
+ return {
+ fullData: this.fullData,
+ plotData: this.state.plotData,
+ width: dimensions.width,
+ height: dimensions.height,
+ chartConfig: this.state.chartConfig,
+ xScale: this.state.xScale,
+ xAccessor: this.state.xAccessor,
+ displayXAccessor: this.state.displayXAccessor,
+ chartCanvasType: this.props.type,
+ margin: this.props.margin,
+ ratio: this.props.ratio,
+ xAxisZoom: this.xAxisZoom,
+ yAxisZoom: this.yAxisZoom,
+ getCanvasContexts: this.getCanvasContexts,
+ redraw: this.redraw,
+ subscribe: this.subscribe,
+ unsubscribe: this.unsubscribe,
+ generateSubscriptionId: this.generateSubscriptionId,
+ getMutableState: this.getMutableState,
+ amIOnTop: this.amIOnTop,
+ setCursorClass: this.setCursorClass,
+ };
+ }
+
+ public UNSAFE_componentWillReceiveProps(nextProps) {
+ const reset = shouldResetChart(this.props, nextProps);
+
+ const interaction = isInteractionEnabled(this.state.xScale, this.state.xAccessor, this.state.plotData);
+ const { chartConfig: initialChartConfig } = this.state;
+
+ let newState;
+ if (!interaction || reset || !shallowEqual(this.props.xExtents, nextProps.xExtents)) {
+ // do reset
+ newState = resetChart(nextProps);
+ this.mutableState = {};
+ } else {
+
+ const [start, end] = this.state.xScale.domain();
+ const prevLastItem = last(this.fullData);
+
+ const calculatedState = calculateFullData(nextProps);
+ const { xAccessor } = calculatedState;
+ const lastItemWasVisible = xAccessor(prevLastItem) <= end && xAccessor(prevLastItem) >= start;
+
+ newState = updateChart(
+ calculatedState,
+ this.state.xScale,
+ nextProps,
+ lastItemWasVisible,
+ initialChartConfig,
+ );
+ }
+
+ const { fullData, ...state } = newState;
+
+ if (!this.panInProgress) {
+ this.clearThreeCanvas();
+
+ this.setState(state);
+ }
+ this.fullData = fullData;
+ }
+
+ public resetYDomain(chartId) {
+ const { chartConfig } = this.state;
+ let changed = false;
+ const newChartConfig = chartConfig
+ .map((each) => {
+ if ((isNotDefined(chartId) || each.id === chartId)
+ && !shallowEqual(each.yScale.domain(), each.realYDomain)) {
+ changed = true;
+ return {
+ ...each,
+ yScale: each.yScale.domain(each.realYDomain),
+ yPanEnabled: false,
+ };
+ }
+ return each;
+ });
+
+ if (changed) {
+ this.clearThreeCanvas();
+ this.setState({
+ chartConfig: newChartConfig,
+ });
+ }
+ }
+
+ public shouldComponentUpdate() {
+ return !this.panInProgress;
+ }
+
+ public render() {
+
+ const {
+ type,
+ height,
+ width,
+ margin = ChartCanvas.defaultProps.margin,
+ className,
+ zIndex = ChartCanvas.defaultProps.zIndex,
+ defaultFocus, ratio, mouseMoveEvent, panEvent, zoomEvent } = this.props;
+ const { useCrossHairStyleCursor, onSelect } = this.props;
+
+ const { plotData, xScale, xAccessor, chartConfig } = this.state;
+ const dimensions = getDimensions(this.props);
+
+ const interaction = isInteractionEnabled(xScale, xAccessor, plotData);
+
+ const cursorStyle = useCrossHairStyleCursor && interaction;
+ const cursor = getCursorStyle();
+ return (
+
+
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/EventCapture.tsx b/packages/react-financial-charts/src/EventCapture.tsx
new file mode 100644
index 000000000..d196e60bd
--- /dev/null
+++ b/packages/react-financial-charts/src/EventCapture.tsx
@@ -0,0 +1,644 @@
+import { event as d3Event, mouse, select, touches } from "d3-selection";
+import * as React from "react";
+
+import {
+ d3Window, getTouchProps, isDefined, MOUSEENTER,
+ MOUSELEAVE,
+ MOUSEMOVE, mousePosition,
+ MOUSEUP, noop,
+ TOUCHEND, TOUCHMOVE,
+ touchPosition,
+} from "./utils";
+import { getCurrentCharts } from "./utils/ChartDataUtil";
+
+interface EventCaptureProps {
+ mouseMove: boolean;
+ zoom: boolean;
+ pan: boolean;
+ panSpeedMultiplier: number;
+ focus: boolean;
+ useCrossHairStyleCursor?: boolean;
+ width: number;
+ height: number;
+ chartConfig: Array<{ origin: number[], height: number }>;
+ xAccessor: any; // func
+ xScale: any; // func
+ disableInteraction: boolean;
+ getAllPanConditions: () => Array<{ panEnabled: boolean, draggable: boolean }>;
+ onMouseMove?: (touchXY: number[], eventType: string, event: React.TouchEvent) => void;
+ onMouseEnter?: (event: any) => void;
+ onMouseLeave?: (event: React.MouseEvent) => void;
+ onZoom?: (zoomDir: 1 | -1, mouseXY: number[], event: React.WheelEvent) => void;
+ onPinchZoom?: any; // func
+ onPinchZoomEnd: any; // func
+ onPan?: any; // func
+ onPanEnd?: any; // func
+ onDragStart?: (details: { startPos: number[] }, event: React.MouseEvent) => void;
+ onDrag?: (details: { startPos: number[], mouseXY: number[] }, event: React.MouseEvent) => void;
+ onDragComplete?: (details: { mouseXY: number[] }, event: React.MouseEvent) => void;
+ onClick?: (mouseXY: number[], event: React.MouseEvent) => void;
+ onDoubleClick?: (mouseXY: number[], event: React.MouseEvent) => void;
+ onContextMenu?: (mouseXY: number[], event: React.MouseEvent) => void;
+ onMouseDown?: (mouseXY: number[], currentCharts: any, event: React.MouseEvent) => void;
+}
+
+interface EventCaptureState {
+ cursorOverrideClass?: string;
+ dragInProgress?: boolean;
+ dragStartPosition?: any;
+ panInProgress: boolean;
+ panStart?: any;
+ pinchZoomStart?: any;
+}
+
+export class EventCapture extends React.Component {
+
+ public static defaultProps = {
+ mouseMove: false,
+ zoom: false,
+ pan: false,
+ panSpeedMultiplier: 1,
+ focus: false,
+ onDragComplete: noop,
+ disableInteraction: false,
+ };
+
+ private clicked?: boolean;
+ private dx: number = 0;
+ private dy: number = 0;
+ private dragHappened?: boolean;
+ private focus?: boolean;
+ private lastNewPos?;
+ private mouseInside: boolean;
+ private mouseInteraction: boolean;
+ private node;
+ private panEndTimeout?;
+ private panHappened?: boolean;
+
+ constructor(props: EventCaptureProps) {
+ super(props);
+
+ this.handleEnter = this.handleEnter.bind(this);
+ this.handleLeave = this.handleLeave.bind(this);
+ this.handleWheel = this.handleWheel.bind(this);
+ this.handleMouseMove = this.handleMouseMove.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handlePanEnd = this.handlePanEnd.bind(this);
+ this.handlePan = this.handlePan.bind(this);
+ this.handleTouchStart = this.handleTouchStart.bind(this);
+ this.handleTouchMove = this.handleTouchMove.bind(this);
+ this.handlePinchZoom = this.handlePinchZoom.bind(this);
+ this.handlePinchZoomEnd = this.handlePinchZoomEnd.bind(this);
+ this.handleClick = this.handleClick.bind(this);
+ this.handleRightClick = this.handleRightClick.bind(this);
+ this.handleDrag = this.handleDrag.bind(this);
+ this.handleDragEnd = this.handleDragEnd.bind(this);
+ this.shouldPan = this.shouldPan.bind(this);
+ this.canPan = this.canPan.bind(this);
+ this.setCursorClass = this.setCursorClass.bind(this);
+ this.saveNode = this.saveNode.bind(this);
+ this.mouseInside = false;
+ this.mouseInteraction = true;
+ this.focus = props.focus;
+ this.state = {
+ panInProgress: false,
+ };
+ }
+
+ public saveNode(node) {
+ this.node = node;
+ }
+
+ public componentDidMount() {
+ if (this.node) {
+ select(this.node)
+ .on(MOUSEENTER, this.handleEnter)
+ .on(MOUSELEAVE, this.handleLeave);
+ }
+ }
+
+ public componentDidUpdate() {
+ this.componentDidMount();
+ }
+
+ public componentWillUnmount() {
+ if (this.node) {
+ select(this.node)
+ .on(MOUSEENTER, null)
+ .on(MOUSELEAVE, null);
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, null);
+ }
+ }
+
+ public handleEnter() {
+ const { onMouseEnter } = this.props;
+ if (onMouseEnter === undefined) {
+ return;
+ }
+
+ const e = d3Event;
+ this.mouseInside = true;
+ if (!this.state.panInProgress
+ && !this.state.dragInProgress) {
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.handleMouseMove);
+ }
+ onMouseEnter(e);
+ }
+
+ public handleLeave(e: React.MouseEvent) {
+ const { onMouseLeave } = this.props;
+ if (onMouseLeave === undefined) {
+ return;
+ }
+
+ this.mouseInside = false;
+ if (!this.state.panInProgress
+ && !this.state.dragInProgress) {
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, null);
+ }
+ onMouseLeave(e);
+ }
+
+ public handleWheel(e: React.WheelEvent) {
+ const { zoom, onZoom } = this.props;
+ const { panInProgress } = this.state;
+
+ const yZoom = Math.abs(e.deltaY) > Math.abs(e.deltaX) && Math.abs(e.deltaY) > 0;
+ const mouseXY = mousePosition(e);
+ e.preventDefault();
+
+ if (zoom && this.focus && yZoom && !panInProgress) {
+ const zoomDir = e.deltaY > 0 ? 1 : -1;
+
+ if (onZoom !== undefined) {
+ onZoom(zoomDir, mouseXY, e);
+ }
+ } else if (this.focus) {
+ if (this.shouldPan()) {
+ // pan already in progress
+ const {
+ panStartXScale,
+ chartsToPan,
+ } = this.state.panStart;
+ this.lastNewPos = mouseXY;
+ this.panHappened = true;
+
+ this.dx += e.deltaX;
+ this.dy += e.deltaY;
+ const dxdy = { dx: this.dx, dy: this.dy };
+
+ this.props.onPan(mouseXY, panStartXScale, dxdy, chartsToPan, e);
+ } else {
+ const { xScale, chartConfig } = this.props;
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+
+ this.dx = 0;
+ this.dy = 0;
+ this.setState({
+ panInProgress: true,
+ panStart: {
+ panStartXScale: xScale,
+ panOrigin: mouseXY,
+ chartsToPan: currentCharts,
+ },
+ });
+ }
+ this.queuePanEnd();
+ }
+ }
+
+ public queuePanEnd() {
+ if (isDefined(this.panEndTimeout)) {
+ clearTimeout(this.panEndTimeout);
+ }
+ this.panEndTimeout = setTimeout(() => {
+ this.handlePanEnd();
+ }, 100);
+ }
+
+ public handleMouseMove() {
+ const e = d3Event;
+
+ const { onMouseMove, mouseMove } = this.props;
+
+ if (this.mouseInteraction &&
+ mouseMove &&
+ !this.state.panInProgress) {
+
+ const newPos = mouse(this.node);
+
+ if (onMouseMove !== undefined) {
+ onMouseMove(newPos, "mouse", e);
+ }
+ }
+ }
+
+ public handleClick(e: React.MouseEvent) {
+ const mouseXY = mousePosition(e);
+ const { onClick, onDoubleClick } = this.props;
+
+ if (!this.panHappened && !this.dragHappened) {
+ if (this.clicked && onDoubleClick !== undefined) {
+ onDoubleClick(mouseXY, e);
+ this.clicked = false;
+ } else if (onClick !== undefined) {
+ onClick(mouseXY, e);
+ this.clicked = true;
+ setTimeout(() => {
+ if (this.clicked) {
+ this.clicked = false;
+ }
+ }, 400);
+ }
+ }
+ }
+
+ public handleRightClick(e: React.MouseEvent) {
+ e.stopPropagation();
+ e.preventDefault();
+ const { onContextMenu, onPanEnd } = this.props;
+
+ const mouseXY = mousePosition(e, this.node.getBoundingClientRect());
+
+ if (isDefined(this.state.panStart)) {
+ const { panStartXScale, panOrigin, chartsToPan } = this.state.panStart;
+ if (this.panHappened) {
+ onPanEnd(mouseXY, panStartXScale, panOrigin, chartsToPan, e);
+ }
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, null)
+ .on(MOUSEUP, null);
+
+ this.setState({
+ panInProgress: false,
+ panStart: null,
+ });
+ }
+
+ if (onContextMenu !== undefined) {
+ onContextMenu(mouseXY, e);
+ }
+ }
+
+ public handleDrag() {
+ const e = d3Event;
+ if (this.props.onDrag) {
+ this.dragHappened = true;
+ const mouseXY = mouse(this.node);
+ this.props.onDrag({
+ startPos: this.state.dragStartPosition,
+ mouseXY,
+ }, e);
+ }
+ }
+
+ public cancelDrag() {
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.mouseInside ? this.handleMouseMove : null)
+ .on(MOUSEUP, null);
+
+ this.setState({
+ dragInProgress: false,
+ });
+ this.mouseInteraction = true;
+ }
+
+ public handleDragEnd() {
+ const e = d3Event;
+ const mouseXY = mouse(this.node);
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.mouseInside ? this.handleMouseMove : null)
+ .on(MOUSEUP, null);
+
+ if (this.dragHappened) {
+ const { onDragComplete } = this.props;
+ if (onDragComplete !== undefined) {
+ onDragComplete({ mouseXY }, e);
+ }
+ }
+
+ this.setState({
+ dragInProgress: false,
+ });
+ this.mouseInteraction = true;
+ }
+
+ public canPan() {
+ const { getAllPanConditions } = this.props;
+ const { pan: initialPanEnabled } = this.props;
+
+ const {
+ panEnabled,
+ draggable: somethingSelected,
+ } = getAllPanConditions()
+ .reduce((returnObj, a) => {
+ return {
+ draggable: returnObj.draggable || a.draggable,
+ panEnabled: returnObj.panEnabled && a.panEnabled,
+ };
+ }, {
+ draggable: false,
+ panEnabled: initialPanEnabled,
+ });
+
+ return {
+ panEnabled,
+ somethingSelected,
+ };
+ }
+
+ public handleMouseDown(e: React.MouseEvent) {
+ if (e.button !== 0) {
+ return;
+ }
+ const { xScale, chartConfig, onMouseDown } = this.props;
+
+ this.panHappened = false;
+ this.dragHappened = false;
+ this.focus = true;
+
+ if (!this.state.panInProgress
+ && this.mouseInteraction
+ ) {
+
+ const mouseXY = mousePosition(e);
+ const currentCharts = getCurrentCharts(chartConfig, mouseXY);
+ const {
+ panEnabled, somethingSelected,
+ } = this.canPan();
+ const pan = panEnabled && !somethingSelected;
+
+ if (pan) {
+ this.setState({
+ panInProgress: pan,
+ panStart: {
+ panStartXScale: xScale,
+ panOrigin: mouseXY,
+ chartsToPan: currentCharts,
+ },
+ });
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.handlePan)
+ .on(MOUSEUP, this.handlePanEnd);
+
+ } else if (somethingSelected) {
+ this.setState({
+ panInProgress: false,
+ dragInProgress: true,
+ panStart: null,
+ dragStartPosition: mouseXY,
+ });
+
+ const { onDragStart } = this.props;
+
+ if (onDragStart !== undefined) {
+ onDragStart({ startPos: mouseXY }, e);
+ }
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.handleDrag)
+ .on(MOUSEUP, this.handleDragEnd);
+ }
+
+ if (onMouseDown !== undefined) {
+ onMouseDown(mouseXY, currentCharts, e);
+ }
+ }
+ e.preventDefault();
+ }
+
+ public shouldPan() {
+ const { pan: panEnabled, onPan } = this.props;
+ return panEnabled
+ && onPan
+ && isDefined(this.state.panStart);
+ }
+
+ public handlePan() {
+ const e = d3Event;
+
+ if (this.shouldPan()) {
+ this.panHappened = true;
+
+ const { panStartXScale, panOrigin, chartsToPan } = this.state.panStart;
+
+ const mouseXY = this.mouseInteraction
+ ? mouse(this.node)
+ : touches(this.node)[0];
+
+ this.lastNewPos = mouseXY;
+ const dx = mouseXY[0] - panOrigin[0];
+ const dy = mouseXY[1] - panOrigin[1];
+
+ this.dx = dx;
+ this.dy = dy;
+
+ this.props.onPan(
+ mouseXY, panStartXScale, { dx, dy }, chartsToPan, e,
+ );
+ }
+ }
+
+ public handlePanEnd() {
+ const e = d3Event;
+ const { pan: panEnabled, onPanEnd } = this.props;
+
+ if (isDefined(this.state.panStart)) {
+ const { panStartXScale, chartsToPan } = this.state.panStart;
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.mouseInside ? this.handleMouseMove : null)
+ .on(MOUSEUP, null)
+ .on(TOUCHMOVE, null)
+ .on(TOUCHEND, null);
+
+ if (this.panHappened
+ // && !this.contextMenuClicked
+ && panEnabled
+ && onPanEnd) {
+ const { dx, dy } = this;
+
+ delete this.dx;
+ delete this.dy;
+ onPanEnd(this.lastNewPos, panStartXScale, { dx, dy }, chartsToPan, e);
+ }
+
+ this.setState({
+ panInProgress: false,
+ panStart: null,
+ });
+ }
+ }
+
+ public handleTouchMove(e: React.TouchEvent) {
+ const { onMouseMove } = this.props;
+ if (onMouseMove === undefined) {
+ return;
+ }
+
+ const touchXY = touchPosition(getTouchProps(e.touches[0]), e);
+ onMouseMove(touchXY, "touch", e);
+ }
+
+ public handleTouchStart(e: React.TouchEvent) {
+ this.mouseInteraction = false;
+
+ const { pan: panEnabled, chartConfig, onMouseMove } = this.props;
+ const { xScale, onPanEnd } = this.props;
+
+ if (e.touches.length === 1) {
+
+ this.panHappened = false;
+ const touchXY = touchPosition(getTouchProps(e.touches[0]), e);
+ if (onMouseMove !== undefined) {
+ onMouseMove(touchXY, "touch", e);
+ }
+
+ if (panEnabled) {
+ const currentCharts = getCurrentCharts(chartConfig, touchXY);
+
+ this.setState({
+ panInProgress: true,
+ panStart: {
+ panStartXScale: xScale,
+ panOrigin: touchXY,
+ chartsToPan: currentCharts,
+ },
+ });
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(TOUCHMOVE, this.handlePan, false)
+ .on(TOUCHEND, this.handlePanEnd, false);
+
+ }
+ } else if (e.touches.length === 2) {
+ // pinch zoom begin
+ // do nothing pinch zoom is handled in handleTouchMove
+ const { panInProgress, panStart } = this.state;
+
+ if (panInProgress && panEnabled && onPanEnd) {
+ const { panStartXScale, panOrigin, chartsToPan } = panStart;
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(MOUSEMOVE, this.mouseInside ? this.handleMouseMove : null)
+ .on(MOUSEUP, null)
+ .on(TOUCHMOVE, this.handlePinchZoom, false)
+ .on(TOUCHEND, this.handlePinchZoomEnd, false);
+
+ const touch1Pos = touchPosition(getTouchProps(e.touches[0]), e);
+ const touch2Pos = touchPosition(getTouchProps(e.touches[1]), e);
+
+ if (this.panHappened
+ // && !this.contextMenuClicked
+ && panEnabled
+ && onPanEnd) {
+
+ onPanEnd(this.lastNewPos, panStartXScale, panOrigin, chartsToPan, e);
+ }
+
+ this.setState({
+ panInProgress: false,
+ pinchZoomStart: {
+ xScale,
+ touch1Pos,
+ touch2Pos,
+ range: xScale.range(),
+ chartsToPan,
+ },
+ });
+ }
+ }
+ }
+
+ public handlePinchZoom() {
+ const e = d3Event;
+ const [touch1Pos, touch2Pos] = touches(this.node);
+ const { xScale, zoom: zoomEnabled, onPinchZoom } = this.props;
+
+ // eslint-disable-next-line no-unused-vars
+ const { chartsToPan, ...initialPinch } = this.state.pinchZoomStart;
+
+ if (zoomEnabled && onPinchZoom) {
+ onPinchZoom(initialPinch, {
+ touch1Pos,
+ touch2Pos,
+ xScale,
+ }, e);
+ }
+ }
+
+ public handlePinchZoomEnd() {
+ const e = d3Event;
+
+ const win = d3Window(this.node);
+ select(win)
+ .on(TOUCHMOVE, null)
+ .on(TOUCHEND, null);
+
+ const { zoom: zoomEnabled, onPinchZoomEnd } = this.props;
+
+ // eslint-disable-next-line no-unused-vars
+ const { chartsToPan, ...initialPinch } = this.state.pinchZoomStart;
+
+ if (zoomEnabled && onPinchZoomEnd) {
+ onPinchZoomEnd(initialPinch, e);
+ }
+
+ this.setState({
+ pinchZoomStart: undefined,
+ });
+ }
+
+ public setCursorClass(cursorOverrideClass) {
+ if (cursorOverrideClass !== this.state.cursorOverrideClass) {
+ this.setState({
+ cursorOverrideClass,
+ });
+ }
+ }
+
+ public render() {
+ const { height, width, disableInteraction, useCrossHairStyleCursor } = this.props;
+ const className = this.state.cursorOverrideClass !== undefined
+ ? this.state.cursorOverrideClass
+ : !useCrossHairStyleCursor ? "" : this.state.panInProgress
+ ? "react-stockcharts-grabbing-cursor"
+ : "react-stockcharts-crosshair-cursor";
+
+ const interactionProps = disableInteraction || {
+ onWheel: this.handleWheel,
+ onMouseDown: this.handleMouseDown,
+ onClick: this.handleClick,
+ onContextMenu: this.handleRightClick,
+ onTouchStart: this.handleTouchStart,
+ onTouchMove: this.handleTouchMove,
+ };
+
+ return (
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/GenericChartComponent.tsx b/packages/react-financial-charts/src/GenericChartComponent.tsx
new file mode 100644
index 000000000..3426083d4
--- /dev/null
+++ b/packages/react-financial-charts/src/GenericChartComponent.tsx
@@ -0,0 +1,140 @@
+import * as PropTypes from "prop-types";
+
+import GenericComponent from "./GenericComponent";
+import {
+ find,
+ isDefined,
+} from "./utils";
+
+const ALWAYS_TRUE_TYPES = [
+ "drag",
+ "dragend",
+];
+
+class GenericChartComponent extends GenericComponent {
+
+ public static defaultProps = GenericComponent.defaultProps;
+
+ public static contextTypes = {
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ margin: PropTypes.object.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ getCanvasContexts: PropTypes.func,
+ chartCanvasType: PropTypes.string,
+ xScale: PropTypes.func.isRequired,
+ xAccessor: PropTypes.func.isRequired,
+ displayXAccessor: PropTypes.func.isRequired,
+ plotData: PropTypes.array.isRequired,
+ fullData: PropTypes.array.isRequired,
+ chartConfig: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ ]).isRequired,
+ morePropsDecorator: PropTypes.func,
+ generateSubscriptionId: PropTypes.func,
+ getMutableState: PropTypes.func.isRequired,
+ amIOnTop: PropTypes.func.isRequired,
+ subscribe: PropTypes.func.isRequired,
+ unsubscribe: PropTypes.func.isRequired,
+ setCursorClass: PropTypes.func.isRequired,
+ canvasOriginX: PropTypes.number,
+ canvasOriginY: PropTypes.number,
+ ratio: PropTypes.number.isRequired,
+ };
+
+ public constructor(props, context) {
+ super(props, context);
+
+ this.preCanvasDraw = this.preCanvasDraw.bind(this);
+ this.postCanvasDraw = this.postCanvasDraw.bind(this);
+ this.shouldTypeProceed = this.shouldTypeProceed.bind(this);
+ this.preEvaluate = this.preEvaluate.bind(this);
+ }
+
+ public preCanvasDraw(ctx, moreProps) {
+
+ super.preCanvasDraw(ctx, moreProps);
+
+ ctx.save();
+ const { margin, ratio } = this.context;
+ const { chartConfig } = moreProps;
+
+ const canvasOriginX = (0.5 * ratio) + chartConfig.origin[0] + margin.left;
+ const canvasOriginY = (0.5 * ratio) + chartConfig.origin[1] + margin.top;
+
+ const { chartConfig: { width, height } } = moreProps;
+ const { clip, edgeClip } = this.props;
+
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(ratio, ratio);
+ if (edgeClip) {
+ ctx.beginPath();
+ ctx.rect(-1, canvasOriginY - 10, width + margin.left + margin.right + 1, height + 20);
+ ctx.clip();
+ }
+
+ ctx.translate(canvasOriginX, canvasOriginY);
+
+ if (clip) {
+ ctx.beginPath();
+ ctx.rect(-1, -1, width + 1, height + 1);
+ ctx.clip();
+ }
+ }
+
+ public postCanvasDraw(ctx, moreProps) {
+ super.postCanvasDraw(ctx, moreProps);
+ ctx.restore();
+ }
+
+ public updateMoreProps(moreProps) {
+ super.updateMoreProps(moreProps);
+ const { chartConfig: chartConfigList } = moreProps;
+
+ if (chartConfigList && Array.isArray(chartConfigList)) {
+ const { chartId } = this.context;
+ const chartConfig = find(chartConfigList, (each) => each.id === chartId);
+ this.moreProps.chartConfig = chartConfig;
+ }
+ if (isDefined(this.moreProps.chartConfig)) {
+ const { origin: [ox, oy] } = this.moreProps.chartConfig;
+ if (isDefined(moreProps.mouseXY)) {
+ const { mouseXY: [x, y] } = moreProps;
+ this.moreProps.mouseXY = [
+ x - ox,
+ y - oy,
+ ];
+ }
+ if (isDefined(moreProps.startPos)) {
+ const { startPos: [x, y] } = moreProps;
+ this.moreProps.startPos = [
+ x - ox,
+ y - oy,
+ ];
+ }
+ }
+ }
+
+ public preEvaluate(/* type, moreProps */) {
+ ///
+ }
+
+ public shouldTypeProceed(type, moreProps) {
+ if (
+ (type === "mousemove" || type === "click")
+ && this.props.disablePan) {
+ return true;
+ }
+ if (
+ ALWAYS_TRUE_TYPES.indexOf(type) === -1
+ && isDefined(moreProps)
+ && isDefined(moreProps.currentCharts)
+ ) {
+ return (moreProps.currentCharts.indexOf(this.context.chartId) > -1);
+ }
+ return true;
+ }
+}
+
+export default GenericChartComponent;
diff --git a/packages/react-financial-charts/src/GenericComponent.tsx b/packages/react-financial-charts/src/GenericComponent.tsx
new file mode 100644
index 000000000..0c29ad4f6
--- /dev/null
+++ b/packages/react-financial-charts/src/GenericComponent.tsx
@@ -0,0 +1,505 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import {
+ functor,
+ identity,
+ isDefined,
+ isNotDefined,
+ noop,
+} from "./utils";
+
+const aliases = {
+ mouseleave: "mousemove", // to draw interactive after mouse exit
+ panend: "pan",
+ pinchzoom: "pan",
+ mousedown: "mousemove",
+ click: "mousemove",
+ contextmenu: "mousemove",
+ dblclick: "mousemove",
+ dragstart: "drag",
+ dragend: "drag",
+ dragcancel: "drag",
+};
+
+interface GenericComponentProps {
+ svgDraw: any; // func
+ canvasDraw?: any; // func
+ drawOn: any[];
+ clip?: boolean;
+ edgeClip?: boolean;
+ interactiveCursorClass?: string;
+ selected?: boolean;
+ enableDragOnHover?: boolean;
+ disablePan?: boolean;
+ canvasToDraw: any; // func
+ isHover?: any; // func
+ onClick?: any; // func
+ onClickWhenHover?: any; // func
+ onClickOutside?: any; // func
+ onPan?: any; // func
+ onPanEnd?: any; // func
+ onDragStart?: any; // func
+ onDrag?: any; // func
+ onDragComplete?: any; // func
+ onDoubleClick?: any; // func
+ onDoubleClickWhenHover?: any; // func
+ onContextMenu?: any; // func
+ onContextMenuWhenHover?: any; // func
+ onMouseMove?: any; // func
+ onMouseDown?: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ debug?: any; // func
+}
+
+interface GenericComponentState {
+ updateCount: number;
+}
+
+class GenericComponent extends React.Component {
+
+ public static defaultProps = {
+ svgDraw: functor(null),
+ draw: [],
+ canvasToDraw: (contexts) => contexts.mouseCoord,
+ clip: true,
+ edgeClip: false,
+ selected: false,
+ disablePan: false,
+ enableDragOnHover: false,
+ onClickWhenHover: noop,
+ onClickOutside: noop,
+ onDragStart: noop,
+ onMouseMove: noop,
+ onMouseDown: noop,
+ debug: noop,
+ };
+
+ public static contextTypes = {
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ margin: PropTypes.object.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ getCanvasContexts: PropTypes.func,
+ chartCanvasType: PropTypes.string,
+ xScale: PropTypes.func.isRequired,
+ xAccessor: PropTypes.func.isRequired,
+ displayXAccessor: PropTypes.func.isRequired,
+ plotData: PropTypes.array.isRequired,
+ fullData: PropTypes.array.isRequired,
+ chartConfig: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object,
+ ]).isRequired,
+ morePropsDecorator: PropTypes.func,
+ generateSubscriptionId: PropTypes.func,
+ getMutableState: PropTypes.func.isRequired,
+ amIOnTop: PropTypes.func.isRequired,
+ subscribe: PropTypes.func.isRequired,
+ unsubscribe: PropTypes.func.isRequired,
+ setCursorClass: PropTypes.func.isRequired,
+ };
+
+ public moreProps;
+
+ private dragInProgress;
+ private evaluationInProgress;
+ private iSetTheCursorClass;
+ private suscriberId;
+
+ public constructor(props, context) {
+ super(props, context);
+ this.drawOnCanvas = this.drawOnCanvas.bind(this);
+ this.getMoreProps = this.getMoreProps.bind(this);
+ this.listener = this.listener.bind(this);
+ this.draw = this.draw.bind(this);
+ this.updateMoreProps = this.updateMoreProps.bind(this);
+ this.evaluateType = this.evaluateType.bind(this);
+ this.isHover = this.isHover.bind(this);
+ this.preCanvasDraw = this.preCanvasDraw.bind(this);
+ this.postCanvasDraw = this.postCanvasDraw.bind(this);
+ this.getPanConditions = this.getPanConditions.bind(this);
+ this.shouldTypeProceed = this.shouldTypeProceed.bind(this);
+ this.preEvaluate = this.preEvaluate.bind(this);
+
+ const { generateSubscriptionId } = context;
+ this.suscriberId = generateSubscriptionId();
+
+ this.moreProps = {};
+
+ this.state = {
+ updateCount: 0,
+ };
+ }
+
+ public updateMoreProps(moreProps) {
+ Object.keys(moreProps).forEach((key) => {
+ this.moreProps[key] = moreProps[key];
+ });
+ }
+
+ public shouldTypeProceed(type, moreProps) {
+ return true;
+ }
+
+ public preEvaluate() {
+ /// empty
+ }
+
+ public listener(type, moreProps, state, e) {
+ if (isDefined(moreProps)) {
+ this.updateMoreProps(moreProps);
+ }
+ this.evaluationInProgress = true;
+ this.evaluateType(type, e);
+ this.evaluationInProgress = false;
+ }
+
+ public evaluateType(type, e) {
+ const newType = aliases[type] || type;
+ const proceed = this.props.drawOn.indexOf(newType) > -1;
+
+ if (!proceed) {
+ return;
+ }
+
+ // @ts-ignore
+ this.preEvaluate(type, this.moreProps, e);
+
+ if (!this.shouldTypeProceed(type, this.moreProps)) {
+ return;
+ }
+
+ switch (type) {
+ case "zoom":
+ case "mouseenter":
+ // DO NOT DRAW FOR THESE EVENTS
+ break;
+ case "mouseleave": {
+ this.moreProps.hovering = false;
+ const moreProps = this.getMoreProps();
+
+ if (this.props.onUnHover) {
+ this.props.onUnHover(moreProps, e);
+ }
+ break;
+ }
+ case "contextmenu": {
+ if (this.props.onContextMenu) {
+ this.props.onContextMenu(this.getMoreProps(), e);
+ }
+ if (
+ this.moreProps.hovering
+ && this.props.onContextMenuWhenHover
+ ) {
+ this.props.onContextMenuWhenHover(this.getMoreProps(), e);
+ }
+ break;
+ }
+ case "mousedown": {
+ if (this.props.onMouseDown) {
+ this.props.onMouseDown(this.getMoreProps(), e);
+ }
+ break;
+ }
+ case "click": {
+ const moreProps = this.getMoreProps();
+ if (this.moreProps.hovering) {
+ this.props.onClickWhenHover(moreProps, e);
+ } else {
+ this.props.onClickOutside(moreProps, e);
+ }
+ if (this.props.onClick) {
+ this.props.onClick(moreProps, e);
+ }
+ break;
+ }
+ case "mousemove": {
+
+ const prevHover = this.moreProps.hovering;
+ this.moreProps.hovering = this.isHover(e);
+
+ const { amIOnTop, setCursorClass } = this.context;
+
+ if (this.moreProps.hovering
+ && !this.props.selected
+ /* && !prevHover */
+ && amIOnTop(this.suscriberId)
+ && isDefined(this.props.onHover)) {
+ setCursorClass("react-stockcharts-pointer-cursor");
+ this.iSetTheCursorClass = true;
+ } else if (this.moreProps.hovering
+ && this.props.selected
+ && amIOnTop(this.suscriberId)) {
+ setCursorClass(this.props.interactiveCursorClass);
+ this.iSetTheCursorClass = true;
+ } else if (prevHover
+ && !this.moreProps.hovering
+ && this.iSetTheCursorClass) {
+ this.iSetTheCursorClass = false;
+ setCursorClass(null);
+ }
+ const moreProps = this.getMoreProps();
+
+ if (this.moreProps.hovering && !prevHover) {
+ if (this.props.onHover) {
+ this.props.onHover(moreProps, e);
+ }
+ }
+ if (prevHover && !this.moreProps.hovering) {
+ if (this.props.onUnHover) {
+ this.props.onUnHover(moreProps, e);
+ }
+ }
+
+ if (this.props.onMouseMove) {
+ this.props.onMouseMove(moreProps, e);
+ }
+ break;
+ }
+ case "dblclick": {
+ const moreProps = this.getMoreProps();
+
+ if (this.props.onDoubleClick) {
+ this.props.onDoubleClick(moreProps, e);
+ }
+ if (
+ this.moreProps.hovering
+ && this.props.onDoubleClickWhenHover
+ ) {
+ this.props.onDoubleClickWhenHover(moreProps, e);
+ }
+ break;
+ }
+ case "pan": {
+ this.moreProps.hovering = false;
+ if (this.props.onPan) {
+ this.props.onPan(this.getMoreProps(), e);
+ }
+ break;
+ }
+ case "panend": {
+ if (this.props.onPanEnd) {
+ this.props.onPanEnd(this.getMoreProps(), e);
+ }
+ break;
+ }
+ case "dragstart": {
+ if (this.getPanConditions().draggable) {
+ const { amIOnTop } = this.context;
+ if (amIOnTop(this.suscriberId)) {
+ this.dragInProgress = true;
+ this.props.onDragStart(this.getMoreProps(), e);
+ }
+ }
+ break;
+ }
+ case "drag": {
+ if (this.dragInProgress && this.props.onDrag) {
+ this.props.onDrag(this.getMoreProps(), e);
+ }
+ break;
+ }
+ case "dragend": {
+ if (this.dragInProgress && this.props.onDragComplete) {
+ this.props.onDragComplete(this.getMoreProps(), e);
+ }
+ this.dragInProgress = false;
+ break;
+ }
+ case "dragcancel": {
+ if (this.dragInProgress || this.iSetTheCursorClass) {
+ const { setCursorClass } = this.context;
+ setCursorClass(null);
+ }
+ break;
+ }
+ }
+ }
+
+ public isHover(e) {
+ return isDefined(this.props.isHover)
+ ? this.props.isHover(this.getMoreProps(), e)
+ : false;
+ }
+
+ public getPanConditions() {
+ const draggable = (
+ !!(this.props.selected && this.moreProps.hovering)
+ || (this.props.enableDragOnHover && this.moreProps.hovering)
+ );
+
+ return {
+ draggable,
+ panEnabled: !this.props.disablePan,
+ };
+ }
+
+ // @ts-ignore
+ public draw({ trigger, force } = { force: false }) {
+ const type = aliases[trigger] || trigger;
+ const proceed = this.props.drawOn.indexOf(type) > -1;
+
+ if (proceed
+ || this.props.selected /* this is to draw as soon as you select */
+ || force
+ ) {
+ const { chartCanvasType } = this.context;
+ const { canvasDraw } = this.props;
+
+ if (isNotDefined(canvasDraw) || chartCanvasType === "svg") {
+ const { updateCount } = this.state;
+ this.setState({
+ updateCount: updateCount + 1,
+ });
+ } else {
+ this.drawOnCanvas();
+ }
+ }
+ }
+
+ public UNSAFE_componentWillMount() {
+ const { subscribe, chartId } = this.context;
+ const { clip, edgeClip } = this.props;
+
+ subscribe(this.suscriberId,
+ {
+ chartId, clip, edgeClip,
+ listener: this.listener,
+ draw: this.draw,
+ getPanConditions: this.getPanConditions,
+ },
+ );
+ this.UNSAFE_componentWillReceiveProps(this.props, this.context);
+ }
+
+ public componentWillUnmount() {
+ const { unsubscribe } = this.context;
+ unsubscribe(this.suscriberId);
+ if (this.iSetTheCursorClass) {
+ const { setCursorClass } = this.context;
+ setCursorClass(null);
+ }
+ }
+
+ public componentDidMount() {
+ this.componentDidUpdate(this.props);
+ }
+
+ public componentDidUpdate(prevProps) {
+ const { chartCanvasType } = this.context;
+ const { canvasDraw, selected, interactiveCursorClass } = this.props;
+
+ if (prevProps.selected !== selected) {
+ const { setCursorClass } = this.context;
+ if (selected && this.moreProps.hovering) {
+ this.iSetTheCursorClass = true;
+ setCursorClass(interactiveCursorClass);
+ } else {
+ this.iSetTheCursorClass = false;
+ setCursorClass(null);
+ }
+ }
+ if (isDefined(canvasDraw)
+ && !this.evaluationInProgress
+ && chartCanvasType !== "svg") {
+
+ this.updateMoreProps(this.moreProps);
+ this.drawOnCanvas();
+ }
+ }
+
+ public UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
+ const { xScale, plotData, chartConfig, getMutableState } = nextContext;
+
+ this.props.debug(nextContext);
+ this.moreProps = {
+ ...this.moreProps,
+ ...getMutableState(),
+ /*
+ ^ this is so
+ mouseXY, currentCharts, currentItem are available to
+ newly created components like MouseHoverText which
+ is created right after a new interactive object is drawn
+ */
+ xScale, plotData, chartConfig,
+ };
+ }
+
+ public getMoreProps() {
+ const {
+ xScale,
+ plotData,
+ chartConfig,
+ morePropsDecorator,
+ xAccessor,
+ displayXAccessor,
+ width,
+ height,
+ } = this.context;
+
+ const { chartId, fullData } = this.context;
+
+ const moreProps = {
+ xScale, plotData, chartConfig,
+ xAccessor, displayXAccessor,
+ width, height,
+ chartId,
+ fullData,
+ ...this.moreProps,
+ };
+
+ return (morePropsDecorator || identity)(moreProps);
+ }
+
+ public preCanvasDraw(ctx, moreProps) {
+ // do nothing
+ }
+
+ public postCanvasDraw(ctx, moreProps) {
+ // empty
+ }
+
+ public drawOnCanvas() {
+ const { canvasDraw, canvasToDraw } = this.props;
+ const { getCanvasContexts } = this.context;
+
+ const moreProps = this.getMoreProps();
+
+ const ctx = canvasToDraw(getCanvasContexts());
+
+ this.preCanvasDraw(ctx, moreProps);
+ canvasDraw(ctx, moreProps);
+ this.postCanvasDraw(ctx, moreProps);
+ }
+
+ public render() {
+ const { chartCanvasType, chartId } = this.context;
+ const { canvasDraw, clip, svgDraw } = this.props;
+
+ if (isDefined(canvasDraw) && chartCanvasType !== "svg") {
+ return null;
+ }
+
+ const suffix = isDefined(chartId) ? "-" + chartId : "";
+
+ const style = clip ? { clipPath: `url(#chart-area-clip${suffix})` } : undefined;
+
+ return (
+
+ {svgDraw(this.getMoreProps())}
+
+ );
+ }
+}
+
+export default GenericComponent;
+
+export function getAxisCanvas(contexts) {
+ return contexts.axes;
+}
+
+export function getMouseCanvas(contexts) {
+ return contexts.mouseCoord;
+}
diff --git a/packages/react-financial-charts/src/ZoomButtons.tsx b/packages/react-financial-charts/src/ZoomButtons.tsx
new file mode 100644
index 000000000..f2f27d440
--- /dev/null
+++ b/packages/react-financial-charts/src/ZoomButtons.tsx
@@ -0,0 +1,217 @@
+import { interpolateNumber } from "d3-interpolate";
+import { path as d3Path } from "d3-path";
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import { last, noop } from "./utils";
+
+interface ZoomButtonsProps {
+ zoomMultiplier: number;
+ size: number[];
+ heightFromBase: number;
+ rx: number;
+ ry: number;
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ fill: string;
+ fillOpacity: number;
+ fontSize: number;
+ textDy: string;
+ textFill: string;
+ textStrokeWidth: number;
+ onReset: any; // func
+}
+
+class ZoomButtons extends React.Component {
+
+ public static defaultProps = {
+ size: [30, 24],
+ heightFromBase: 50,
+ rx: 3,
+ ry: 3,
+ stroke: "#000000",
+ strokeOpacity: 0.3,
+ strokeWidth: 1,
+ fill: "#D6D6D6",
+ fillOpacity: 0.4,
+ fontSize: 16,
+ textDy: ".3em",
+ textFill: "#000000",
+ textStrokeWidth: 2,
+ zoomMultiplier: 1.5,
+ onReset: noop,
+ };
+
+ public static contextTypes = {
+ xScale: PropTypes.func.isRequired,
+ chartConfig: PropTypes.object.isRequired,
+ plotData: PropTypes.array.isRequired,
+ xAccessor: PropTypes.func.isRequired,
+ xAxisZoom: PropTypes.func.isRequired,
+ };
+
+ private interval?: any;
+
+ public render() {
+ const { chartConfig } = this.context;
+ const { width, height } = chartConfig;
+ const { size, heightFromBase, rx, ry } = this.props;
+ const { stroke, strokeOpacity, fill, strokeWidth, fillOpacity } = this.props;
+ const { textFill, textStrokeWidth } = this.props;
+ const { onReset } = this.props;
+ const centerX = Math.round(width / 2);
+ const y = height - heightFromBase;
+
+ const [w, h] = size;
+ const hLength = 5;
+ const wLength = 6;
+
+ const textY = Math.round(y + h / 2);
+
+ const resetX = centerX;
+
+ const zoomOut = d3Path();
+ const zoomOutX = centerX - w - 2 * strokeWidth;
+ zoomOut.moveTo(zoomOutX - wLength, textY);
+ zoomOut.lineTo(zoomOutX + wLength, textY);
+ zoomOut.closePath();
+
+ const zoomIn = d3Path();
+ const zoomInX = centerX + w + 2 * strokeWidth;
+
+ zoomIn.moveTo(zoomInX - wLength, textY);
+ zoomIn.lineTo(zoomInX + wLength, textY);
+
+ zoomIn.moveTo(zoomInX, textY - hLength);
+ zoomIn.lineTo(zoomInX, textY + hLength);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ private readonly handleZoomIn = () => {
+ if (this.interval) { return; }
+ this.zoom(-1);
+ }
+
+ private readonly handleZoomOut = () => {
+ if (this.interval) { return; }
+ this.zoom(1);
+ }
+
+ private readonly zoom = (direction: number) => {
+ const { xAxisZoom, xScale, plotData, xAccessor } = this.context;
+
+ const cx = xScale(xAccessor(last(plotData)));
+
+ const { zoomMultiplier } = this.props;
+
+ const c = direction > 0 ? 1 * zoomMultiplier : 1 / zoomMultiplier;
+
+ const [start, end] = xScale.domain();
+ const [newStart, newEnd] = xScale
+ .range()
+ .map((x) => cx + (x - cx) * c)
+ .map(xScale.invert);
+
+ const left = interpolateNumber(start, newStart);
+ const right = interpolateNumber(end, newEnd);
+
+ const foo = [0.25, 0.3, 0.5, 0.6, 0.75, 1].map((i) => {
+ return [left(i), right(i)];
+ });
+
+ this.interval = setInterval(() => {
+ xAxisZoom(foo.shift());
+ if (foo.length === 0) {
+ clearInterval(this.interval);
+ delete this.interval;
+ }
+ }, 10);
+ }
+}
+
+export default ZoomButtons;
diff --git a/packages/react-financial-charts/src/algorithm/index.ts b/packages/react-financial-charts/src/algorithm/index.ts
new file mode 100644
index 000000000..83abef6ec
--- /dev/null
+++ b/packages/react-financial-charts/src/algorithm/index.ts
@@ -0,0 +1,53 @@
+// tslint:disable: only-arrow-functions space-before-function-paren
+
+import { identity, merge, slidingWindow } from "../utils";
+
+export default function () {
+
+ let windowSize = 1;
+ let accumulator = identity;
+ let mergeAs = identity;
+
+ function algorithm(data: any) {
+
+ const defaultAlgorithm = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator(accumulator);
+
+ const calculator = merge()
+ .algorithm(defaultAlgorithm)
+ // @ts-ignore
+ .merge(mergeAs);
+
+ const newData = calculator(data);
+
+ return newData;
+ }
+
+ algorithm.accumulator = function (x: any) {
+ if (!arguments.length) {
+ return accumulator;
+ }
+ accumulator = x;
+ return algorithm;
+ };
+
+ algorithm.windowSize = function (x: any) {
+ if (!arguments.length) {
+ return windowSize;
+ }
+ windowSize = x;
+ return algorithm;
+ };
+
+ algorithm.merge = function (x: any) {
+ if (!arguments.length) {
+ return mergeAs;
+ }
+ mergeAs = x;
+ return algorithm;
+ };
+
+ return algorithm;
+}
diff --git a/packages/react-financial-charts/src/annotation/Annotate.tsx b/packages/react-financial-charts/src/annotation/Annotate.tsx
new file mode 100644
index 000000000..13262dbd8
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/Annotate.tsx
@@ -0,0 +1,54 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+
+interface AnnotateProps {
+ readonly className?: string;
+ readonly with?: any; // func
+ readonly when?: any; // func
+ readonly usingProps?: object;
+}
+
+export class Annotate extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-annotate react-stockcharts-default-cursor",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps: any) => {
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const { className, usingProps, with: Annotation, when } = this.props;
+
+ const data = this.plotfilter(when, plotData);
+
+ return (
+
+ {data.map((d: any, idx) => {
+ return (
+
+ );
+ })}
+
+ );
+ }
+
+ private readonly plotfilter = (when: any, plotData: any[]) => {
+ return plotData.filter(when);
+ }
+}
diff --git a/packages/react-financial-charts/src/annotation/BarAnnotation.tsx b/packages/react-financial-charts/src/annotation/BarAnnotation.tsx
new file mode 100644
index 000000000..478f31615
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/BarAnnotation.tsx
@@ -0,0 +1,162 @@
+import * as React from "react";
+import { functor } from "../utils";
+
+interface BarAnnotationProps {
+ readonly className?: string;
+ readonly path?: any; // func
+ readonly onClick?: any; // func
+ readonly xAccessor?: any; // func
+ readonly xScale?: any; // func
+ readonly yScale?: any; // func
+ readonly datum?: object;
+ readonly stroke?: string;
+ readonly fill?: string;
+ readonly opacity?: number;
+ readonly text?: string;
+ readonly textAnchor?: string;
+ readonly fontFamily?: string;
+ readonly fontSize?: number;
+ readonly textOpacity?: number;
+ readonly textFill?: string;
+ readonly textRotate?: number;
+ readonly textXOffset?: number;
+ readonly textYOffset?: number;
+ readonly textIcon?: string;
+ readonly textIconFontSize?: number;
+ readonly textIconOpacity?: number;
+ readonly textIconFill?: string;
+ readonly textIconRotate?: number;
+ readonly textIconXOffset?: number;
+ readonly textIconYOffset?: number;
+ readonly textIconAnchor?: string;
+}
+
+export class BarAnnotation extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-bar-annotation",
+ opacity: 1,
+ fill: "#000000",
+ textAnchor: "middle",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 10,
+ textFill: "#000000",
+ textOpacity: 1,
+ textIconFill: "#000000",
+ textIconFontSize: 10,
+ x: ({ xScale, xAccessor, datum }) => xScale(xAccessor(datum)),
+ };
+
+ public render() {
+ const { className, stroke, opacity } = this.props;
+ const { xAccessor, xScale, yScale, path } = this.props;
+ const {
+ text,
+ textXOffset,
+ textYOffset,
+ textAnchor,
+ fontFamily,
+ fontSize,
+ textFill,
+ textOpacity,
+ textRotate,
+ } = this.props;
+
+ const { x, y, fill, tooltip } = helper(
+ this.props,
+ xAccessor,
+ xScale,
+ yScale,
+ );
+
+ const {
+ textIcon,
+ textIconFontSize,
+ textIconFill,
+ textIconOpacity,
+ textIconRotate,
+ textIconXOffset,
+ textIconYOffset,
+ } = this.props;
+
+ return (
+
+ {tooltip != null ? {tooltip} : null}
+ {text != null ? (
+
+ {text}
+
+ ) : null}
+ {textIcon != null ? (
+
+ {textIcon}
+
+ ) : null}
+ {path != null ? (
+
+ ) : null}
+
+ );
+ }
+
+ private readonly onClick = (e: React.MouseEvent) => {
+ const { onClick } = this.props;
+
+ if (onClick) {
+ const { xScale, yScale, datum } = this.props;
+ onClick({ xScale, yScale, datum }, e);
+ }
+ }
+}
+
+function helper(props, xAccessor, xScale, yScale) {
+ const { x, y, datum, fill, tooltip, plotData } = props;
+
+ const xFunc = functor(x);
+ const yFunc = functor(y);
+
+ const [xPos, yPos] = [
+ xFunc({ xScale, xAccessor, datum, plotData }),
+ yFunc({ yScale, datum, plotData }),
+ ];
+
+ return {
+ x: xPos,
+ y: yPos,
+ fill: functor(fill)(datum),
+ tooltip: functor(tooltip)(datum),
+ };
+}
diff --git a/packages/react-financial-charts/src/annotation/Label.tsx b/packages/react-financial-charts/src/annotation/Label.tsx
new file mode 100644
index 000000000..b920d899e
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/Label.tsx
@@ -0,0 +1,117 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import GenericComponent from "../GenericComponent";
+
+import { functor, hexToRGBA, isDefined } from "../utils";
+import { helper, LabelAnnotation } from "./LabelAnnotation";
+
+interface LabelProps {
+ readonly className?: string;
+ readonly selectCanvas?: any; // func
+ readonly text?: string | any; // func
+ readonly textAnchor?: string;
+ readonly fontFamily?: string;
+ readonly fontSize?: number;
+ readonly opacity?: number;
+ readonly rotate?: number;
+ readonly onClick?: any; // func
+ readonly xAccessor?: any; // func
+ readonly xScale?: any; // func
+ readonly yScale?: any; // func
+ readonly datum?: object;
+ readonly x?: number | any; // func
+ readonly y?: number | any; // func
+}
+
+export class Label extends React.Component {
+
+ public static defaultProps = {
+ textAnchor: "middle",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fill: "#000000",
+ opacity: 1,
+ rotate: 0,
+ x: ({ xScale, xAccessor, datum }) => xScale(xAccessor(datum)),
+ selectCanvas: (canvases) => canvases.bg,
+ };
+
+ public static contextTypes = {
+ canvasOriginX: PropTypes.number,
+ canvasOriginY: PropTypes.number,
+
+ margin: PropTypes.object.isRequired,
+ ratio: PropTypes.number.isRequired,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ drawOnCanvas2(ctx, this.props, this.context, moreProps);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { chartConfig } = moreProps;
+
+ return (
+
+ );
+ }
+}
+
+function getText(props) {
+ return functor(props.text)(props);
+}
+
+function getYScale(chartConfig) {
+ return Array.isArray(chartConfig) ? undefined : chartConfig.yScale;
+}
+
+function drawOnCanvas2(ctx, props, context, moreProps) {
+ ctx.save();
+
+ const { canvasOriginX, canvasOriginY, margin, ratio } = context;
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(ratio, ratio);
+
+ if (isDefined(canvasOriginX)) {
+ ctx.translate(canvasOriginX, canvasOriginY);
+ } else {
+ ctx.translate(margin.left + (0.5 * ratio), margin.top + (0.5 * ratio));
+ }
+
+ drawOnCanvas(ctx, props, moreProps);
+
+ ctx.restore();
+
+}
+
+function drawOnCanvas(ctx, props, moreProps) {
+ const { textAnchor, fontFamily, fontSize, opacity, rotate } = props;
+ const { xScale, chartConfig, xAccessor } = moreProps;
+
+ const { xPos, yPos, fill, text } = helper(props, xAccessor, xScale, getYScale(chartConfig));
+
+ const radians = (rotate / 180) * Math.PI;
+ ctx.save();
+ ctx.translate(xPos, yPos);
+ ctx.rotate(radians);
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor;
+
+ ctx.beginPath();
+ ctx.fillText(text, 0, 0);
+ ctx.restore();
+}
diff --git a/packages/react-financial-charts/src/annotation/LabelAnnotation.tsx b/packages/react-financial-charts/src/annotation/LabelAnnotation.tsx
new file mode 100644
index 000000000..3f6976937
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/LabelAnnotation.tsx
@@ -0,0 +1,77 @@
+import * as React from "react";
+import { functor } from "../utils";
+
+interface LabelAnnotationProps {
+ readonly className?: string;
+ readonly text?: string | any; // func
+ readonly textAnchor?: string;
+ readonly fontFamily?: string;
+ readonly fontSize?: number;
+ readonly opacity?: number;
+ readonly rotate?: number;
+ readonly onClick?: any; // func
+ readonly xAccessor?: any; // func
+ readonly xScale?: any; // func
+ readonly yScale?: any; // func
+ readonly datum?: object;
+ readonly x?: number | any; // func
+ readonly y?: number | any; // func
+}
+
+export class LabelAnnotation extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-labelannotation",
+ textAnchor: "middle",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fill: "#000000",
+ opacity: 1,
+ rotate: 0,
+ x: ({ xScale, xAccessor, datum }) => xScale(xAccessor(datum)),
+ };
+
+ public render() {
+ const { className, textAnchor, fontFamily, fontSize, opacity, rotate } = this.props;
+ const { xAccessor, xScale, yScale } = this.props;
+
+ const { xPos, yPos, fill, text, tooltip } = helper(this.props, xAccessor, xScale, yScale);
+
+ return (
+ {tooltip}
+ {text}
+ );
+ }
+
+ private readonly handleClick = (e) => {
+ const { onClick } = this.props;
+
+ if (onClick) {
+ const { xScale, yScale, datum } = this.props;
+ onClick({ xScale, yScale, datum }, e);
+ }
+ }
+}
+
+export const helper = (props, xAccessor, xScale, yScale) => {
+ const { x, y, datum, fill, text, tooltip, plotData } = props;
+
+ const xFunc = functor(x);
+ const yFunc = functor(y);
+
+ const [xPos, yPos] = [xFunc({ xScale, xAccessor, datum, plotData }), yFunc({ yScale, datum, plotData })];
+
+ return {
+ xPos,
+ yPos,
+ text: functor(text)(datum),
+ fill: functor(fill)(datum),
+ tooltip: functor(tooltip)(datum),
+ };
+};
diff --git a/packages/react-financial-charts/src/annotation/SvgPathAnnotation.tsx b/packages/react-financial-charts/src/annotation/SvgPathAnnotation.tsx
new file mode 100644
index 000000000..2d66c830f
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/SvgPathAnnotation.tsx
@@ -0,0 +1,62 @@
+import * as React from "react";
+import { functor } from "../utils";
+
+interface SvgPathAnnotationProps {
+ readonly className?: string;
+ readonly path: any; // func
+ readonly onClick?: any; // func
+ readonly xAccessor?: any; // func
+ readonly xScale?: any; // func
+ readonly yScale?: any; // func
+ readonly datum?: object;
+ readonly stroke?: string;
+ readonly fill?: string;
+ readonly opacity?: number;
+}
+
+export class SvgPathAnnotation extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-svgpathannotation",
+ opacity: 1,
+ x: ({ xScale, xAccessor, datum }) => xScale(xAccessor(datum)),
+ };
+
+ public render() {
+ const { className, stroke, opacity } = this.props;
+
+ const { xAccessor, xScale, yScale, path } = this.props;
+
+ const { x, y, fill, tooltip } = helper(this.props, xAccessor, xScale, yScale);
+
+ return (
+ {tooltip}
+
+ );
+ }
+
+ private readonly handleClick = (e: React.MouseEvent) => {
+ const { onClick } = this.props;
+
+ if (onClick) {
+ const { xScale, yScale, datum } = this.props;
+ onClick({ xScale, yScale, datum }, e);
+ }
+ }
+}
+
+function helper(props, xAccessor, xScale, yScale) {
+ const { x, y, datum, fill, tooltip, plotData } = props;
+
+ const xFunc = functor(x);
+ const yFunc = functor(y);
+
+ const [xPos, yPos] = [xFunc({ xScale, xAccessor, datum, plotData }), yFunc({ yScale, datum, plotData })];
+
+ return {
+ x: xPos,
+ y: yPos,
+ fill: functor(fill)(datum),
+ tooltip: functor(tooltip)(datum),
+ };
+}
diff --git a/packages/react-financial-charts/src/annotation/index.ts b/packages/react-financial-charts/src/annotation/index.ts
new file mode 100644
index 000000000..cb5f4ce97
--- /dev/null
+++ b/packages/react-financial-charts/src/annotation/index.ts
@@ -0,0 +1,30 @@
+export * from "./Annotate";
+export { LabelAnnotation } from "./LabelAnnotation";
+export * from "./SvgPathAnnotation";
+export * from "./Label";
+
+const halfWidth = 10;
+const bottomWidth = 3;
+const height = 20;
+
+export const buyPath = ({ x, y }: { x: number; y: number }) => {
+ return `M${x} ${y} `
+ + `L${x + halfWidth} ${y + halfWidth} `
+ + `L${x + bottomWidth} ${y + halfWidth} `
+ + `L${x + bottomWidth} ${y + height} `
+ + `L${x - bottomWidth} ${y + height} `
+ + `L${x - bottomWidth} ${y + halfWidth} `
+ + `L${x - halfWidth} ${y + halfWidth} `
+ + "Z";
+};
+
+export const sellPath = ({ x, y }: { x: number; y: number }) => {
+ return `M${x} ${y} `
+ + `L${x + halfWidth} ${y - halfWidth} `
+ + `L${x + bottomWidth} ${y - halfWidth} `
+ + `L${x + bottomWidth} ${y - height} `
+ + `L${x - bottomWidth} ${y - height} `
+ + `L${x - bottomWidth} ${y - halfWidth} `
+ + `L${x - halfWidth} ${y - halfWidth} `
+ + "Z";
+};
diff --git a/packages/react-financial-charts/src/axes/Axis.tsx b/packages/react-financial-charts/src/axes/Axis.tsx
new file mode 100644
index 000000000..bc9029cc3
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/Axis.tsx
@@ -0,0 +1,452 @@
+import { range as d3Range } from "d3-array";
+import { forceCollide, forceSimulation, forceX } from "d3-force";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { AxisZoomCapture } from "./AxisZoomCapture";
+
+import { first, getStrokeDasharray, hexToRGBA, identity, isDefined, isNotDefined, last, strokeDashTypes, zipper } from "../utils";
+
+interface AxisProps {
+ innerTickSize?: number;
+ outerTickSize?: number;
+ tickFormat?: any; // func
+ tickPadding?: number;
+ tickSize?: number;
+ ticks?: number;
+ tickLabelFill?: string;
+ tickStroke?: string;
+ tickStrokeOpacity?: number;
+ tickStrokeWidth?: number;
+ tickStrokeDasharray?: strokeDashTypes;
+ tickValues?: number[] | any; // func
+ tickInterval?: number;
+ tickIntervalFunction?: any; // func
+ showDomain?: boolean;
+ showTicks?: boolean;
+ className?: string;
+ axisZoomCallback?: any; // func
+ zoomEnabled?: boolean;
+ inverted?: boolean;
+ zoomCursorClassName?: string;
+ transform: number[];
+ range: number[];
+ getMouseDelta: any; // func
+ getScale: any; // func
+ bg: {
+ h: number;
+ x: number;
+ w: number;
+ y: number;
+ };
+ edgeClip: boolean;
+ onContextMenu?: any; // func
+ onDoubleClick?: any; // func
+}
+
+class Axis extends React.Component {
+
+ public static defaultProps = {
+ zoomEnabled: false,
+ zoomCursorClassName: "",
+ edgeClip: false,
+ };
+
+ private node;
+
+ public render() {
+ const { bg, axisZoomCallback, className, zoomCursorClassName, zoomEnabled, getScale, inverted } = this.props;
+ const { transform, getMouseDelta, edgeClip } = this.props;
+ const { onContextMenu, onDoubleClick } = this.props;
+
+ const zoomCapture = zoomEnabled
+ ?
+ : null;
+
+ return (
+
+ {zoomCapture}
+
+
+ );
+ }
+
+ private readonly saveNode = (node) => {
+ this.node = node;
+ }
+
+ private readonly getMoreProps = () => {
+ return this.node.getMoreProps();
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className } = this.props;
+ const { showDomain, showTicks, range, getScale } = this.props;
+
+ const ticks = showTicks ? axisTicksSVG(this.props, getScale(moreProps)) : null;
+ const domain = showDomain ? axisLineSVG(this.props, range) : null;
+
+ return
+ {ticks}
+ {domain}
+ ;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { showDomain, showTicks, transform, range, getScale } = this.props;
+
+ ctx.save();
+ ctx.translate(transform[0], transform[1]);
+
+ if (showDomain) { drawAxisLine(ctx, this.props, range); }
+ if (showTicks) {
+ const tickProps = tickHelper(this.props, getScale(moreProps));
+ drawTicks(ctx, tickProps);
+ }
+
+ ctx.restore();
+ }
+}
+
+function tickHelper(props, scale) {
+ const {
+ orient, innerTickSize, tickFormat, tickPadding,
+ tickLabelFill, tickStrokeWidth, tickStrokeDasharray,
+ fontSize, fontFamily, fontWeight, showTicks, flexTicks,
+ showTickLabel,
+ } = props;
+ const {
+ ticks: tickArguments, tickValues: tickValuesProp,
+ tickStroke, tickStrokeOpacity, tickInterval, tickIntervalFunction,
+ } = props;
+
+ let tickValues;
+ if (isDefined(tickValuesProp)) {
+ if (typeof tickValuesProp === "function") {
+ tickValues = tickValuesProp(scale.domain());
+ } else {
+ tickValues = tickValuesProp;
+ }
+ } else if (isDefined(tickInterval)) {
+ const [min, max] = scale.domain();
+ const baseTickValues = d3Range(min, max, (max - min) / tickInterval);
+
+ tickValues = tickIntervalFunction
+ ? tickIntervalFunction(min, max, tickInterval)
+ : baseTickValues;
+ } else if (isDefined(scale.ticks)) {
+ tickValues = scale.ticks(tickArguments, flexTicks);
+ } else {
+ tickValues = scale.domain();
+ }
+
+ const baseFormat = scale.tickFormat
+ ? scale.tickFormat(tickArguments)
+ : identity;
+
+ const format = isNotDefined(tickFormat)
+ ? baseFormat
+ : (d) => tickFormat(d) || "";
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+ const tickSpacing = Math.max(innerTickSize, 0) + tickPadding;
+
+ let ticks;
+ let dy;
+ // tslint:disable-next-line: variable-name
+ let canvas_dy;
+ let textAnchor;
+
+ if (orient === "bottom" || orient === "top") {
+ dy = sign < 0 ? "0em" : ".71em";
+ canvas_dy = sign < 0 ? 0 : (fontSize * .71);
+ textAnchor = "middle";
+
+ ticks = tickValues.map((d) => {
+ const x = Math.round(scale(d));
+ return {
+ value: d,
+ x1: x,
+ y1: 0,
+ x2: x,
+ y2: sign * innerTickSize,
+ labelX: x,
+ labelY: sign * tickSpacing,
+ };
+ });
+
+ if (showTicks && flexTicks) {
+
+ const nodes = ticks.map((d) => ({ id: d.value, value: d.value, fy: d.y2, origX: d.x1 }));
+
+ const simulation = forceSimulation(nodes)
+ .force("x", forceX((d) => d.origX).strength(1))
+ .force("collide", forceCollide(22))
+ .stop();
+
+ for (let i = 0; i < 100; ++i) { simulation.tick(); }
+
+ const zip = zipper()
+ .combine((a, b) => {
+ if (Math.abs(b.x - b.origX) > 0.01) {
+ return {
+ ...a,
+ x2: b.x,
+ labelX: b.x,
+ };
+ }
+ return a;
+ });
+
+ // @ts-ignore
+ ticks = zip(ticks, nodes);
+ }
+
+ } else {
+ ticks = tickValues.map((d) => {
+ const y = Math.round(scale(d));
+ return {
+ value: d,
+ x1: 0,
+ y1: y,
+ x2: sign * innerTickSize,
+ y2: y,
+ labelX: sign * tickSpacing,
+ labelY: y,
+ };
+ });
+
+ dy = ".32em";
+ canvas_dy = (fontSize * .32);
+ textAnchor = sign < 0 ? "end" : "start";
+ }
+
+ return {
+ ticks, scale, tickStroke,
+ tickLabelFill: (tickLabelFill || tickStroke),
+ tickStrokeOpacity,
+ tickStrokeWidth,
+ tickStrokeDasharray,
+ dy,
+ canvas_dy,
+ textAnchor,
+ fontSize,
+ fontFamily,
+ fontWeight,
+ format,
+ showTickLabel,
+ };
+}
+
+/* eslint-disable react/prop-types */
+function axisLineSVG(props, range) {
+ const { orient, outerTickSize } = props;
+ const { domainClassName, fill, stroke, strokeWidth, opacity } = props;
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+
+ let d;
+
+ if (orient === "bottom" || orient === "top") {
+ d = "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize;
+ } else {
+ d = "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize;
+ }
+
+ return (
+
+
+ );
+}
+/* eslint-enable react/prop-types */
+
+function drawAxisLine(ctx, props, range) {
+ // props = { ...AxisLine.defaultProps, ...props };
+
+ const { orient, outerTickSize, stroke, strokeWidth, opacity } = props;
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+ const xAxis = (orient === "bottom" || orient === "top");
+
+ // var range = d3_scaleRange(xAxis ? xScale : yScale);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, opacity);
+
+ ctx.beginPath();
+
+ if (xAxis) {
+ ctx.moveTo(first(range), sign * outerTickSize);
+ ctx.lineTo(first(range), 0);
+ ctx.lineTo(last(range), 0);
+ ctx.lineTo(last(range), sign * outerTickSize);
+ } else {
+ ctx.moveTo(sign * outerTickSize, first(range));
+ ctx.lineTo(0, first(range));
+ ctx.lineTo(0, last(range));
+ ctx.lineTo(sign * outerTickSize, last(range));
+ }
+ ctx.stroke();
+}
+
+interface TickProps {
+ children: string;
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+ labelX: number;
+ labelY: number;
+ dy: string;
+ tickStroke?: string;
+ tickLabelFill?: string;
+ tickStrokeWidth?: number;
+ tickStrokeOpacity?: number;
+ tickStrokeDasharray?: strokeDashTypes;
+ textAnchor?: string;
+ fontSize?: number;
+ fontFamily?: string;
+ fontWeight?: number | string;
+}
+
+function Tick(props: TickProps) {
+ const {
+ tickLabelFill,
+ tickStroke,
+ tickStrokeOpacity,
+ tickStrokeDasharray,
+ tickStrokeWidth,
+ textAnchor,
+ fontSize,
+ fontFamily,
+ fontWeight,
+ } = props;
+
+ const { x1, y1, x2, y2, labelX, labelY, dy } = props;
+
+ return (
+
+
+
+ {props.children}
+
+
+ );
+}
+
+function axisTicksSVG(props, scale) {
+ const result = tickHelper(props, scale);
+
+ const { tickLabelFill, tickStroke, tickStrokeOpacity, tickStrokeWidth, tickStrokeDasharray, textAnchor } = result;
+ const { fontSize, fontFamily, fontWeight, ticks, format } = result;
+
+ const { dy } = result;
+
+ return (
+
+ {ticks.map((tick, idx) => {
+ return (
+ {format(tick.value)}
+ );
+ })}
+
+ );
+}
+
+function drawTicks(ctx, result) {
+
+ const { tickStroke, tickStrokeOpacity, tickLabelFill } = result;
+ const { textAnchor, fontSize, fontFamily, fontWeight, ticks, showTickLabel } = result;
+
+ ctx.strokeStyle = hexToRGBA(tickStroke, tickStrokeOpacity);
+
+ ctx.fillStyle = tickStroke;
+ // ctx.textBaseline = 'middle';
+
+ ticks.forEach((tick) => {
+ drawEachTick(ctx, tick, result);
+ });
+
+ ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = tickLabelFill;
+ ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor;
+
+ if (showTickLabel) {
+ ticks.forEach((tick) => {
+ drawEachTickLabel(ctx, tick, result);
+ });
+ }
+}
+
+function drawEachTick(ctx, tick, result) {
+ const { tickStrokeWidth, tickStrokeDasharray } = result;
+
+ ctx.beginPath();
+
+ ctx.moveTo(tick.x1, tick.y1);
+ ctx.lineTo(tick.x2, tick.y2);
+ ctx.lineWidth = tickStrokeWidth;
+ ctx.setLineDash(getStrokeDasharray(tickStrokeDasharray).split(","));
+ ctx.stroke();
+}
+
+function drawEachTickLabel(ctx, tick, result) {
+ const { canvas_dy, format } = result;
+
+ ctx.beginPath();
+ ctx.fillText(format(tick.value), tick.labelX, tick.labelY + canvas_dy);
+}
+
+export default Axis;
diff --git a/packages/react-financial-charts/src/axes/AxisLine.tsx b/packages/react-financial-charts/src/axes/AxisLine.tsx
new file mode 100644
index 000000000..986f07ac2
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/AxisLine.tsx
@@ -0,0 +1,104 @@
+import * as React from "react";
+import { first, hexToRGBA, last } from "../utils";
+
+interface AxisLineProps {
+ className?: string;
+ shapeRendering?: string;
+ orient: string;
+ scale: any; // func
+ outerTickSize?: number;
+ fill?: string;
+ stroke?: string;
+ strokeWidth?: number;
+ opacity?: number;
+ range: number[];
+}
+
+/*
+function d3_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [start, stop] : [stop, start];
+}
+
+function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+}
+*/
+export class AxisLine extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-axis-line",
+ shapeRendering: "crispEdges",
+ fill: "none",
+ stroke: "#000000",
+ strokeWidth: 1,
+ opacity: 1,
+ };
+
+ public static drawOnCanvasStatic = (props, ctx/* , xScale, yScale*/) => {
+ props = { ...AxisLine.defaultProps, ...props };
+
+ const { orient, outerTickSize, stroke, strokeWidth, opacity, range } = props;
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+ const xAxis = (orient === "bottom" || orient === "top");
+
+ // var range = d3_scaleRange(xAxis ? xScale : yScale);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, opacity);
+
+ ctx.beginPath();
+
+ if (xAxis) {
+ ctx.moveTo(first(range), sign * outerTickSize);
+ ctx.lineTo(first(range), 0);
+ ctx.lineTo(last(range), 0);
+ ctx.lineTo(last(range), sign * outerTickSize);
+ } else {
+ ctx.moveTo(sign * outerTickSize, first(range));
+ ctx.lineTo(0, first(range));
+ ctx.lineTo(0, last(range));
+ ctx.lineTo(sign * outerTickSize, last(range));
+ }
+ ctx.stroke();
+ }
+
+ public render() {
+ const {
+ orient,
+ outerTickSize = 0,
+ fill,
+ stroke,
+ strokeWidth,
+ className,
+ shapeRendering,
+ opacity,
+ range,
+ } = this.props;
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+
+ // var range = d3_scaleRange(scale);
+
+ let d;
+
+ if (orient === "bottom" || orient === "top") {
+ d = "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize;
+ } else {
+ d = "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize;
+ }
+
+ return (
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/axes/AxisTicks.tsx b/packages/react-financial-charts/src/axes/AxisTicks.tsx
new file mode 100644
index 000000000..bc1eacf03
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/AxisTicks.tsx
@@ -0,0 +1,193 @@
+import * as React from "react";
+
+import { hexToRGBA, identity, isNotDefined } from "../utils";
+
+function tickTransform_svg_axisX(scale, tick) {
+ return [Math.round(scale(tick)), 0];
+}
+
+function tickTransform_svg_axisY(scale, tick) {
+ return [0, Math.round(scale(tick))];
+}
+
+interface TickProps {
+ transform: number[];
+ tickStroke?: string;
+ tickStrokeOpacity?: number;
+ textAnchor?: string;
+ fontSize?: number;
+ fontFamily?: string;
+ x?: number;
+ y?: number;
+ x2?: number;
+ y2?: number;
+ dy?: string;
+}
+
+class Tick extends React.Component {
+
+ public static drawOnCanvasStatic = (tick, ctx, result) => {
+ const { scale, tickTransform, canvas_dy, x, y, x2, y2, format } = result;
+
+ const origin = tickTransform(scale, tick);
+
+ ctx.beginPath();
+
+ ctx.moveTo(origin[0], origin[1]);
+ ctx.lineTo(origin[0] + x2, origin[1] + y2);
+ ctx.stroke();
+
+ ctx.fillText(format(tick), origin[0] + x, origin[1] + y + canvas_dy);
+ }
+
+ public render() {
+ const { transform, tickStroke, tickStrokeOpacity, textAnchor, fontSize, fontFamily } = this.props;
+ const { x, y, x2, y2, dy } = this.props;
+ return (
+
+
+
+ {this.props.children}
+
+
+ );
+ }
+}
+
+interface AxisTicksProps {
+ orient: "top" | "bottom" | "left" | "right";
+ innerTickSize?: number;
+ tickFormat?: any; // func
+ tickPadding?: number;
+ ticks?: number[];
+ tickValues?: number[];
+ scale: any; // func
+ tickStroke?: string;
+ tickStrokeOpacity?: number;
+}
+
+// tslint:disable-next-line: max-classes-per-file
+export class AxisTicks extends React.Component {
+
+ public static defaultProps = {
+ innerTickSize: 5,
+ tickPadding: 6,
+ ticks: [10],
+ tickStroke: "#000",
+ tickStrokeOpacity: 1,
+ };
+
+ public static drawOnCanvasStatic = (props, ctx, xScale, yScale) => {
+ props = { ...AxisTicks.defaultProps, ...props };
+
+ const { orient } = props;
+ const xAxis = (orient === "bottom" || orient === "top");
+
+ const result = AxisTicks.helper(props, xAxis ? xScale : yScale);
+
+ const { tickStroke, tickStrokeOpacity, textAnchor, fontSize, fontFamily } = result;
+
+ ctx.strokeStyle = hexToRGBA(tickStroke, tickStrokeOpacity);
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = tickStroke;
+ ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor;
+
+ result.ticks.forEach((tick) => {
+ Tick.drawOnCanvasStatic(tick, ctx, result);
+ });
+ }
+
+ public static helper = (props, scale) => {
+ const { orient, innerTickSize, tickFormat, tickPadding, fontSize, fontFamily } = props;
+ const { ticks: tickArguments, tickValues, tickStroke, tickStrokeOpacity } = props;
+
+ const ticks = isNotDefined(tickValues)
+ ? (scale.ticks
+ ? scale.ticks(...tickArguments)
+ : scale.domain())
+ : tickValues;
+
+ const baseFormat = scale.tickFormat
+ ? scale.tickFormat(...tickArguments)
+ : identity;
+
+ const format = isNotDefined(tickFormat)
+ ? baseFormat
+ : (d) => baseFormat(d) ? tickFormat(d) : "";
+
+ const sign = orient === "top" || orient === "left" ? -1 : 1;
+ const tickSpacing = Math.max(innerTickSize, 0) + tickPadding;
+
+ let tickTransform;
+ let x;
+ let y;
+ let x2;
+ let y2;
+ let dy;
+ // tslint:disable-next-line: variable-name
+ let canvas_dy;
+ let textAnchor;
+
+ if (orient === "bottom" || orient === "top") {
+ tickTransform = tickTransform_svg_axisX;
+ x2 = 0;
+ y2 = sign * innerTickSize;
+ x = 0;
+ y = sign * tickSpacing;
+ dy = sign < 0 ? "0em" : ".71em";
+ canvas_dy = sign < 0 ? 0 : (fontSize * .71);
+ textAnchor = "middle";
+ } else {
+ tickTransform = tickTransform_svg_axisY;
+ x2 = sign * innerTickSize;
+ y2 = 0;
+ x = sign * tickSpacing;
+ y = 0;
+ dy = ".32em";
+ canvas_dy = (fontSize * .32);
+ textAnchor = sign < 0 ? "end" : "start";
+ }
+ return {
+ ticks,
+ scale,
+ tickTransform,
+ tickStroke, tickStrokeOpacity, dy, canvas_dy, x, y, x2, y2, textAnchor, fontSize, fontFamily, format,
+ };
+ }
+
+ public render() {
+ const result = AxisTicks.helper(this.props, this.props.scale);
+ const {
+ ticks,
+ scale,
+ tickTransform,
+ tickStroke,
+ tickStrokeOpacity,
+ dy,
+ x,
+ y,
+ x2,
+ y2,
+ textAnchor, fontSize, fontFamily, format } = result;
+
+ return (
+
+ {ticks.map((tick, idx) => {
+ return (
+ {format(tick)}
+ );
+ })}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/axes/AxisZoomCapture.tsx b/packages/react-financial-charts/src/axes/AxisZoomCapture.tsx
new file mode 100644
index 000000000..ce18f1985
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/AxisZoomCapture.tsx
@@ -0,0 +1,219 @@
+import { mean } from "d3-array";
+import { event as d3Event, mouse, select, touches } from "d3-selection";
+import * as React from "react";
+
+import {
+ d3Window,
+ first,
+ getTouchProps,
+ isDefined,
+ last,
+ MOUSEMOVE,
+ mousePosition,
+ MOUSEUP,
+ noop,
+ sign,
+ TOUCHEND,
+ TOUCHMOVE,
+ touchPosition,
+} from "../utils";
+
+interface AxisZoomCaptureProps {
+ innerTickSize?: number;
+ outerTickSize?: number;
+ tickFormat?: any; // func
+ tickPadding?: number;
+ tickSize?: number;
+ ticks?: number;
+ tickValues?: number[];
+ showDomain?: boolean;
+ showTicks?: boolean;
+ className?: string;
+ axisZoomCallback?: any; // func
+ inverted?: boolean;
+ bg: {
+ h: number;
+ x: number;
+ w: number;
+ y: number;
+ };
+ zoomCursorClassName?: string;
+ getMoreProps: any; // func
+ getScale: any; // func
+ getMouseDelta: any; // func
+ onDoubleClick: any; // func
+ onContextMenu: any; // func
+}
+
+interface AxisZoomCaptureState {
+ startPosition: any | null;
+}
+
+export class AxisZoomCapture extends React.Component {
+
+ public static defaultProps = {
+ onDoubleClick: noop,
+ onContextMenu: noop,
+ inverted: true,
+ };
+
+ private node;
+ private mouseInteraction;
+ private clicked;
+ private dragHappened;
+
+ public constructor(props) {
+ super(props);
+ this.state = {
+ startPosition: null,
+ };
+ }
+
+ public render() {
+ const { bg, className, zoomCursorClassName } = this.props;
+
+ const cursor = isDefined(this.state.startPosition)
+ ? zoomCursorClassName
+ : "react-stockcharts-default-cursor";
+
+ return (
+
+ );
+ }
+
+ private readonly handleDragEnd = () => {
+
+ if (!this.dragHappened) {
+ if (this.clicked) {
+ const e = d3Event;
+ const mouseXY = this.mouseInteraction
+ ? mouse(this.node)
+ : touches(this.node)[0];
+ const { onDoubleClick } = this.props;
+
+ onDoubleClick(mouseXY, e);
+ } else {
+ this.clicked = true;
+ setTimeout(() => {
+ this.clicked = false;
+ }, 300);
+ }
+ }
+
+ select(d3Window(this.node))
+ .on(MOUSEMOVE, null)
+ .on(MOUSEUP, null)
+ .on(TOUCHMOVE, null)
+ .on(TOUCHEND, null);
+
+ this.setState({
+ startPosition: null,
+ });
+ }
+
+ private readonly handleDrag = () => {
+ const { startPosition } = this.state;
+ const { getMouseDelta, inverted } = this.props;
+
+ this.dragHappened = true;
+ if (isDefined(startPosition)) {
+ const { startScale } = startPosition;
+ const { startXY } = startPosition;
+
+ const mouseXY = this.mouseInteraction
+ ? mouse(this.node)
+ : touches(this.node)[0];
+
+ const diff = getMouseDelta(startXY, mouseXY);
+
+ const center = mean(startScale.range());
+
+ const tempRange = startScale.range()
+ .map((d) => inverted ? d - sign(d - center) * diff : d + sign(d - center) * diff);
+
+ const newDomain = tempRange.map(startScale.invert);
+
+ if (sign(last(startScale.range()) - first(startScale.range())) === sign(last(tempRange) - first(tempRange))) {
+
+ const { axisZoomCallback } = this.props;
+ axisZoomCallback(newDomain);
+ }
+ }
+ }
+
+ private readonly handleDragStartTouch = (e) => {
+ this.mouseInteraction = false;
+
+ const { getScale, getMoreProps } = this.props;
+ const startScale = getScale(getMoreProps());
+ this.dragHappened = false;
+
+ if (e.touches.length === 1 && startScale.invert) {
+ select(d3Window(this.node))
+ .on(TOUCHMOVE, this.handleDrag)
+ .on(TOUCHEND, this.handleDragEnd);
+
+ const startXY = touchPosition(getTouchProps(e.touches[0]), e);
+
+ this.setState({
+ startPosition: {
+ startXY,
+ startScale,
+ },
+ });
+ }
+ }
+
+ private readonly handleDragStartMouse = (e) => {
+ this.mouseInteraction = true;
+
+ const { getScale, getMoreProps } = this.props;
+ const startScale = getScale(getMoreProps());
+ this.dragHappened = false;
+
+ if (startScale.invert) {
+ select(d3Window(this.node))
+ .on(MOUSEMOVE, this.handleDrag, false)
+ .on(MOUSEUP, this.handleDragEnd, false);
+
+ const startXY = mousePosition(e);
+
+ this.setState({
+ startPosition: {
+ startXY,
+ startScale,
+ },
+ });
+ }
+ e.preventDefault();
+ }
+
+ private readonly handleRightClick = (e) => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ const { onContextMenu } = this.props;
+
+ const mouseXY = mousePosition(e, this.node.getBoundingClientRect());
+
+ select(d3Window(this.node))
+ .on(MOUSEMOVE, null)
+ .on(MOUSEUP, null);
+ this.setState({
+ startPosition: null,
+ });
+
+ onContextMenu(mouseXY, e);
+ }
+
+ private readonly saveNode = (node) => {
+ this.node = node;
+ }
+}
diff --git a/packages/react-financial-charts/src/axes/LICENSE b/packages/react-financial-charts/src/axes/LICENSE
new file mode 100644
index 000000000..68b028aa2
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/LICENSE
@@ -0,0 +1,28 @@
+Implementation of AxisTicks and AxisLine
+derived from d3's axis.js
+Copyright (c) 2010-2015, Michael Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* The name Michael Bostock may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/react-financial-charts/src/axes/XAxis.tsx b/packages/react-financial-charts/src/axes/XAxis.tsx
new file mode 100644
index 000000000..bcfa7d6ae
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/XAxis.tsx
@@ -0,0 +1,127 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import Axis from "./Axis";
+
+interface XAxisProps {
+ readonly axisAt: number | "top" | "bottom" | "middle";
+ readonly orient: "top" | "bottom";
+ readonly innerTickSize?: number;
+ readonly outerTickSize?: number;
+ readonly tickFormat?: any; // func
+ readonly tickPadding?: number;
+ readonly tickSize?: number;
+ readonly ticks?: number;
+ readonly tickValues?: number[];
+ readonly showTicks?: boolean;
+ readonly className?: string;
+ readonly zoomEnabled?: boolean;
+ readonly onContextMenu?: any; // func
+ readonly onDoubleClick?: any; // func
+ readonly getMouseDelta?: (startXY: number[], mouseXY: number[]) => number;
+ readonly xZoomHeight?: number;
+}
+
+export class XAxis extends React.Component {
+
+ public static defaultProps = {
+ showTicks: true,
+ showTickLabel: true,
+ showDomain: true,
+ className: "react-stockcharts-x-axis",
+ ticks: 10,
+ outerTickSize: 0,
+ fill: "none",
+ stroke: "#000000",
+ strokeWidth: 1,
+ opacity: 1,
+ domainClassName: "react-stockcharts-axis-domain",
+ innerTickSize: 5,
+ tickPadding: 6,
+ tickStroke: "#000000",
+ tickStrokeOpacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fontWeight: 400,
+ xZoomHeight: 25,
+ zoomEnabled: true,
+ getMouseDelta: (startXY, mouseXY) => startXY[0] - mouseXY[0],
+ };
+
+ public static contextTypes = {
+ chartConfig: PropTypes.object.isRequired,
+ xAxisZoom: PropTypes.func.isRequired,
+ };
+
+ public render() {
+ const {
+ getMouseDelta = XAxis.defaultProps.getMouseDelta,
+ zoomEnabled,
+ ...rest
+ } = this.props;
+
+ const { ...moreProps } = helper(this.props, this.context);
+
+ return (
+
+ );
+ }
+
+ private readonly axisZoomCallback = (newXDomain) => {
+ const { xAxisZoom } = this.context;
+
+ xAxisZoom(newXDomain);
+ }
+}
+
+function helper(props: XAxisProps, context) {
+ const {
+ axisAt,
+ xZoomHeight = XAxis.defaultProps.xZoomHeight,
+ orient,
+ } = props;
+ const { chartConfig: { width, height } } = context;
+
+ let axisLocation;
+ const x = 0;
+ const w = width;
+ const h = xZoomHeight;
+
+ if (axisAt === "top") {
+ axisLocation = 0;
+ } else if (axisAt === "bottom") {
+ axisLocation = height;
+ } else if (axisAt === "middle") {
+ axisLocation = (height) / 2;
+ } else {
+ axisLocation = axisAt;
+ }
+
+ const y = (orient === "top") ? -xZoomHeight : 0;
+
+ return {
+ transform: [0, axisLocation],
+ range: [0, width],
+ getScale: getXScale,
+ bg: { x, y, h, w },
+ };
+}
+
+function getXScale(moreProps) {
+ const { xScale: scale, width } = moreProps;
+
+ if (scale.invert) {
+ const trueRange = [0, width];
+ const trueDomain = trueRange.map(scale.invert);
+ return scale.copy()
+ .domain(trueDomain)
+ .range(trueRange);
+ }
+
+ return scale;
+}
diff --git a/packages/react-financial-charts/src/axes/YAxis.tsx b/packages/react-financial-charts/src/axes/YAxis.tsx
new file mode 100644
index 000000000..a6f72f0a0
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/YAxis.tsx
@@ -0,0 +1,127 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import Axis from "./Axis";
+
+interface YAxisProps {
+ readonly axisAt: number | "left" | "right" | "middle";
+ readonly orient: "left" | "right";
+ readonly innerTickSize?: number;
+ readonly outerTickSize?: number;
+ readonly tickFormat?: any; // func
+ readonly tickPadding?: number;
+ readonly tickSize?: number;
+ readonly ticks?: number;
+ readonly yZoomWidth?: number;
+ readonly tickValues?: number[];
+ readonly showTicks?: boolean;
+ readonly className?: string;
+ readonly zoomEnabled?: boolean;
+ readonly onContextMenu?: any; // func
+ readonly onDoubleClick?: any; // func
+ readonly getMouseDelta?: (startXY: number[], mouseXY: number[]) => number;
+}
+
+export class YAxis extends React.Component {
+
+ public static defaultProps = {
+ showTicks: true,
+ showTickLabel: true,
+ showDomain: true,
+ className: "react-stockcharts-y-axis",
+ ticks: 10,
+ outerTickSize: 0,
+ domainClassName: "react-stockcharts-axis-domain",
+ fill: "none",
+ stroke: "#000000",
+ strokeWidth: 1,
+ opacity: 1,
+ innerTickSize: 5,
+ tickPadding: 6,
+ tickStroke: "#000000",
+ tickStrokeOpacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fontWeight: 400,
+ yZoomWidth: 40,
+ zoomEnabled: true,
+ getMouseDelta: (startXY, mouseXY) => startXY[1] - mouseXY[1],
+ };
+
+ public static contextTypes = {
+ yAxisZoom: PropTypes.func.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
+ chartConfig: PropTypes.object.isRequired,
+ };
+
+ public render() {
+
+ const {
+ getMouseDelta = YAxis.defaultProps.getMouseDelta,
+ ...rest
+ } = this.props;
+
+ const { zoomEnabled, ...moreProps } = helper(this.props, this.context);
+
+ return (
+
+ );
+ }
+
+ private readonly axisZoomCallback = (newYDomain) => {
+ const { chartId, yAxisZoom } = this.context;
+ yAxisZoom(chartId, newYDomain);
+ }
+}
+
+function helper(props: YAxisProps, context) {
+ const {
+ axisAt,
+ yZoomWidth = YAxis.defaultProps.yZoomWidth,
+ orient,
+ } = props;
+ const { chartConfig: { width, height } } = context;
+
+ let axisLocation;
+ const y = 0;
+ const w = yZoomWidth;
+ const h = height;
+
+ if (axisAt === "left") {
+ axisLocation = 0;
+ } else if (axisAt === "right") {
+ axisLocation = width;
+ } else if (axisAt === "middle") {
+ axisLocation = (width) / 2;
+ } else {
+ axisLocation = axisAt;
+ }
+
+ const x = (orient === "left") ? -yZoomWidth : 0;
+
+ return {
+ transform: [axisLocation, 0],
+ range: [0, height],
+ getScale: getYScale,
+ bg: { x, y, h, w },
+ zoomEnabled: context.chartConfig.yPan,
+ };
+}
+
+function getYScale(moreProps) {
+ const { yScale: scale, flipYScale, height } = moreProps.chartConfig;
+ if (scale.invert) {
+ const trueRange = flipYScale ? [0, height] : [height, 0];
+ const trueDomain = trueRange.map(scale.invert);
+ return scale.copy()
+ .domain(trueDomain)
+ .range(trueRange);
+ }
+ return scale;
+}
diff --git a/packages/react-financial-charts/src/axes/index.ts b/packages/react-financial-charts/src/axes/index.ts
new file mode 100644
index 000000000..d24baa079
--- /dev/null
+++ b/packages/react-financial-charts/src/axes/index.ts
@@ -0,0 +1,2 @@
+export * from "./XAxis";
+export * from "./YAxis";
diff --git a/packages/react-financial-charts/src/calculator/atr.ts b/packages/react-financial-charts/src/calculator/atr.ts
new file mode 100644
index 000000000..e0ce5bb04
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/atr.ts
@@ -0,0 +1,69 @@
+import { sum } from "d3-array";
+
+import { isDefined, last, slidingWindow } from "../utils";
+
+import { ATR as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+ let source = (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close });
+
+ function calculator(data) {
+ const { windowSize } = options;
+
+ const trueRangeAlgorithm = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .source(source)
+ .undefinedValue((d) => d.high - d.low) // the first TR value is simply the High minus the Low
+ .accumulator((values) => {
+ const prev = values[0];
+ const d = values[1];
+ return Math.max(d.high - d.low,
+ d.high - prev.close,
+ d.low - prev.close);
+ });
+
+ let prevATR;
+
+ const atrAlgorithm = slidingWindow()
+ .skipInitial(1) // trueRange starts from index 1 so ATR starts from 1
+ // @ts-ignore
+ .windowSize(windowSize)
+ .accumulator((values) => {
+ const tr = last(values);
+ const atr = isDefined(prevATR)
+ ? ((prevATR * (windowSize - 1)) + tr) / windowSize
+ : sum(values) / windowSize;
+
+ prevATR = atr;
+ return atr;
+ });
+
+ const newData = atrAlgorithm(trueRangeAlgorithm(data));
+
+ return newData;
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ calculator.source = function (x) {
+ if (!arguments.length) {
+ return source;
+ }
+ source = x;
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/bollingerband.ts b/packages/react-financial-charts/src/calculator/bollingerband.ts
new file mode 100644
index 000000000..9c72aeeb7
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/bollingerband.ts
@@ -0,0 +1,84 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/bollingerBands.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import { deviation, mean } from "d3-array";
+
+import { last, path, slidingWindow, zipper } from "../utils";
+import ema from "./ema";
+
+import { BollingerBand as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, multiplier, movingAverageType, sourcePath } = options;
+
+ // @ts-ignore
+ const source = path(sourcePath);
+
+ const meanAlgorithm = movingAverageType === "ema"
+ ? ema().options({ windowSize, sourcePath })
+ : slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator((values) => mean(values))
+ .sourcePath(sourcePath);
+
+ const bollingerBandAlgorithm = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator((values) => {
+ const avg = last(values).mean;
+ const stdDev = deviation(values, (each) => source(each.datum));
+ return {
+ top: avg + multiplier * stdDev,
+ middle: avg,
+ bottom: avg - multiplier * stdDev,
+ };
+ });
+
+ const zip = zipper()
+ .combine((datum, meanValue) => ({ datum, meanValue }));
+
+ // @ts-ignore
+ const tuples = zip(data, meanAlgorithm(data));
+ return bollingerBandAlgorithm(tuples);
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/change.ts b/packages/react-financial-charts/src/calculator/change.ts
new file mode 100644
index 000000000..6c869dbc4
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/change.ts
@@ -0,0 +1,36 @@
+import { slidingWindow } from "../utils";
+import { Change as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { sourcePath } = options;
+
+ const algo = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .sourcePath(sourcePath)
+ .accumulator(([prev, curr]) => {
+ const absoluteChange = curr - prev;
+ const percentChange = absoluteChange * 100 / prev;
+ return { absoluteChange, percentChange };
+ });
+
+ const newData = algo(data);
+
+ return newData;
+ }
+ calculator.undefinedLength = function () {
+ return 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/compare.ts b/packages/react-financial-charts/src/calculator/compare.ts
new file mode 100644
index 000000000..16c3b1a5e
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/compare.ts
@@ -0,0 +1,58 @@
+import { head, isDefined, isNotDefined, path } from "../utils";
+import { Change as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { basePath, mainKeys, compareKeys } = options;
+
+ // @ts-ignore
+ const base = path(basePath);
+
+ const first = head(data);
+ const b = base(first);
+
+ const firsts = {};
+
+ const compareData = data.map((d) => {
+ const result = {};
+
+ mainKeys.forEach((key) => {
+ if (typeof d[key] === "object") {
+ // @ts-ignore
+ result[key] = {};
+ Object.keys(d[key]).forEach((subkey) => {
+ // @ts-ignore
+ result[key][subkey] = (d[key][subkey] - b) / b;
+ });
+ } else {
+ // @ts-ignore
+ result[key] = (d[key] - b) / b;
+ }
+ });
+
+ compareKeys.forEach((key) => {
+ if (isDefined(d[key]) && isNotDefined(firsts[key])) {
+ // @ts-ignore
+ firsts[key] = d[key];
+ }
+ if (isDefined(d[key]) && isDefined(firsts[key])) {
+ // @ts-ignore
+ result[key] = (d[key] - firsts[key]) / firsts[key];
+ }
+ });
+ return result;
+ });
+
+ return compareData;
+ }
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/defaultOptionsForComputation.ts b/packages/react-financial-charts/src/calculator/defaultOptionsForComputation.ts
new file mode 100644
index 000000000..5372ee57c
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/defaultOptionsForComputation.ts
@@ -0,0 +1,116 @@
+export const BollingerBand = {
+ windowSize: 20,
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+ multiplier: 2,
+ movingAverageType: "sma",
+};
+
+export const ATR = {
+ windowSize: 14,
+};
+
+export const ForceIndex = {
+ sourcePath: "close", // "high", "low", "open", "close"
+ volumePath: "volume",
+};
+
+export const SmoothedForceIndex = {
+ sourcePath: "close", // "high", "low", "open", "close"
+ volumePath: "volume",
+ smoothingType: "ema",
+ smoothingWindow: 13,
+};
+
+export const Change = {
+ sourcePath: "close", // "high", "low", "open", "close"
+ basePath: "close",
+ mainKeys: [],
+ compareKeys: [],
+};
+
+export const Compare = {
+ basePath: "close",
+ mainKeys: ["open", "high", "low", "close"],
+ compareKeys: [],
+};
+
+export const ElderRay = {
+ windowSize: 13,
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close", // "high", "low", "open", "close"
+ movingAverageType: "sma",
+};
+
+export const ElderImpulse = {
+ sourcePath: "close", // "high", "low", "open", "close"
+};
+
+export const SAR = {
+ accelerationFactor: 0.02,
+ maxAccelerationFactor: 0.2,
+};
+
+export const MACD = {
+ fast: 12,
+ slow: 26,
+ signal: 9,
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+};
+
+export const FullStochasticOscillator = {
+ windowSize: 12,
+ kWindowSize: 3,
+ dWindowSize: 3,
+};
+
+export const RSI = {
+ windowSize: 14,
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close", // "high", "low", "open", "close"
+};
+
+export const EMA = {
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+ windowSize: 10,
+};
+
+export const SMA = {
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+ windowSize: 10,
+};
+
+export const WMA = {
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+ windowSize: 10,
+};
+
+export const TMA = {
+ // source: d => d.close, // "high", "low", "open", "close"
+ sourcePath: "close",
+ windowSize: 10,
+};
+
+export const Kagi = {
+ reversalType: "ATR", // "ATR", "FIXED"
+ windowSize: 14,
+ reversal: 2,
+ sourcePath: "close", // "high", "low", "open", "close"
+};
+
+export const Renko = {
+ reversalType: "ATR", // "ATR", "FIXED"
+ windowSize: 14,
+ fixedBrickSize: 2,
+ sourcePath: "high/low", // "close", "high/low"
+};
+
+export const PointAndFigure = {
+ boxSize: 0.5,
+ reversal: 3,
+ sourcePath: "high/low", // "close", "high/low"
+};
diff --git a/packages/react-financial-charts/src/calculator/elderRay.ts b/packages/react-financial-charts/src/calculator/elderRay.ts
new file mode 100644
index 000000000..b2a349c5b
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/elderRay.ts
@@ -0,0 +1,80 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/elderRay.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import { mean } from "d3-array";
+
+import ema from "./ema";
+
+import { isDefined, slidingWindow, zipper } from "../utils";
+import { ElderRay as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+ let ohlc = (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close });
+
+ function calculator(data) {
+ const { windowSize, sourcePath, movingAverageType } = options;
+
+ const meanAlgorithm = movingAverageType === "ema"
+ ? ema().options({ windowSize, sourcePath })
+ : slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator((values) => mean(values)).sourcePath(sourcePath);
+
+ const zip = zipper()
+ .combine((datum, meanValue) => {
+ const bullPower = isDefined(meanValue) ? ohlc(datum).high - meanValue : undefined;
+ const bearPower = isDefined(meanValue) ? ohlc(datum).low - meanValue : undefined;
+ return { bullPower, bearPower };
+ });
+
+ // @ts-ignore
+ const newData = zip(data, meanAlgorithm(data));
+ return newData;
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.ohlc = function (x) {
+ if (!arguments.length) {
+ return ohlc;
+ }
+ ohlc = x;
+ return calculator;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/ema.ts b/packages/react-financial-charts/src/calculator/ema.ts
new file mode 100644
index 000000000..1a0c9f35c
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/ema.ts
@@ -0,0 +1,77 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/exponentialMovingAverage.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import { isNotDefined, path } from "../utils";
+import { EMA as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, sourcePath } = options;
+
+ // @ts-ignore
+ const source = path(sourcePath);
+ const alpha = 2 / (windowSize + 1);
+ let previous;
+ let initialAccumulator = 0;
+ let skip = 0;
+
+ return data.map(function (d, i) {
+ const v = source(d, i);
+ if (isNotDefined(previous) && isNotDefined(v)) {
+ skip++;
+ return undefined;
+ } else if (i < windowSize + skip - 1) {
+ initialAccumulator += v;
+ return undefined;
+ } else if (i === windowSize + skip - 1) {
+ initialAccumulator += v;
+ const initialValue = initialAccumulator / windowSize;
+ previous = initialValue;
+ return initialValue;
+ } else {
+ const nextValue = v * alpha + (1 - alpha) * previous;
+ previous = nextValue;
+ return nextValue;
+ }
+ });
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/forceIndex.ts b/packages/react-financial-charts/src/calculator/forceIndex.ts
new file mode 100644
index 000000000..5c26dfb6f
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/forceIndex.ts
@@ -0,0 +1,38 @@
+import { path, slidingWindow } from "../utils";
+import { ForceIndex as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { sourcePath, volumePath } = options;
+
+ // @ts-ignore
+ const source = path(sourcePath);
+
+ // @ts-ignore
+ const volume = path(volumePath);
+
+ const forceIndexCalulator = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .accumulator(([prev, curr]) => (source(curr) - source(prev)) * volume(curr));
+
+ const forceIndex = forceIndexCalulator(data);
+
+ return forceIndex;
+ }
+ calculator.undefinedLength = function () {
+ return 2;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/heikinAshi.ts b/packages/react-financial-charts/src/calculator/heikinAshi.ts
new file mode 100644
index 000000000..7add11109
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/heikinAshi.ts
@@ -0,0 +1,36 @@
+import { identity, mappedSlidingWindow } from "../utils";
+
+export default function () {
+
+ let source = identity;
+
+ function calculator(data) {
+ const algorithm = mappedSlidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .undefinedValue(({ open, high, low, close }) => {
+ close = (open + high + low + close) / 4;
+ return { open, high, low, close };
+ })
+ .accumulator(([prev, now]) => {
+ // console.log(prev, now);
+ const { date, volume } = now;
+ const close = (now.open + now.high + now.low + now.close) / 4;
+ const open = (prev.open + prev.close) / 2;
+ const high = Math.max(open, now.high, close);
+ const low = Math.min(open, now.low, close);
+ return { date, open, high, low, close, volume };
+ });
+
+ return algorithm(data);
+ }
+ calculator.source = function (x) {
+ if (!arguments.length) {
+ return source;
+ }
+ source = x;
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/index.ts b/packages/react-financial-charts/src/calculator/index.ts
new file mode 100644
index 000000000..aae131da9
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/index.ts
@@ -0,0 +1,19 @@
+export { default as ema } from "./ema";
+export { default as sma } from "./sma";
+export { default as wma } from "./wma";
+export { default as tma } from "./tma";
+export { default as bollingerband } from "./bollingerband";
+export { default as heikinAshi } from "./heikinAshi";
+export { default as kagi } from "./kagi";
+export { default as pointAndFigure } from "./pointAndFigure";
+export { default as renko } from "./renko";
+export { default as macd } from "./macd";
+export { default as rsi } from "./rsi";
+export { default as sto } from "./sto";
+export { default as atr } from "./atr";
+export { default as forceIndex } from "./forceIndex";
+export { default as smoothedForceIndex } from "./smoothedForceIndex";
+export { default as elderRay } from "./elderRay";
+export { default as sar } from "./sar";
+export { default as compare } from "./compare";
+export { default as change } from "./change";
diff --git a/packages/react-financial-charts/src/calculator/kagi.ts b/packages/react-financial-charts/src/calculator/kagi.ts
new file mode 100644
index 000000000..5adf8e9ce
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/kagi.ts
@@ -0,0 +1,226 @@
+import { functor, isNotDefined, merge, path } from "../utils";
+import atr from "./atr";
+
+import { Kagi as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+ let dateAccessor = (d) => d.date;
+ let dateMutator = (d, date) => { d.date = date; };
+
+ function calculator(data) {
+ const { reversalType, windowSize, reversal, sourcePath } = options;
+
+ // @ts-ignore
+ const source = path(sourcePath);
+ let reversalThreshold;
+
+ if (reversalType === "ATR") {
+ // calculateATR(rawData, period);
+ const atrAlgorithm = atr().options({ windowSize });
+
+ const atrCalculator = merge()
+ .algorithm(atrAlgorithm)
+ // @ts-ignore
+ .merge((d, c) => { d["atr" + windowSize] = c; });
+
+ atrCalculator(data);
+ reversalThreshold = (d) => d["atr" + windowSize];
+ } else {
+ reversalThreshold = functor(reversal);
+ }
+
+ const kagiData: any[] = [];
+
+ let prevPeak;
+ let prevTrough;
+ let direction;
+
+ let line: {
+ added?: any;
+ date?: any;
+ from?: any;
+ to?: any;
+ open?: number;
+ high?: number;
+ low?: number;
+ close?: number;
+ current?: any;
+ changePoint?: any;
+ changeTo?: any;
+ volume?: number;
+ reverseAt?: any;
+ startAs?: any;
+ startOfYear?: any;
+ startOfQuarter?: any;
+ startOfMonth?: any;
+ startOfWeek?: any;
+ } = {};
+
+ data.forEach(function (d) {
+ if (isNotDefined(line.from)) {
+ dateMutator(line, dateAccessor(d));
+ line.from = dateAccessor(d);
+
+ if (!line.open) { line.open = d.open; }
+ line.high = d.high;
+ line.low = d.low;
+ if (!line.close) { line.close = source(d); }
+ line.startOfYear = d.startOfYear;
+ line.startOfQuarter = d.startOfQuarter;
+ line.startOfMonth = d.startOfMonth;
+ line.startOfWeek = d.startOfWeek;
+ }
+
+ if (!line.startOfYear) {
+ line.startOfYear = d.startOfYear;
+ if (line.startOfYear) {
+ line.date = d.date;
+ // line.displayDate = d.displayDate;
+ }
+ }
+
+ if (!line.startOfQuarter) {
+ line.startOfQuarter = d.startOfQuarter;
+ if (line.startOfQuarter && !line.startOfYear) {
+ line.date = d.date;
+ // line.displayDate = d.displayDate;
+ }
+ }
+
+ if (!line.startOfMonth) {
+ line.startOfMonth = d.startOfMonth;
+ if (line.startOfMonth && !line.startOfQuarter) {
+ line.date = d.date;
+ // line.displayDate = d.displayDate;
+ }
+ }
+ if (!line.startOfWeek) {
+ line.startOfWeek = d.startOfWeek;
+ if (line.startOfWeek && !line.startOfMonth) {
+ line.date = d.date;
+ // line.displayDate = d.displayDate;
+ }
+ }
+ line.volume = (line.volume || 0) + d.volume;
+ // @ts-ignore
+ line.high = Math.max(line.high, d.high);
+ // @ts-ignore
+ line.low = Math.min(line.low, d.low);
+ line.to = dateAccessor(d);
+
+ // @ts-ignore
+ const priceMovement = (source(d) - line.close);
+
+ // console.log(source(d), priceMovement)
+ // @ts-ignore
+ if ((line.close >= line.open /* going up */ && priceMovement > 0 /* and moving in same direction */)
+ // @ts-ignore
+ || (line.close < line.open /* going down */ && priceMovement < 0 /* and moving in same direction */)) {
+ line.close = source(d);
+ // @ts-ignore
+ if (prevTrough && line.close < prevTrough) {
+ // going below the prevTrough, so change from yang to yin
+ // A yin line forms when a Kagi line breaks below the prior trough.
+ line.changePoint = prevTrough;
+ if (line.startAs !== "yin") {
+ line.changeTo = "yin";
+ // line.startAs = "yang";
+ }
+ }
+
+ // @ts-ignore
+ if (prevPeak && line.close > prevPeak) {
+ // going above the prevPeak, so change from yin to yang
+ // A yang line forms when a Kagi line breaks above the prior peak
+ line.changePoint = prevPeak;
+ if (line.startAs !== "yang") {
+ line.changeTo = "yang";
+ // line.startAs = "yin";
+ }
+ }
+ // @ts-ignore
+ } else if ((line.close >= line.open /* going up */
+ && priceMovement < 0 /* and moving in other direction */
+ && Math.abs(priceMovement) > reversalThreshold(d) /* and the movement is big enough for reversal */)
+ // @ts-ignore
+ || (line.close < line.open /* going down */
+ && priceMovement > 0 /* and moving in other direction */
+ /* and the movement is big enough for reversal */
+ && Math.abs(priceMovement) > reversalThreshold(d))) {
+ // reverse direction
+ const nextLineOpen = line.close;
+
+ // @ts-ignore
+ direction = (line.close - line.open) / Math.abs(line.close - line.open);
+
+ let nextChangePoint;
+ let nextChangeTo;
+ if (direction < 0 /* if direction so far has been -ve*/) {
+ // compare with line.close becomes prevTrough
+ if (isNotDefined(prevPeak)) { prevPeak = line.open; }
+ prevTrough = line.close;
+ if (source(d) > prevPeak) {
+ nextChangePoint = prevPeak;
+ nextChangeTo = "yang";
+ }
+ } else {
+ if (isNotDefined(prevTrough)) { prevTrough = line.open; }
+ prevPeak = line.close;
+ if (source(d) < prevTrough) {
+ nextChangePoint = prevTrough;
+ nextChangeTo = "yin";
+ }
+ }
+ if (isNotDefined(line.startAs)) {
+ line.startAs = direction > 0 ? "yang" : "yin";
+ }
+
+ const startAs = line.changeTo || line.startAs;
+ line.added = true;
+ kagiData.push(line);
+ direction = -1 * direction; // direction is reversed
+
+ line = { ...line };
+ line.open = nextLineOpen;
+ line.close = source(d);
+ line.startAs = startAs;
+ line.changePoint = nextChangePoint;
+ line.changeTo = nextChangeTo;
+ line.added = false;
+ line.from = undefined;
+ line.volume = 0;
+ } else {
+ // console.log("MOVING IN REV DIR BUT..", line.open, line.close, source(d));
+ }
+ line.current = source(d);
+ // @ts-ignore
+ let dir = line.close - line.open;
+ dir = dir === 0 ? 1 : dir / Math.abs(dir);
+ // @ts-ignore
+ line.reverseAt = dir > 0 ? line.close - reversalThreshold(d) : line.open - reversalThreshold(d);
+ });
+ if (!line.added) { kagiData.push(line); }
+
+ return kagiData;
+ }
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+ calculator.dateMutator = function (x) {
+ if (!arguments.length) { return dateMutator; }
+ dateMutator = x;
+ return calculator;
+ };
+ calculator.dateAccessor = function (x) {
+ if (!arguments.length) { return dateAccessor; }
+ dateAccessor = x;
+ return calculator;
+ };
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/macd.ts b/packages/react-financial-charts/src/calculator/macd.ts
new file mode 100644
index 000000000..fb6b20eac
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/macd.ts
@@ -0,0 +1,85 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/macd.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import ema from "./ema";
+
+import { isDefined, zipper } from "../utils";
+import { MACD as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { fast, slow, signal, sourcePath } = options;
+
+ const fastEMA = ema()
+ .options({ windowSize: fast, sourcePath });
+
+ const slowEMA = ema()
+ .options({ windowSize: slow, sourcePath });
+
+ const signalEMA = ema()
+ .options({ windowSize: signal, sourcePath: undefined });
+
+ const macdCalculator = zipper()
+ .combine((fastEMAValue, slowEMAValue) => {
+ return (isDefined(fastEMAValue) && isDefined(slowEMAValue)) ? fastEMAValue - slowEMAValue : undefined;
+ });
+
+ // @ts-ignore
+ const macdArray = macdCalculator(fastEMA(data), slowEMA(data));
+
+ const undefinedArray = new Array(slow);
+ // @ts-ignore
+ const signalArray = undefinedArray.concat(signalEMA(macdArray.slice(slow)));
+
+ const zip = zipper()
+ .combine((macdValue, signalValue) => ({
+ macdValue,
+ signalValue,
+ divergence: (isDefined(macdValue) && isDefined(signalValue)) ? macdValue - signalValue : undefined,
+ }));
+
+ // @ts-ignore
+ const macd = zip(macdArray, signalArray);
+
+ return macd;
+ }
+
+ calculator.undefinedLength = function () {
+ const { slow, signal } = options;
+ return slow + signal - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/pointAndFigure.ts b/packages/react-financial-charts/src/calculator/pointAndFigure.ts
new file mode 100644
index 000000000..0edafa439
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/pointAndFigure.ts
@@ -0,0 +1,244 @@
+import { isNotDefined } from "../utils";
+import { PointAndFigure as defaultOptions } from "./defaultOptionsForComputation";
+
+function createBox(d, dateAccessor, dateMutator) {
+ const box = {
+ open: d.open,
+ fromDate: dateAccessor(d),
+ toDate: dateAccessor(d),
+ startOfYear: d.startOfYear,
+ startOfQuarter: d.startOfQuarter,
+ startOfMonth: d.startOfMonth,
+ startOfWeek: d.startOfWeek,
+ };
+ dateMutator(box, dateAccessor(d));
+ return box;
+}
+
+function updateColumns(columnData, dateAccessor, dateMutator) {
+ columnData.forEach(function (d) {
+ // var lastBox = d.boxes[d.boxes.length - 1];
+
+ d.startOfYear = false;
+ d.startOfQuarter = false;
+ d.startOfMonth = false;
+ d.startOfWeek = false;
+
+ d.boxes.forEach(function (eachBox) {
+ if (isNotDefined(d.open)) { d.open = eachBox.open; }
+ d.close = eachBox.close;
+ d.high = Math.max(d.open, d.close);
+ d.low = Math.min(d.open, d.close);
+
+ if (isNotDefined(d.fromDate)) { d.fromDate = eachBox.fromDate; }
+ if (isNotDefined(d.date)) { d.date = eachBox.date; }
+ d.toDate = eachBox.toDate;
+
+ if (eachBox.startOfYear) {
+ d.startOfYear = d.startOfYear || eachBox.startOfYear;
+ d.startOfQuarter = eachBox.startOfQuarter;
+ d.startOfMonth = eachBox.startOfMonth;
+ d.startOfWeek = eachBox.startOfWeek;
+
+ dateMutator(d, dateAccessor(eachBox));
+ }
+ if (d.startOfQuarter !== true && eachBox.startOfQuarter) {
+ d.startOfQuarter = eachBox.startOfQuarter;
+ d.startOfMonth = eachBox.startOfMonth;
+ d.startOfWeek = eachBox.startOfWeek;
+ // d.displayDate = eachBox.displayDate;
+ dateMutator(d, dateAccessor(eachBox));
+ }
+ if (d.startOfMonth !== true && eachBox.startOfMonth) {
+ d.startOfMonth = eachBox.startOfMonth;
+ d.startOfWeek = eachBox.startOfWeek;
+ // d.displayDate = eachBox.displayDate;
+ dateMutator(d, dateAccessor(eachBox));
+ }
+ if (d.startOfWeek !== true && eachBox.startOfWeek) {
+ d.startOfWeek = eachBox.startOfWeek;
+ // d.displayDate = eachBox.displayDate;
+ dateMutator(d, dateAccessor(eachBox));
+ }
+ });
+
+ });
+
+ // console.table(columnData);
+ // console.table(rawData);
+ return columnData;
+}
+
+export default function () {
+ let options = defaultOptions;
+ let dateAccessor = (d) => d.date;
+ let dateMutator = (d, date) => { d.date = date; };
+
+ function calculator(rawData) {
+ const { reversal, boxSize, sourcePath } = options;
+
+ const source = sourcePath === "high/low"
+ ? (d) => ({ high: d.high, low: d.low })
+ : (d) => ({ high: d.close, low: d.close });
+
+ const pricingMethod = source;
+ const columnData: any[] = [];
+
+ // @ts-ignore
+ let column: {
+ boxes: any[];
+ direction: any;
+ open: number;
+ close?: number;
+ } = {
+ boxes: [],
+ open: rawData[0].open,
+ };
+ let box = createBox(rawData[0], dateAccessor, dateMutator);
+
+ columnData.push(column);
+
+ rawData.forEach(function (d) {
+ // @ts-ignore
+ column.volume = (column.volume || 0) + d.volume;
+
+ if (!box.startOfYear) {
+ box.startOfYear = d.startOfYear;
+ if (box.startOfYear) {
+ dateMutator(box, dateAccessor(d));
+ // box.displayDate = d.displayDate;
+ }
+ }
+
+ if (!box.startOfYear && !box.startOfQuarter) {
+ box.startOfQuarter = d.startOfQuarter;
+ if (box.startOfQuarter && !box.startOfYear) {
+ dateMutator(box, dateAccessor(d));
+ // box.displayDate = d.displayDate;
+ }
+ }
+
+ if (!box.startOfQuarter && !box.startOfMonth) {
+ box.startOfMonth = d.startOfMonth;
+ if (box.startOfMonth && !box.startOfQuarter) {
+ dateMutator(box, dateAccessor(d));
+ // box.displayDate = d.displayDate;
+ }
+ }
+ if (!box.startOfMonth && !box.startOfWeek) {
+ box.startOfWeek = d.startOfWeek;
+ if (box.startOfWeek && !box.startOfMonth) {
+ dateMutator(box, dateAccessor(d));
+ // box.displayDate = d.displayDate;
+ }
+ }
+
+ if (columnData.length === 1 && column.boxes.length === 0) {
+ const upwardMovement = (Math.max((pricingMethod(d).high - column.open), 0)); // upward movement
+ const downwardMovement = Math.abs(Math.min((column.open - pricingMethod(d).low), 0)); // downward movement
+ column.direction = upwardMovement > downwardMovement ? 1 : -1;
+ if (boxSize * reversal < upwardMovement
+ || boxSize * reversal < downwardMovement) {
+ // enough movement to trigger a reversal
+ box.toDate = dateAccessor(d);
+ box.open = column.open;
+ const noOfBoxes = column.direction > 0
+ ? Math.floor(upwardMovement / boxSize)
+ : Math.floor(downwardMovement / boxSize);
+ for (let i = 0; i < noOfBoxes; i++) {
+ // @ts-ignore
+ box.close = box.open + column.direction * boxSize;
+ // @ts-ignore
+ const prevBoxClose = box.close;
+ column.boxes.push(box);
+ box = createBox(box, dateAccessor, dateMutator);
+ // box = cloneMe(box);
+ box.open = prevBoxClose;
+ }
+ box.fromDate = dateAccessor(d);
+ // @ts-ignore
+ box.date = dateAccessor(d);
+ }
+ } else {
+ // one or more boxes already formed in the current column
+ const upwardMovement = (Math.max((pricingMethod(d).high - box.open), 0)); // upward movement
+ const downwardMovement = Math.abs(Math.min((pricingMethod(d).low - box.open), 0)); // downward movement
+
+ if ((column.direction > 0 && upwardMovement > boxSize) /* rising column AND box can be formed */
+ || (column.direction < 0 && downwardMovement > boxSize) /* falling column AND box can be formed */) {
+ // form another box
+ // @ts-ignore
+ box.close = box.open + column.direction * boxSize;
+ box.toDate = dateAccessor(d);
+
+ // @ts-ignore
+ const prevBoxClose = box.close;
+ column.boxes.push(box);
+ box = createBox(d, dateAccessor, dateMutator);
+ box.open = prevBoxClose;
+ box.fromDate = dateAccessor(d);
+ dateMutator(box, dateAccessor(d));
+ } else if (
+ /* rising column and there is downward movement to trigger a reversal */
+ (column.direction > 0 && downwardMovement > boxSize * reversal)
+ /* falling column and there is downward movement to trigger a reversal */
+ || (column.direction < 0 && upwardMovement > boxSize * reversal)) {
+ // reversal
+
+ box.open = box.open + -1 * column.direction * boxSize;
+ box.toDate = dateAccessor(d);
+ // box.displayDate = d.displayDate;
+ dateMutator(box, dateAccessor(d));
+ // box.startOfYear = d.startOfYear;
+ // box.startOfQuarter = d.startOfQuarter;
+ // box.startOfMonth = d.startOfMonth;
+ // box.startOfWeek = d.startOfWeek;
+ // console.table(column.boxes);
+ // var idx = index + 1;
+ column = {
+ boxes: [],
+ // @ts-ignore
+ volume: 0,
+ direction: -1 * column.direction,
+ };
+ const noOfBoxes = column.direction > 0
+ ? Math.floor(upwardMovement / boxSize)
+ : Math.floor(downwardMovement / boxSize);
+ for (let i = 0; i < noOfBoxes; i++) {
+ // @ts-ignore
+ box.close = box.open + column.direction * boxSize;
+ // @ts-ignore
+ const prevBoxClose = box.close;
+ column.boxes.push(box);
+ box = createBox(d, dateAccessor, dateMutator);
+ box.open = prevBoxClose;
+ }
+
+ columnData.push(column);
+ }
+ }
+ });
+ updateColumns(columnData, dateAccessor, dateMutator);
+
+ return columnData;
+ }
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+ calculator.dateMutator = function (x) {
+ if (!arguments.length) { return dateMutator; }
+ dateMutator = x;
+ return calculator;
+ };
+ calculator.dateAccessor = function (x) {
+ if (!arguments.length) { return dateAccessor; }
+ dateAccessor = x;
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/renko.ts b/packages/react-financial-charts/src/calculator/renko.ts
new file mode 100644
index 000000000..0e31a0469
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/renko.ts
@@ -0,0 +1,217 @@
+
+import { functor, isNotDefined, merge } from "../utils";
+
+import atr from "./atr";
+
+import { Renko as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ let dateAccessor = (d) => d.date;
+ let dateMutator = (d, date) => { d.date = date; };
+
+ function calculator(rawData) {
+ const { reversalType, fixedBrickSize, sourcePath, windowSize } = options;
+
+ const source = sourcePath === "high/low"
+ ? (d) => ({ high: d.high, low: d.low })
+ : (d) => ({ high: d.close, low: d.close });
+
+ const pricingMethod = source;
+ let brickSize;
+
+ if (reversalType === "ATR") {
+ // calculateATR(rawData, period);
+ const atrAlgorithm = atr().options({ windowSize });
+
+ const atrCalculator = merge()
+ .algorithm(atrAlgorithm)
+ // @ts-ignore
+ .merge((d, c) => { d["atr" + windowSize] = c; });
+
+ atrCalculator(rawData);
+ brickSize = (d) => d["atr" + windowSize];
+ } else {
+ brickSize = functor(fixedBrickSize);
+ }
+
+ const renkoData: any[] = [];
+
+ let index = 0;
+ let prevBrickClose = rawData[index].open;
+ let prevBrickOpen = rawData[index].open;
+ let brick: {
+ added?: any;
+ date?: any;
+ direction?: any;
+ from?: any;
+ fromDate?: any;
+ to?: any;
+ toDate?: any;
+ open?: number;
+ high?: number;
+ low?: number;
+ close?: number;
+ fullyFormed?: any;
+ current?: any;
+ changePoint?: any;
+ changeTo?: any;
+ volume?: number;
+ reverseAt?: any;
+ startAs?: any;
+ startOfYear?: any;
+ startOfQuarter?: any;
+ startOfMonth?: any;
+ startOfWeek?: any;
+ } = {};
+ let direction = 0;
+
+ rawData.forEach(function (d, idx) {
+ if (isNotDefined(brick.from)) {
+ brick.high = d.high;
+ brick.low = d.low;
+ brick.startOfYear = d.startOfYear;
+ brick.startOfQuarter = d.startOfQuarter;
+ brick.startOfMonth = d.startOfMonth;
+ brick.startOfWeek = d.startOfWeek;
+
+ brick.from = idx;
+ brick.fromDate = dateAccessor(d);
+ // indexMutator(brick, index++);
+ dateMutator(brick, dateAccessor(d));
+ }
+ brick.volume = (brick.volume || 0) + d.volume;
+
+ const prevCloseToHigh = (prevBrickClose - pricingMethod(d).high);
+ const prevCloseToLow = (prevBrickClose - pricingMethod(d).low);
+ const prevOpenToHigh = (prevBrickOpen - pricingMethod(d).high);
+ const prevOpenToLow = (prevBrickOpen - pricingMethod(d).low);
+ const priceMovement = Math.min(
+ Math.abs(prevCloseToHigh),
+ Math.abs(prevCloseToLow),
+ Math.abs(prevOpenToHigh),
+ Math.abs(prevOpenToLow));
+
+ // @ts-ignore
+ brick.high = Math.max(brick.high, d.high);
+ // @ts-ignore
+ brick.low = Math.min(brick.low, d.low);
+
+ if (!brick.startOfYear) {
+ brick.startOfYear = d.startOfYear;
+ if (brick.startOfYear) {
+ dateMutator(brick, dateAccessor(d));
+ // brick.displayDate = d.displayDate;
+ }
+ }
+
+ if (!brick.startOfQuarter) {
+ brick.startOfQuarter = d.startOfQuarter;
+ if (brick.startOfQuarter && !brick.startOfYear) {
+ dateMutator(brick, dateAccessor(d));
+ // brick.displayDate = d.displayDate;
+ }
+ }
+
+ if (!brick.startOfMonth) {
+ brick.startOfMonth = d.startOfMonth;
+ if (brick.startOfMonth && !brick.startOfQuarter) {
+ dateMutator(brick, dateAccessor(d));
+ // brick.displayDate = d.displayDate;
+ }
+ }
+ if (!brick.startOfWeek) {
+ brick.startOfWeek = d.startOfWeek;
+ if (brick.startOfWeek && !brick.startOfMonth) {
+ dateMutator(brick, dateAccessor(d));
+ // brick.displayDate = d.displayDate;
+ }
+ }
+
+ // d.brick = JSON.stringify(brick);
+ if (brickSize(d)) {
+ const noOfBricks = Math.floor(priceMovement / brickSize(d));
+
+ brick.open = (Math.abs(prevCloseToHigh) < Math.abs(prevOpenToHigh)
+ || Math.abs(prevCloseToLow) < Math.abs(prevOpenToLow))
+ ? prevBrickClose
+ : prevBrickOpen;
+
+ if (noOfBricks >= 1) {
+ let j = 0;
+ for (j = 0; j < noOfBricks; j++) {
+ // @ts-ignore
+ brick.close = (brick.open < pricingMethod(d).high)
+ // if brick open is less than current price it means it is green/hollow brick
+ ? brick.open + brickSize(d)
+ // @ts-ignore
+ : brick.open - brickSize(d);
+ // @ts-ignore
+ direction = brick.close > brick.open ? 1 : -1;
+ brick.direction = direction;
+ brick.to = idx;
+ brick.toDate = dateAccessor(d);
+ // brick.diff = brick.open - brick.close;
+ // brick.atr = d.atr;
+ brick.fullyFormed = true;
+ renkoData.push(brick);
+
+ prevBrickClose = brick.close;
+ prevBrickOpen = brick.open;
+
+ const newBrick = {
+ high: brick.high,
+ low: brick.low,
+ open: brick.close,
+ startOfYear: false,
+ startOfMonth: false,
+ startOfQuarter: false,
+ startOfWeek: false,
+ };
+ brick = newBrick;
+ brick.from = idx;
+ brick.fromDate = dateAccessor(d);
+ // indexMutator(brick, index + j);
+ dateMutator(brick, dateAccessor(d));
+ brick.volume = (brick.volume || 0) + d.volume;
+ }
+ index = index + j - 1;
+ brick = {};
+ } else {
+ if (idx === rawData.length - 1) {
+ brick.close = direction > 0 ? pricingMethod(d).high : pricingMethod(d).low;
+ brick.to = idx;
+ brick.toDate = dateAccessor(d);
+ dateMutator(brick, dateAccessor(d));
+ brick.fullyFormed = false;
+ renkoData.push(brick);
+ }
+ }
+ }
+
+ });
+ return renkoData;
+
+ }
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ calculator.dateMutator = function (x) {
+ if (!arguments.length) { return dateMutator; }
+ dateMutator = x;
+ return calculator;
+ };
+ calculator.dateAccessor = function (x) {
+ if (!arguments.length) { return dateAccessor; }
+ dateAccessor = x;
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/rsi.ts b/packages/react-financial-charts/src/calculator/rsi.ts
new file mode 100644
index 000000000..575aafced
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/rsi.ts
@@ -0,0 +1,100 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/relativeStrengthIndex.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import { mean } from "d3-array";
+
+import { isDefined, last, path, slidingWindow } from "../utils";
+import { RSI as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, sourcePath } = options;
+
+ // @ts-ignore
+ const source = path(sourcePath);
+
+ let prevAvgGain;
+ let prevAvgLoss;
+ const rsiAlgorithm = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator((values) => {
+
+ const avgGain = isDefined(prevAvgGain)
+ ? (prevAvgGain * (windowSize - 1) + last(values).gain) / windowSize
+ : mean(values, (each) => each.gain);
+
+ const avgLoss = isDefined(prevAvgLoss)
+ ? (prevAvgLoss * (windowSize - 1) + last(values).loss) / windowSize
+ : mean(values, (each) => each.loss);
+
+ const relativeStrength = avgGain / avgLoss;
+ const rsi = 100 - (100 / (1 + relativeStrength));
+
+ prevAvgGain = avgGain;
+ prevAvgLoss = avgLoss;
+
+ return rsi;
+ });
+
+ const gainsAndLossesCalculator = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .undefinedValue(() => [0, 0])
+ .accumulator((tuple) => {
+ const prev = tuple[0];
+ const now = tuple[1];
+ const change = source(now) - source(prev);
+ return {
+ gain: Math.max(change, 0),
+ loss: Math.abs(Math.min(change, 0)),
+ };
+ });
+
+ const gainsAndLosses = gainsAndLossesCalculator(data);
+
+ const rsiData = rsiAlgorithm(gainsAndLosses);
+
+ return rsiData;
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/sar.ts b/packages/react-financial-charts/src/calculator/sar.ts
new file mode 100644
index 000000000..049a6a7c1
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/sar.ts
@@ -0,0 +1,113 @@
+import { isDefined, isNotDefined, mappedSlidingWindow } from "../utils";
+import { SAR as defaultOptions } from "./defaultOptionsForComputation";
+
+function calc(prev, now) {
+ const risingSar = prev.risingSar
+ + prev.af * (prev.risingEp - prev.risingSar);
+
+ const fallingSar = prev.fallingSar
+ - prev.af * (prev.fallingSar - prev.fallingEp);
+
+ const risingEp = Math.max(prev.risingEp, now.high);
+ const fallingEp = Math.min(prev.fallingEp, now.low);
+
+ return {
+ risingSar,
+ fallingSar,
+ risingEp,
+ fallingEp,
+ };
+}
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { accelerationFactor, maxAccelerationFactor } = options;
+
+ const algorithm = mappedSlidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .undefinedValue(({ high, low }) => {
+ return {
+ risingSar: low,
+ risingEp: high,
+ fallingSar: high,
+ fallingEp: low,
+ af: accelerationFactor,
+ };
+ })
+ .accumulator(([prev, now]) => {
+
+ const {
+ risingSar,
+ fallingSar,
+ risingEp,
+ fallingEp,
+ } = calc(prev, now);
+
+ if (isNotDefined(prev.use)
+ && risingSar > now.low
+ && fallingSar < now.high) {
+ return {
+ risingSar,
+ fallingSar,
+ risingEp,
+ fallingEp,
+ };
+ }
+
+ const use = isDefined(prev.use)
+ ? prev.use === "rising"
+ ? risingSar > now.low ? "falling" : "rising"
+ : fallingSar < now.high ? "rising" : "falling"
+ : risingSar > now.low
+ ? "falling"
+ : "rising";
+
+ const current = prev.use === use
+ ? {
+ af: Math.min(maxAccelerationFactor, prev.af + accelerationFactor),
+ fallingEp,
+ risingEp,
+ fallingSar,
+ risingSar,
+ }
+ : {
+ af: accelerationFactor,
+ fallingEp: now.low,
+ risingEp: now.high,
+ fallingSar: Math.max(prev.risingEp, now.high),
+ risingSar: Math.min(prev.fallingEp, now.low),
+ };
+
+ const { date, high, low } = now;
+ return {
+ date,
+ high,
+ low,
+ ...current,
+ use,
+ sar: use === "falling" ? current.fallingSar : current.risingSar,
+ };
+ });
+
+ const calculatedData = algorithm(data).map((d) => d.sar);
+ // console.log(calculatedData);
+
+ return calculatedData;
+ }
+ calculator.undefinedLength = function () {
+ return 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/sma.ts b/packages/react-financial-charts/src/calculator/sma.ts
new file mode 100644
index 000000000..40ca46469
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/sma.ts
@@ -0,0 +1,34 @@
+import { mean } from "d3-array";
+
+import { slidingWindow } from "../utils";
+import { SMA as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, sourcePath } = options;
+
+ const average = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .sourcePath(sourcePath)
+ .accumulator((values) => mean(values));
+
+ return average(data);
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/smoothedForceIndex.ts b/packages/react-financial-charts/src/calculator/smoothedForceIndex.ts
new file mode 100644
index 000000000..0a84f019b
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/smoothedForceIndex.ts
@@ -0,0 +1,53 @@
+import { zipper } from "../utils";
+import { SmoothedForceIndex as defaultOptions } from "./defaultOptionsForComputation";
+import ema from "./ema";
+import forceIndex from "./forceIndex";
+import sma from "./sma";
+
+export default function () {
+
+ const underlyingAlgorithm = forceIndex();
+ const merge = zipper()
+ .combine((force, smoothed) => {
+ return { force, smoothed };
+ });
+
+ let options = defaultOptions;
+ function calculator(data) {
+ const { smoothingType, smoothingWindow } = options;
+ const { sourcePath, volumePath } = options;
+
+ const algo = underlyingAlgorithm
+ .options({ sourcePath, volumePath });
+
+ // @ts-ignore
+ const force = algo(data);
+
+ const ma = smoothingType === "ema" ? ema() : sma();
+ const forceMA = ma
+ .options({
+ windowSize: smoothingWindow,
+ sourcePath: undefined,
+ });
+
+ // @ts-ignore
+ const smoothed = forceMA(force);
+
+ // @ts-ignore
+ return merge(force, smoothed);
+ }
+
+ calculator.undefinedLength = function () {
+ const { smoothingWindow } = options;
+ return underlyingAlgorithm.undefinedLength() + smoothingWindow - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/sto.ts b/packages/react-financial-charts/src/calculator/sto.ts
new file mode 100644
index 000000000..62dd26d33
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/sto.ts
@@ -0,0 +1,102 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/stochasticOscillator.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import { max, mean, min } from "d3-array";
+
+import { last, slidingWindow, zipper } from "../utils";
+import { FullStochasticOscillator as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ let source = (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close });
+
+ function calculator(data) {
+ const { windowSize, kWindowSize, dWindowSize } = options;
+
+ const high = (d) => source(d).high;
+ const low = (d) => source(d).low;
+ const close = (d) => source(d).close;
+
+ const kWindow = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .accumulator((values) => {
+
+ const highestHigh = max(values, high);
+ const lowestLow = min(values, low);
+
+ const currentClose = close(last(values));
+ const k = (currentClose - lowestLow) / (highestHigh - lowestLow) * 100;
+
+ return k;
+ });
+
+ const kSmoothed = slidingWindow()
+ .skipInitial(windowSize - 1)
+ // @ts-ignore
+ .windowSize(kWindowSize)
+ .accumulator((values) => mean(values));
+
+ const dWindow = slidingWindow()
+ .skipInitial(windowSize - 1 + kWindowSize - 1)
+ // @ts-ignore
+ .windowSize(dWindowSize)
+ .accumulator((values) => mean(values));
+
+ const stoAlgorithm = zipper()
+ .combine((K, D) => ({ K, D }));
+
+ const kData = kSmoothed(kWindow(data));
+ const dData = dWindow(kData);
+
+ // @ts-ignore
+ const indicatorData = stoAlgorithm(kData, dData);
+
+ return indicatorData;
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize, kWindowSize, dWindowSize } = options;
+ return windowSize + kWindowSize + dWindowSize;
+ };
+ calculator.source = function (x) {
+ if (!arguments.length) {
+ return source;
+ }
+ source = x;
+ return calculator;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/tma.ts b/packages/react-financial-charts/src/calculator/tma.ts
new file mode 100644
index 000000000..d16b1e788
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/tma.ts
@@ -0,0 +1,79 @@
+/*
+ TRIMA (Triangular Moving Average).
+
+ The Triangular Moving Average can be used like any other Moving Average, to
+ obtain a smoother representation of the underlying data.
+ It is important to note that the Triangular Moving Average is typically much
+ smoother than other moving averages.
+
+ Triangular moving averages give greater weight to prices at the centre of the
+ chosen period andi it is calculated as double smoothed SMA (simple moving average).
+
+ Examples:
+ For TimeSerie={a,b,c,d,e,f...} ('a' is the older price)
+
+ 1st value for TMA 4-Period is: ((1*a)+(2*b)+(2*c)+(1*d)) / 6
+ 2nd value for TMA 4-Period is: ((1*b)+(2*c)+(2*d)+(1*e)) / 6
+
+ 1st value for TMA 5-Period is: ((1*a)+(2*b)+(3*c)+(2*d)+(1*e)) / 9
+ 2nd value for TMA 5-Period is: ((1*b)+(2*c)+(3*d)+(2*e)+(1*f)) / 9
+
+ Using algebra, it can be demonstrated that the TMA is equivalent to
+ doing a SMA of a SMA. The following explain the rules:
+
+ (1) When the period is even, TMA(x,period)=SMA(SMA(x,period/2),(period/2)+1)
+ (2) When the period is odd, TMA(x,period)=SMA(SMA(x,(period+1)/2),(period+1)/2)
+
+ In other word:
+ (1) A period of 4 becomes TMA(x,4) = SMA( SMA( x, 2), 3 )
+ (2) A period of 5 becomes TMA(x,5) = SMA( SMA( x, 3), 3 )
+
+ The SMA of a SMA is the algorithm generally found in books.
+*/
+
+import { sum } from "d3-array";
+
+import { slidingWindow } from "../utils";
+import { TMA as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, sourcePath } = options;
+
+ const n = Math.floor(windowSize / 2);
+ const weight = (windowSize % 2) === 0
+ ? n * (n + 1)
+ : (n + 1) * (n + 1);
+
+ const triaverage = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .sourcePath(sourcePath)
+ .accumulator((values) => {
+ const total = sum(values, (v, i) => {
+ return i < n
+ ? (i + 1) * v
+ : (windowSize - i) * v;
+ });
+ return total / weight;
+ });
+
+ return triaverage(data);
+
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/calculator/wma.ts b/packages/react-financial-charts/src/calculator/wma.ts
new file mode 100644
index 000000000..a8c13a5c3
--- /dev/null
+++ b/packages/react-financial-charts/src/calculator/wma.ts
@@ -0,0 +1,42 @@
+import { sum } from "d3-array";
+
+import { slidingWindow } from "../utils";
+import { WMA as defaultOptions } from "./defaultOptionsForComputation";
+
+export default function () {
+
+ let options = defaultOptions;
+
+ function calculator(data) {
+ const { windowSize, sourcePath } = options;
+
+ const weight = windowSize * (windowSize + 1) / 2;
+
+ const waverage = slidingWindow()
+ .windowSize(windowSize)
+ // @ts-ignore
+ .sourcePath(sourcePath)
+ .accumulator((values) => {
+ const total = sum(values, (v, i) => {
+ return (i + 1) * v;
+ });
+ return total / weight;
+ });
+
+ return waverage(data);
+ }
+ calculator.undefinedLength = function () {
+ const { windowSize } = options;
+
+ return windowSize - 1;
+ };
+ calculator.options = function (x) {
+ if (!arguments.length) {
+ return options;
+ }
+ options = { ...defaultOptions, ...x };
+ return calculator;
+ };
+
+ return calculator;
+}
diff --git a/packages/react-financial-charts/src/coordinates/CrossHairCursor.tsx b/packages/react-financial-charts/src/coordinates/CrossHairCursor.tsx
new file mode 100644
index 000000000..8a1d4aac2
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/CrossHairCursor.tsx
@@ -0,0 +1,130 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import GenericComponent, { getMouseCanvas } from "../GenericComponent";
+
+import { getStrokeDasharray, hexToRGBA, isDefined, isNotDefined, strokeDashTypes } from "../utils";
+
+interface CrossHairCursorProps {
+ readonly className?: string;
+ readonly opacity?: number;
+ readonly snapX?: boolean;
+ readonly stroke?: string;
+ readonly strokeDasharray?: strokeDashTypes;
+}
+
+const defaultCustomX = (props: CrossHairCursorProps, moreProps) => {
+ const { xScale, xAccessor, currentItem, mouseXY } = moreProps;
+ const { snapX } = props;
+ const x = snapX
+ ? Math.round(xScale(xAccessor(currentItem)))
+ : mouseXY[0];
+ return x;
+};
+
+export class CrossHairCursor extends React.Component {
+
+ public static defaultProps = {
+ stroke: "#000000",
+ opacity: 0.3,
+ strokeDasharray: "ShortDash",
+ snapX: true,
+ customX: defaultCustomX,
+ };
+
+ public static contextTypes = {
+ margin: PropTypes.object.isRequired,
+ ratio: PropTypes.number.isRequired,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className } = this.props;
+ const lines = this.helper(this.props, moreProps);
+
+ if (lines === undefined) {
+ return null;
+ }
+
+ return (
+
+ {lines.map(({ strokeDasharray, ...rest }, idx) =>
+ )}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const lines = this.helper(this.props, moreProps);
+
+ if (lines !== undefined && isDefined(lines)) {
+
+ const { margin, ratio } = this.context;
+ const originX = 0.5 * ratio + margin.left;
+ const originY = 0.5 * ratio + margin.top;
+
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(ratio, ratio);
+
+ ctx.translate(originX, originY);
+
+ lines.forEach((line) => {
+ const dashArray = getStrokeDasharray(line.strokeDasharray)
+ .split(",")
+ .map((d) => +d);
+
+ ctx.strokeStyle = hexToRGBA(line.stroke, line.opacity);
+ ctx.setLineDash(dashArray);
+ ctx.beginPath();
+ ctx.moveTo(line.x1, line.y1);
+ ctx.lineTo(line.x2, line.y2);
+ ctx.stroke();
+ });
+
+ ctx.restore();
+ }
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const {
+ mouseXY, currentItem, show, height, width,
+ } = moreProps;
+
+ const { customX, stroke, opacity, strokeDasharray } = props;
+
+ if (!show || isNotDefined(currentItem)) {
+ return undefined;
+ }
+
+ const line1 = {
+ x1: 0,
+ x2: width,
+ y1: mouseXY[1],
+ y2: mouseXY[1],
+ stroke, strokeDasharray, opacity,
+ };
+ const x = customX(props, moreProps);
+
+ const line2 = {
+ x1: x,
+ x2: x,
+ y1: 0,
+ y2: height,
+ stroke, strokeDasharray, opacity,
+ };
+ return [line1, line2];
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/CurrentCoordinate.tsx b/packages/react-financial-charts/src/coordinates/CurrentCoordinate.tsx
new file mode 100644
index 000000000..b547a89f1
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/CurrentCoordinate.tsx
@@ -0,0 +1,76 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import { isNotDefined } from "../utils";
+
+interface CurrentCoordinateProps {
+ readonly className?: string;
+ readonly fill?: any;
+ readonly r: number;
+ readonly yAccessor: (item: any) => number;
+}
+
+export class CurrentCoordinate extends React.Component {
+
+ public static defaultProps = {
+ r: 3,
+ className: "react-stockcharts-current-coordinate",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const circle = this.helper(this.props, moreProps);
+ if (!circle) { return null; }
+
+ ctx.fillStyle = circle.fill;
+ ctx.beginPath();
+ ctx.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI, false);
+ ctx.fill();
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className } = this.props;
+
+ const circle = this.helper(this.props, moreProps);
+ if (!circle) { return null; }
+
+ const fillColor = circle.fill instanceof Function ? circle.fill(moreProps.currentItem) : circle.fill;
+
+ return (
+
+ );
+ }
+
+ private readonly helper = (props: CurrentCoordinateProps, moreProps) => {
+ const { fill, yAccessor, r } = props;
+
+ const { show, xScale, chartConfig: { yScale }, currentItem, xAccessor } = moreProps;
+
+ if (!show || isNotDefined(currentItem)) {
+ return null;
+ }
+
+ const xValue = xAccessor(currentItem);
+ const yValue = yAccessor(currentItem);
+
+ if (isNotDefined(yValue)) {
+ return null;
+ }
+
+ const x = Math.round(xScale(xValue));
+ const y = Math.round(yScale(yValue));
+
+ return { x, y, r, fill };
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/Cursor.tsx b/packages/react-financial-charts/src/coordinates/Cursor.tsx
new file mode 100644
index 000000000..0b6f48512
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/Cursor.tsx
@@ -0,0 +1,284 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import GenericComponent, { getMouseCanvas } from "../GenericComponent";
+
+import {
+ first,
+ getStrokeDasharray,
+ hexToRGBA,
+ isNotDefined,
+ last,
+ strokeDashTypes,
+} from "../utils";
+
+interface CursorProps {
+ className?: string;
+ stroke?: string;
+ strokeDasharray?: strokeDashTypes;
+ snapX?: boolean;
+ opacity?: number;
+ disableYCursor?: boolean;
+ useXCursorShape?: boolean;
+ xCursorShapeFill?: string | any; // func
+ xCursorShapeStroke: string | any; // func
+ xCursorShapeStrokeDasharray?: strokeDashTypes;
+ xCursorShapeOpacity?: number;
+}
+
+const defaultCustomSnapX = (props: CursorProps, moreProps) => {
+ const { xScale, xAccessor, currentItem, mouseXY } = moreProps;
+ const { snapX } = props;
+ const x = snapX ? Math.round(xScale(xAccessor(currentItem))) : mouseXY[0];
+ return x;
+};
+
+class Cursor extends React.Component {
+
+ public static defaultProps = {
+ stroke: "#000000",
+ opacity: 0.3,
+ strokeDasharray: "ShortDash",
+ snapX: true,
+ customSnapX: defaultCustomSnapX,
+ disableYCursor: false,
+ useXCursorShape: false,
+ xCursorShapeStroke: "#000000",
+ xCursorShapeOpacity: 0.5,
+ };
+
+ public static contextTypes = {
+ margin: PropTypes.object.isRequired,
+ ratio: PropTypes.number.isRequired,
+ // xScale for getting update event upon pan end, this is needed to get past the PureComponent shouldComponentUpdate
+ // xScale: PropTypes.func.isRequired,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private getXCursorShapeStroke(moreProps) {
+ const { xCursorShapeStroke } = this.props;
+ const { currentItem } = moreProps;
+ return xCursorShapeStroke instanceof Function
+ ? xCursorShapeStroke(currentItem)
+ : xCursorShapeStroke;
+ }
+
+ private getXCursorShapeFill(moreProps) {
+ const { xCursorShapeFill } = this.props;
+ const { currentItem } = moreProps;
+ return xCursorShapeFill instanceof Function
+ ? xCursorShapeFill(currentItem)
+ : xCursorShapeFill;
+ }
+
+ private getXCursorShape(moreProps/* , ctx */) {
+ const { height, xScale, currentItem, plotData } = moreProps;
+ const { xAccessor } = moreProps;
+ const xValue = xAccessor(currentItem);
+ const centerX = xScale(xValue);
+ const shapeWidth =
+ Math.abs(
+ xScale(xAccessor(last(plotData))) -
+ xScale(xAccessor(first(plotData))),
+ ) / (plotData.length - 1);
+ const xPos = centerX - shapeWidth / 2;
+
+ return { height, xPos, shapeWidth };
+ }
+
+ private getXYCursor(props, moreProps) {
+ const { mouseXY, currentItem, show, height, width } = moreProps;
+ const {
+ customSnapX,
+ stroke,
+ opacity,
+ strokeDasharray,
+ disableYCursor,
+ } = props;
+
+ if (!show || isNotDefined(currentItem)) {
+ return undefined;
+ }
+
+ const yCursor = {
+ x1: 0,
+ x2: width,
+ y1: mouseXY[1],
+ y2: mouseXY[1],
+ stroke,
+ strokeDasharray,
+ opacity,
+ id: "yCursor",
+ };
+ const x = customSnapX(props, moreProps);
+
+ const xCursor = {
+ x1: x,
+ x2: x,
+ y1: 0,
+ y2: height,
+ stroke,
+ strokeDasharray,
+ opacity,
+ id: "xCursor",
+ };
+
+ return disableYCursor ? [xCursor] : [yCursor, xCursor];
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const cursors = this.getXYCursor(this.props, moreProps);
+
+ if (cursors !== undefined) {
+ const { useXCursorShape } = this.props;
+
+ const { margin, ratio } = this.context;
+ const originX = 0.5 * ratio + margin.left;
+ const originY = 0.5 * ratio + margin.top;
+
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(ratio, ratio);
+
+ ctx.translate(originX, originY);
+
+ cursors.forEach((line) => {
+ const dashArray = getStrokeDasharray(line.strokeDasharray)
+ .split(",")
+ .map((d) => +d);
+ const xShapeFill = this.getXCursorShapeFill(moreProps);
+
+ if (useXCursorShape && line.id === "xCursor") {
+ const {
+ xCursorShapeOpacity,
+ xCursorShapeStrokeDasharray,
+ } = this.props;
+ const xShape = this.getXCursorShape(moreProps);
+
+ if (xCursorShapeStrokeDasharray != null) {
+ const xShapeStroke = this.getXCursorShapeStroke(
+ moreProps,
+ );
+ ctx.strokeStyle = hexToRGBA(
+ xShapeStroke,
+ xCursorShapeOpacity,
+ );
+ ctx.setLineDash(
+ getStrokeDasharray(xCursorShapeStrokeDasharray)
+ .split(",")
+ .map((d) => +d),
+ );
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle =
+ xShapeFill != null
+ ? hexToRGBA(xShapeFill, xCursorShapeOpacity)
+ : "rgba(0, 0, 0, 0)"; // ="transparent"
+
+ ctx.beginPath();
+ xCursorShapeStrokeDasharray == null
+ ? ctx.fillRect(
+ xShape.xPos,
+ 0,
+ xShape.shapeWidth,
+ xShape.height,
+ )
+ : ctx.rect(
+ xShape.xPos,
+ 0,
+ xShape.shapeWidth,
+ xShape.height,
+ );
+ ctx.fill();
+ } else {
+ ctx.strokeStyle = hexToRGBA(line.stroke, line.opacity);
+ ctx.setLineDash(dashArray);
+ ctx.beginPath();
+ ctx.moveTo(line.x1, line.y1);
+ ctx.lineTo(line.x2, line.y2);
+ }
+
+ ctx.stroke();
+ });
+
+ ctx.restore();
+ }
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const cursors = this.getXYCursor(this.props, moreProps);
+ if (cursors === undefined) {
+ return null;
+ }
+
+ const { className, useXCursorShape } = this.props;
+
+ return (
+
+ {cursors.map(({ strokeDasharray, id, ...rest }, idx) => {
+ if (useXCursorShape && id === "xCursor") {
+ const {
+ xCursorShapeOpacity,
+ xCursorShapeStrokeDasharray,
+ } = this.props;
+ const xShape = this.getXCursorShape(moreProps);
+ const xShapeFill = this.getXCursorShapeFill(moreProps);
+ const xShapeStroke = this.getXCursorShapeStroke(
+ moreProps,
+ );
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+ })}
+
+ );
+ }
+}
+
+export default Cursor;
diff --git a/packages/react-financial-charts/src/coordinates/EdgeCoordinate.tsx b/packages/react-financial-charts/src/coordinates/EdgeCoordinate.tsx
new file mode 100644
index 000000000..ba90d40df
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/EdgeCoordinate.tsx
@@ -0,0 +1,192 @@
+
+import * as React from "react";
+
+import { hexToRGBA, isDefined } from "../utils";
+
+const helper = (props) => {
+ const { coordinate: displayCoordinate, show, type, orient, edgeAt, hideLine } = props;
+ const { fill, opacity, fontFamily, fontSize, textFill, lineStroke, lineOpacity, arrowWidth } = props;
+ const { rectWidth, rectHeight } = props;
+ const { x1, y1, x2, y2 } = props;
+
+ if (!show) { return null; }
+
+ let edgeXRect;
+ let edgeYRect;
+ let edgeXText;
+ let edgeYText;
+
+ if (type === "horizontal") {
+
+ edgeXRect = (orient === "right") ? edgeAt + 1 : edgeAt - rectWidth - arrowWidth - 1;
+ edgeYRect = y1 - (rectHeight / 2);
+ edgeXText = (orient === "right") ? edgeAt + (rectWidth / 2) + arrowWidth : edgeAt - (rectWidth / 2) - arrowWidth;
+ edgeYText = y1;
+ } else {
+ edgeXRect = x1 - (rectWidth / 2);
+ edgeYRect = (orient === "bottom") ? edgeAt : edgeAt - rectHeight;
+ edgeXText = x1;
+ edgeYText = (orient === "bottom") ? edgeAt + (rectHeight / 2) : edgeAt - (rectHeight / 2);
+ }
+
+ let coordinateBase;
+ let coordinate;
+ const textAnchor = "middle";
+ if (isDefined(displayCoordinate)) {
+ coordinateBase = {
+ edgeXRect, edgeYRect, rectHeight, rectWidth, fill, opacity, arrowWidth,
+ };
+ coordinate = {
+ edgeXText, edgeYText, textAnchor, fontFamily, fontSize, textFill, displayCoordinate,
+ };
+ }
+
+ const line = hideLine ? undefined : {
+ opacity: lineOpacity, stroke: lineStroke, x1, y1, x2, y2,
+ };
+ return {
+ coordinateBase, coordinate, line, orient,
+ };
+};
+
+interface EdgeCoordinateProps {
+ className?: string;
+ type: "vertical" | "horizontal";
+ coordinate: any;
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+ orient?: "bottom" | "top" | "left" | "right";
+ rectWidth?: number;
+ hideLine?: boolean;
+ fill?: string;
+ opacity?: number;
+ fontFamily: string;
+ fontSize: number;
+}
+
+export class EdgeCoordinate extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-edgecoordinate",
+ orient: "left",
+ hideLine: false,
+ fill: "#8a8a8a",
+ opacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ textFill: "#FFFFFF",
+ lineStroke: "#000000",
+ lineOpacity: 0.3,
+ arrowWidth: 10,
+ };
+
+ public static drawOnCanvasStatic = (ctx, props) => {
+ props = { ...EdgeCoordinate.defaultProps, ...props };
+
+ const edge = helper(props);
+
+ if (edge === null) { return; }
+
+ if (isDefined(edge.coordinateBase)) {
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
+
+ ctx.fillStyle = hexToRGBA(edge.coordinateBase.fill, edge.coordinateBase.opacity);
+
+ const x = edge.coordinateBase.edgeXRect;
+ const y = edge.coordinateBase.edgeYRect;
+
+ ctx.beginPath();
+
+ if (edge.orient === "right") {
+ ctx.moveTo(x, y + rectHeight / 2);
+ ctx.lineTo(x + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight);
+ ctx.lineTo(x + arrowWidth, y + rectHeight);
+ ctx.closePath();
+ } else if (edge.orient === "left") {
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + rectWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight / 2);
+ ctx.lineTo(x + rectWidth, y + rectHeight);
+ ctx.lineTo(x, y + rectHeight);
+ ctx.closePath();
+ } else {
+ ctx.rect(x, y, rectWidth, rectHeight);
+ }
+ ctx.fill();
+
+ ctx.font = `${edge.coordinate.fontSize}px ${edge.coordinate.fontFamily}`;
+ ctx.fillStyle = edge.coordinate.textFill;
+ ctx.textAlign = edge.coordinate.textAnchor === "middle" ? "center" : edge.coordinate.textAnchor;
+ ctx.textBaseline = "middle";
+
+ ctx.fillText(edge.coordinate.displayCoordinate, edge.coordinate.edgeXText, edge.coordinate.edgeYText);
+ }
+
+ if (edge.line !== undefined) {
+ ctx.strokeStyle = hexToRGBA(edge.line.stroke, edge.line.opacity);
+
+ ctx.beginPath();
+ ctx.moveTo(edge.line.x1, edge.line.y1);
+ ctx.lineTo(edge.line.x2, edge.line.y2);
+ ctx.stroke();
+ }
+ }
+
+ public render() {
+ const { className } = this.props;
+
+ const edge = helper(this.props);
+ if (edge === null) {
+ return null;
+ }
+ let line;
+ let coordinateBase;
+ let coordinate;
+
+ if (edge.line !== undefined) {
+ line = ;
+ }
+
+ if (isDefined(edge.coordinateBase)) {
+
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
+
+ const path = edge.orient === "left"
+ ? `M0,0L0,${rectHeight}L${rectWidth},${rectHeight}L${rectWidth + arrowWidth},10L${rectWidth},0L0,0L0,0`
+ : `M0,${arrowWidth}L${arrowWidth},${rectHeight}L${rectWidth + arrowWidth},${rectHeight}L${rectWidth + arrowWidth},0L${arrowWidth},0L0,${arrowWidth}`;
+
+ coordinateBase = edge.orient === "left" || edge.orient === "right"
+ ?
+
+
+ : ;
+
+ coordinate = ({edge.coordinate.displayCoordinate});
+ }
+ return (
+
+ {line}
+ {coordinateBase}
+ {coordinate}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/EdgeCoordinateV2.tsx b/packages/react-financial-charts/src/coordinates/EdgeCoordinateV2.tsx
new file mode 100644
index 000000000..84cafd6fc
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/EdgeCoordinateV2.tsx
@@ -0,0 +1,153 @@
+import * as React from "react";
+
+import { hexToRGBA, isDefined } from "../utils";
+
+export function renderSVG(props) {
+ const { className } = props;
+
+ const edge = helper(props);
+ if (edge === null) { return null; }
+ let line;
+ let coordinateBase;
+ let coordinate;
+
+ if (edge.line !== undefined && isDefined(edge.line)) {
+ line = ;
+ }
+
+ if (isDefined(edge.coordinateBase)) {
+
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
+
+ const path = edge.orient === "left"
+ ? `M0,0L0,${rectHeight}L${rectWidth},${rectHeight}L${rectWidth + arrowWidth},10L${rectWidth},0L0,0L0,0`
+ : `M0,${arrowWidth}L${arrowWidth},${rectHeight}L${rectWidth + arrowWidth},${rectHeight}L${rectWidth + arrowWidth},0L${arrowWidth},0L0,${arrowWidth}`;
+
+ coordinateBase = edge.orient === "left" || edge.orient === "right"
+ ?
+
+
+ : ;
+
+ coordinate = ({edge.coordinate.displayCoordinate});
+ }
+ return (
+
+ {line}
+ {coordinateBase}
+ {coordinate}
+
+ );
+}
+
+function helper(props) {
+ const { coordinate: displayCoordinate, show, type, orient, edgeAt, hideLine } = props;
+ const { fill, opacity, fontFamily, fontSize, textFill, lineStroke, lineOpacity, arrowWidth } = props;
+ const { rectWidth, rectHeight } = props;
+ const { x1, y1, x2, y2, dx } = props;
+
+ if (!show) {
+ return null;
+ }
+
+ let edgeXRect;
+ let edgeYRect;
+ let edgeXText;
+ let edgeYText;
+
+ if (type === "horizontal") {
+
+ edgeXRect = dx + ((orient === "right") ? edgeAt + 1 : edgeAt - rectWidth - arrowWidth - 1);
+ edgeYRect = y1 - (rectHeight / 2);
+ edgeXText = dx + ((orient === "right") ? edgeAt + (rectWidth / 2) + arrowWidth : edgeAt - (rectWidth / 2) - arrowWidth);
+ edgeYText = y1;
+ } else {
+ edgeXRect = x1 - (rectWidth / 2);
+ edgeYRect = (orient === "bottom") ? edgeAt : edgeAt - rectHeight;
+ edgeXText = x1;
+ edgeYText = (orient === "bottom") ? edgeAt + (rectHeight / 2) : edgeAt - (rectHeight / 2);
+ }
+ let coordinateBase;
+ let coordinate;
+ const textAnchor = "middle";
+ if (isDefined(displayCoordinate)) {
+ coordinateBase = {
+ edgeXRect, edgeYRect, rectHeight, rectWidth, fill, opacity, arrowWidth,
+ };
+ coordinate = {
+ edgeXText, edgeYText, textAnchor, fontFamily, fontSize, textFill, displayCoordinate,
+ };
+ }
+
+ const line = hideLine ? undefined : {
+ opacity: lineOpacity, stroke: lineStroke, x1, y1, x2, y2,
+ };
+ return {
+ coordinateBase, coordinate, line, orient,
+ };
+}
+
+export function drawOnCanvas(ctx, props) {
+ const edge = helper(props);
+
+ if (edge === null) { return; }
+
+ if (isDefined(edge.coordinateBase)) {
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
+
+ ctx.fillStyle = hexToRGBA(edge.coordinateBase.fill, edge.coordinateBase.opacity);
+
+ const x = edge.coordinateBase.edgeXRect;
+ const y = edge.coordinateBase.edgeYRect;
+
+ ctx.beginPath();
+
+ if (edge.orient === "right") {
+ ctx.moveTo(x, y + rectHeight / 2);
+ ctx.lineTo(x + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight);
+ ctx.lineTo(x + arrowWidth, y + rectHeight);
+ ctx.closePath();
+ } else if (edge.orient === "left") {
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + rectWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight / 2);
+ ctx.lineTo(x + rectWidth, y + rectHeight);
+ ctx.lineTo(x, y + rectHeight);
+ ctx.closePath();
+ } else {
+ ctx.rect(x, y, rectWidth, rectHeight);
+ }
+ ctx.fill();
+
+ ctx.font = `${edge.coordinate.fontSize}px ${edge.coordinate.fontFamily}`;
+ ctx.fillStyle = edge.coordinate.textFill;
+ ctx.textAlign = edge.coordinate.textAnchor === "middle" ? "center" : edge.coordinate.textAnchor;
+ ctx.textBaseline = "middle";
+
+ ctx.fillText(edge.coordinate.displayCoordinate, edge.coordinate.edgeXText, edge.coordinate.edgeYText);
+ }
+ if (edge.line !== undefined && isDefined(edge.line)) {
+ ctx.strokeStyle = hexToRGBA(edge.line.stroke, edge.line.opacity);
+
+ ctx.beginPath();
+ ctx.moveTo(edge.line.x1, edge.line.y1);
+ ctx.lineTo(edge.line.x2, edge.line.y2);
+ ctx.stroke();
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/EdgeCoordinateV3.tsx b/packages/react-financial-charts/src/coordinates/EdgeCoordinateV3.tsx
new file mode 100644
index 000000000..35d3693ee
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/EdgeCoordinateV3.tsx
@@ -0,0 +1,307 @@
+import * as React from "react";
+
+import { getStrokeDasharray, hexToRGBA, isDefined } from "../utils";
+
+export function renderSVG(props) {
+ const { className } = props;
+
+ const edge = helper(props);
+ if (edge === null) { return null; }
+ let line;
+ let coordinateBase;
+ let coordinate;
+
+ if (edge.line !== undefined && isDefined(edge.line)) {
+ line = (
+
+ );
+ }
+ if (isDefined(edge.coordinateBase)) {
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
+
+ const path =
+ edge.orient === "left"
+ ? `M0,0L0,${rectHeight}L${rectWidth},${rectHeight}L${rectWidth +
+ arrowWidth},10L${rectWidth},0L0,0L0,0`
+ : `M0,${arrowWidth}L${arrowWidth},${rectHeight}L${rectWidth +
+ arrowWidth},${rectHeight}L${rectWidth +
+ arrowWidth},0L${arrowWidth},0L0,${arrowWidth}`;
+
+ coordinateBase =
+ edge.orient === "left" || edge.orient === "right" ? (
+
+
+
+ ) : (
+
+ );
+
+ coordinate = (
+
+ {edge.coordinate.displayCoordinate}
+
+ );
+ }
+ return (
+
+ {line}
+ {coordinateBase}
+ {coordinate}
+
+ );
+}
+/* eslint-enable react/prop-types */
+
+function helper(props) {
+ const {
+ coordinate: displayCoordinate,
+ show,
+ type,
+ orient,
+ edgeAt,
+ hideLine,
+ lineStrokeDasharray,
+ } = props;
+ const {
+ fill,
+ opacity,
+ fontFamily,
+ fontSize,
+ textFill,
+ lineStroke,
+ lineOpacity,
+ } = props;
+ const { stroke, strokeOpacity, strokeWidth } = props;
+ const { arrowWidth, rectWidth, rectHeight, rectRadius } = props;
+ const { x1, y1, x2, y2, dx } = props;
+
+ if (!show) { return null; }
+
+ let coordinateBase;
+ let coordinate;
+ if (isDefined(displayCoordinate)) {
+ const textAnchor = "middle";
+ // TODO: Below it is necessary to implement logic for the possibility of alignment from the right or from the left.
+
+ let edgeXRect;
+ let edgeYRect;
+ let edgeXText;
+ let edgeYText;
+
+ if (type === "horizontal") {
+ edgeXRect =
+ dx + (orient === "right" ? edgeAt + 1 : edgeAt - rectWidth - 1);
+ edgeYRect = y1 - rectHeight / 2 - strokeWidth;
+ edgeXText =
+ dx +
+ (orient === "right"
+ ? edgeAt + rectWidth / 2
+ : edgeAt - rectWidth / 2);
+ edgeYText = y1;
+ } else {
+ const dy = orient === "bottom" ? strokeWidth - 1 : -strokeWidth + 1;
+ edgeXRect = x1 - rectWidth / 2;
+ edgeYRect =
+ (orient === "bottom" ? edgeAt : edgeAt - rectHeight) + dy;
+ edgeXText = x1;
+ edgeYText =
+ (orient === "bottom"
+ ? edgeAt + rectHeight / 2
+ : edgeAt - rectHeight / 2) + dy;
+ }
+
+ coordinateBase = {
+ edgeXRect,
+ edgeYRect,
+ rectHeight: rectHeight + strokeWidth,
+ rectWidth,
+ rectRadius,
+ fill,
+ opacity,
+ arrowWidth,
+ stroke,
+ strokeOpacity,
+ strokeWidth,
+ };
+ coordinate = {
+ edgeXText,
+ edgeYText,
+ textAnchor,
+ fontFamily,
+ fontSize,
+ textFill,
+ displayCoordinate,
+ };
+ }
+
+ const line = hideLine
+ ? undefined
+ : {
+ opacity: lineOpacity,
+ stroke: lineStroke,
+ strokeDasharray: lineStrokeDasharray,
+ x1,
+ y1,
+ x2,
+ y2,
+ };
+
+ return {
+ coordinateBase,
+ coordinate,
+ line,
+ orient,
+ };
+}
+
+export function drawOnCanvas(ctx, props) {
+ const { fontSize, fontFamily } = props;
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.textBaseline = "middle";
+ const width = Math.round(ctx.measureText(props.coordinate).width + 10);
+
+ const edge = helper({ ...props, rectWidth: width });
+
+ if (edge === null) { return; }
+
+ if (edge.line !== undefined && isDefined(edge.line)) {
+ const dashArray = getStrokeDasharray(edge.line.strokeDasharray)
+ .split(",")
+ .map((d) => +d);
+ ctx.setLineDash(dashArray);
+ ctx.strokeStyle = hexToRGBA(edge.line.stroke, edge.line.opacity);
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.moveTo(edge.line.x1, edge.line.y1);
+ ctx.lineTo(edge.line.x2, edge.line.y2);
+ ctx.stroke();
+ }
+
+ ctx.setLineDash([]);
+ if (isDefined(edge.coordinateBase)) {
+ const {
+ rectWidth,
+ rectHeight,
+ rectRadius,
+ arrowWidth,
+ } = edge.coordinateBase;
+
+ ctx.fillStyle = hexToRGBA(
+ edge.coordinateBase.fill,
+ edge.coordinateBase.opacity,
+ );
+ if (isDefined(edge.coordinateBase.stroke)) {
+ ctx.strokeStyle = hexToRGBA(
+ edge.coordinateBase.stroke,
+ edge.coordinateBase.strokeOpacity,
+ );
+ ctx.lineWidth = edge.coordinateBase.strokeWidth;
+ }
+
+ let x = edge.coordinateBase.edgeXRect;
+ const y = edge.coordinateBase.edgeYRect;
+ const halfHeight = rectHeight / 2;
+
+ ctx.beginPath();
+ if (edge.orient === "right") {
+ x -= arrowWidth;
+ ctx.moveTo(x, y + halfHeight);
+ ctx.lineTo(x + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight);
+ ctx.lineTo(x + arrowWidth, y + rectHeight);
+ ctx.closePath();
+ } else if (edge.orient === "left") {
+ // x += arrowWidth;
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + rectWidth, y);
+ ctx.lineTo(x + rectWidth + arrowWidth, y + halfHeight);
+ ctx.lineTo(x + rectWidth, y + rectHeight);
+ ctx.lineTo(x, y + rectHeight);
+ ctx.closePath();
+ } else {
+ // console.error(x, y, rectWidth, rectHeight)
+ if (rectRadius) {
+ roundRect(ctx, x, y, rectWidth, rectHeight, 3);
+ } else {
+ ctx.rect(x, y, rectWidth, rectHeight);
+ }
+ }
+ ctx.fill();
+
+ if (isDefined(edge.coordinateBase.stroke)) {
+ ctx.stroke();
+ }
+
+ ctx.fillStyle = edge.coordinate.textFill;
+ ctx.textAlign =
+ edge.coordinate.textAnchor === "middle"
+ ? "center"
+ : edge.coordinate.textAnchor;
+ ctx.fillText(
+ edge.coordinate.displayCoordinate,
+ edge.coordinate.edgeXText,
+ edge.coordinate.edgeYText,
+ );
+ }
+}
+
+function roundRect(ctx, x, y, width, height, radius) {
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+}
+
+// export default EdgeCoordinate;
diff --git a/packages/react-financial-charts/src/coordinates/EdgeIndicator.tsx b/packages/react-financial-charts/src/coordinates/EdgeIndicator.tsx
new file mode 100644
index 000000000..698749552
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/EdgeIndicator.tsx
@@ -0,0 +1,136 @@
+import { format } from "d3-format";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { drawOnCanvas, renderSVG } from "./EdgeCoordinateV3";
+
+import { first, functor, isDefined, last, noop, strokeDashTypes } from "../utils";
+
+interface EdgeIndicatorProps {
+ yAccessor?: any; // func
+ type?: "horizontal";
+ className?: string;
+ fill?: string | any; // func
+ lineStroke?: string | any; // func
+ textFill?: string | any; // func
+ itemType: "first" | "last";
+ orient?: "left" | "right";
+ edgeAt?: "left" | "right";
+ displayFormat?: any; // func
+ rectHeight?: number;
+ rectWidth?: number;
+ arrowWidth?: number;
+ lineStrokeDasharray?: strokeDashTypes;
+}
+
+export class EdgeIndicator extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-edgeindicator",
+ type: "horizontal",
+ orient: "left",
+ edgeAt: "left",
+ textFill: "#FFFFFF",
+ displayFormat: format(".2f"),
+ yAxisPad: 0,
+ rectHeight: 20,
+ rectWidth: 50,
+ arrowWidth: 10,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ dx: 0,
+ hideLine: false,
+ fill: "#8a8a8a",
+ opacity: 1,
+ stroke: noop,
+ strokeOpacity: 1,
+ strokeWidth: 3,
+ lineStroke: "#000000",
+ lineOpacity: 0.3,
+ lineStrokeDasharray: "ShortDash",
+ };
+
+ public render() {
+ return ;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const edge = this.helper(this.props, moreProps);
+ const props = {
+ ...this.props,
+ ...edge,
+ };
+ drawOnCanvas(ctx, props);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const edge = this.helper(this.props, moreProps);
+ const props = {
+ ...this.props,
+ ...edge,
+ };
+ return renderSVG(props);
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const { itemType, yAccessor } = props;
+ const { plotData } = moreProps;
+
+ const item = itemType === "first"
+ ? first(plotData, yAccessor)
+ : last(plotData, yAccessor);
+
+ const edge = isDefined(item)
+ ? this.getEdge(props, moreProps, item)
+ : null;
+
+ return edge;
+ }
+
+ private readonly getEdge = (props, moreProps, item) => {
+ const { type: edgeType, displayFormat, edgeAt, yAxisPad, orient, lineStroke } = props;
+
+ const { yAccessor, fill, textFill, rectHeight, rectWidth, arrowWidth } = props;
+ const { fontFamily, fontSize } = props;
+ const { stroke } = props;
+
+ const { xScale, chartConfig: { yScale }, xAccessor, width } = moreProps;
+
+ const yValue = yAccessor(item);
+ const xValue = xAccessor(item);
+
+ const x1 = Math.round(xScale(xValue));
+ const y1 = Math.round(yScale(yValue));
+
+ const [left, right] = [0, width];
+ const edgeX = edgeAt === "left"
+ ? left - yAxisPad
+ : right + yAxisPad;
+
+ return {
+ coordinate: displayFormat(yValue),
+ show: true,
+ type: edgeType,
+ orient,
+ edgeAt: edgeX,
+ fill: functor(fill)(item),
+ lineStroke: functor(lineStroke)(item),
+ stroke: functor(stroke)(item),
+ fontFamily, fontSize,
+ textFill: functor(textFill)(item),
+ rectHeight, rectWidth, arrowWidth,
+ x1,
+ y1,
+ x2: right,
+ y2: y1,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/MouseCoordinateX.tsx b/packages/react-financial-charts/src/coordinates/MouseCoordinateX.tsx
new file mode 100644
index 000000000..90242227e
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/MouseCoordinateX.tsx
@@ -0,0 +1,131 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import { drawOnCanvas, renderSVG } from "./EdgeCoordinateV3";
+
+import { isNotDefined } from "../utils";
+
+interface MouseCoordinateXProps {
+ readonly displayFormat: any; // func
+ readonly yAxisPad?: number;
+ readonly rectWidth?: number;
+ readonly rectHeight?: number;
+ readonly orient?: "bottom" | "top" | "left" | "right";
+ readonly at?: "bottom" | "top" | "left" | "right";
+ readonly fill?: string;
+ readonly opacity?: number;
+ readonly fontFamily?: string;
+ readonly fontSize?: number;
+ readonly textFill?: string;
+ readonly snapX?: boolean;
+}
+
+const defaultCustomX = (props: MouseCoordinateXProps, moreProps) => {
+ const { xScale, xAccessor, currentItem, mouseXY } = moreProps;
+ const { snapX } = props;
+ const x = snapX
+ ? xScale(xAccessor(currentItem))
+ : mouseXY[0];
+
+ const { displayXAccessor } = moreProps;
+ const { displayFormat } = props;
+ const coordinate = snapX
+ ? displayFormat(displayXAccessor(currentItem))
+ : displayFormat(xScale.invert(x));
+ return { x, coordinate };
+};
+
+export class MouseCoordinateX extends React.Component {
+
+ public static defaultProps = {
+ yAxisPad: 0,
+ rectWidth: 80,
+ rectHeight: 20,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ orient: "bottom",
+ at: "bottom",
+ fill: "#525252",
+ opacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ textFill: "#FFFFFF",
+ snapX: true,
+ customX: defaultCustomX,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ if (isNotDefined(props)) { return null; }
+
+ drawOnCanvas(ctx, props);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ if (isNotDefined(props)) { return null; }
+
+ return renderSVG(props);
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const { show, currentItem } = moreProps;
+ const { chartConfig: { height } } = moreProps;
+
+ if (isNotDefined(currentItem)) { return null; }
+
+ const { customX } = props;
+
+ const { orient, at } = props;
+ const { stroke, strokeOpacity, strokeWidth } = props;
+ const { rectRadius, rectWidth, rectHeight } = props;
+ const { fill, opacity, fontFamily, fontSize, textFill } = props;
+
+ const edgeAt = (at === "bottom")
+ ? height
+ : 0;
+
+ const {
+ x,
+ coordinate,
+ } = customX(props, moreProps);
+
+ const type = "vertical";
+ const y1 = 0;
+ const y2 = height;
+ const hideLine = true;
+
+ const coordinateProps = {
+ coordinate,
+ show,
+ type,
+ orient,
+ edgeAt,
+ hideLine,
+ fill, opacity, fontFamily, fontSize, textFill,
+ stroke, strokeOpacity, strokeWidth,
+ rectWidth,
+ rectHeight,
+ rectRadius,
+ arrowWidth: 0,
+ x1: x,
+ x2: x,
+ y1,
+ y2,
+ };
+ return coordinateProps;
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/MouseCoordinateXV2.tsx b/packages/react-financial-charts/src/coordinates/MouseCoordinateXV2.tsx
new file mode 100644
index 000000000..854040e76
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/MouseCoordinateXV2.tsx
@@ -0,0 +1,157 @@
+
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+
+interface MouseCoordinateXV2Props {
+ xPosition?: any; // func
+ drawCoordinate?: any; // func
+ displayFormat: any; // func
+ at?: "bottom" | "top";
+ orient?: "bottom" | "top";
+ text?: {
+ fontStyle: string,
+ fontWeight: string,
+ fontFamily: string,
+ fontSize: number,
+ fill: string | any, // func
+ };
+ bg: {
+ fill: string | any, // func
+ stroke: string,
+ strokeWidth: number,
+ padding: {
+ left: number,
+ right: number,
+ top: number,
+ bottom: number,
+ },
+ };
+ dx?: number;
+ dy?: number;
+}
+
+export class MouseCoordinateXV2 extends React.Component {
+
+ public static defaultProps = {
+ xPosition: defaultXPosition,
+ drawCoordinate: defaultDrawCoordinate,
+ at: "bottom",
+ orient: "bottom",
+ text: {
+ fontStyle: "",
+ fontWeight: "",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ fill: "rgb(35, 35, 35)",
+ },
+ bg: {
+ fill: "rgb(255, 255, 255)",
+ stroke: "rgb(35, 35, 35)",
+ strokeWidth: 1,
+ padding: {
+ left: 7,
+ right: 7,
+ top: 4,
+ bottom: 4,
+ },
+ },
+ dx: 7,
+ dy: 7,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { show, currentItem } = moreProps;
+ const { drawCoordinate } = this.props;
+
+ if (show && currentItem != null) {
+ const shape = getXCoordinateInfo(ctx, this.props, moreProps);
+ drawCoordinate(ctx, shape, this.props, moreProps);
+ }
+ }
+}
+
+function defaultXPosition(props, moreProps) {
+ const { currentItem, xAccessor } = moreProps;
+ return xAccessor(currentItem);
+}
+
+function getXCoordinateInfo(ctx, props, moreProps) {
+ const { xPosition } = props;
+ const xValue = xPosition(props, moreProps);
+ const { at, displayFormat } = props;
+ const { text } = props;
+ const { xScale, chartConfig: { height } } = moreProps;
+ ctx.font = `${text.fontStyle} ${text.fontWeight} ${text.fontSize}px ${text.fontFamily}`;
+
+ const t = displayFormat(xValue);
+ const textWidth = ctx.measureText(t).width;
+
+ const y = at === "bottom" ? height : 0;
+ const x = Math.round(xScale(xValue));
+
+ return {
+ x,
+ y,
+ textWidth,
+ text: t,
+ };
+}
+
+function defaultDrawCoordinate(
+ ctx,
+ shape,
+ props,
+ moreProps,
+) {
+ const { x, y, textWidth, text } = shape;
+ const { orient, dx, dy } = props;
+
+ const {
+ bg: { padding, fill, stroke, strokeWidth },
+ text: { fontSize, fill: textFill },
+ } = props;
+
+ ctx.textAlign = "center";
+
+ const sign = orient === "top" ? -1 : 1;
+ const halfWidth = Math.round(textWidth / 2 + padding.right);
+ const height = Math.round(fontSize + padding.top + padding.bottom);
+
+ ctx.strokeStyle = typeof stroke === "function" ? stroke(moreProps, ctx) : stroke;
+ ctx.fillStyle = typeof fill === "function" ? fill(moreProps, ctx) : fill;
+ ctx.lineWidth = typeof strokeWidth === "function" ? strokeWidth(moreProps) : strokeWidth;
+
+ ctx.beginPath();
+
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + dx, y + sign * dy);
+ ctx.lineTo(x + halfWidth, y + sign * dy);
+ ctx.lineTo(x + halfWidth, y + sign * (dy + height));
+ ctx.lineTo(x - halfWidth, y + sign * (dy + height));
+ ctx.lineTo(x - halfWidth, y + sign * dy);
+ ctx.lineTo(x - dx, y + sign * dy);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.fillStyle = typeof textFill === "function" ? textFill(moreProps, ctx) : textFill;
+
+ ctx.textBaseline = orient === "top" ? "alphabetic" : "hanging";
+ const pad = orient === "top" ? padding.bottom : padding.top;
+
+ ctx.fillText(text, x, y + sign * (dy + pad + 2));
+}
diff --git a/packages/react-financial-charts/src/coordinates/MouseCoordinateY.tsx b/packages/react-financial-charts/src/coordinates/MouseCoordinateY.tsx
new file mode 100644
index 000000000..303a39346
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/MouseCoordinateY.tsx
@@ -0,0 +1,135 @@
+
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import { drawOnCanvas, renderSVG } from "./EdgeCoordinateV3";
+
+import { isNotDefined } from "../utils";
+
+interface MouseCoordinateYProps {
+ displayFormat: any; // func
+ yAxisPad?: number;
+ rectWidth?: number;
+ rectHeight?: number;
+ orient?: "bottom" | "top" | "left" | "right";
+ at?: "bottom" | "top" | "left" | "right";
+ dx?: number;
+ fill?: string;
+ opacity?: number;
+ fontFamily?: string;
+ fontSize?: number;
+ textFill?: string;
+}
+
+export class MouseCoordinateY extends React.Component {
+
+ public static defaultProps = {
+ yAxisPad: 0,
+ rectWidth: 50,
+ rectHeight: 20,
+ orient: "left",
+ at: "left",
+ dx: 0,
+ arrowWidth: 10,
+ fill: "#525252",
+ opacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ textFill: "#FFFFFF",
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ if (isNotDefined(props)) { return null; }
+
+ return renderSVG(props);
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ if (isNotDefined(props)) { return null; }
+
+ drawOnCanvas(ctx, props);
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const { chartId } = moreProps;
+ const { currentCharts, mouseXY } = moreProps;
+
+ if (isNotDefined(mouseXY)) { return null; }
+ if (currentCharts.indexOf(chartId) < 0) { return null; }
+
+ const { show } = moreProps;
+ if (!show) { return null; }
+
+ const y = mouseXY[1];
+ const { chartConfig: { yScale } } = moreProps;
+ const { displayFormat } = props;
+
+ const coordinate = displayFormat(yScale.invert(y));
+
+ return getYCoordinate(y, coordinate, props, moreProps);
+ }
+}
+
+export function getYCoordinate(y, displayValue, props, moreProps) {
+ const { width } = moreProps;
+
+ const { orient, at, rectWidth, rectHeight, dx } = props;
+ const { fill, opacity, fontFamily, fontSize, textFill, arrowWidth } = props;
+ const { stroke, strokeOpacity, strokeWidth } = props;
+
+ const x1 = 0;
+ const x2 = width;
+ const edgeAt = (at === "right")
+ ? width
+ : 0;
+
+ const type = "horizontal";
+ const hideLine = true;
+
+ const coordinateProps = {
+ coordinate: displayValue,
+ show: true,
+ type,
+ orient,
+ edgeAt,
+ hideLine,
+ fill,
+ opacity,
+
+ fontFamily,
+ fontSize,
+ textFill,
+
+ stroke,
+ strokeOpacity,
+ strokeWidth,
+
+ rectWidth,
+ rectHeight,
+
+ arrowWidth,
+ dx,
+ x1,
+ x2,
+ y1: y,
+ y2: y,
+ };
+ return coordinateProps;
+}
diff --git a/packages/react-financial-charts/src/coordinates/PriceCoordinate.tsx b/packages/react-financial-charts/src/coordinates/PriceCoordinate.tsx
new file mode 100644
index 000000000..8bfc9f2b5
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/PriceCoordinate.tsx
@@ -0,0 +1,126 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { functor, strokeDashTypes } from "../utils";
+import { drawOnCanvas, renderSVG } from "./EdgeCoordinateV3";
+
+interface PriceCoordinateProps {
+ displayFormat: any; // func
+ yAxisPad?: number;
+ rectWidth?: number;
+ rectHeight?: number;
+ orient?: "bottom" | "top" | "left" | "right";
+ at?: "bottom" | "top" | "left" | "right";
+ price?: number;
+ dx?: number;
+ arrowWidth?: number;
+ opacity?: number;
+ lineOpacity?: number;
+ lineStroke?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ fill?: string | any; // func
+ strokeDasharray?: strokeDashTypes;
+ stroke?: string;
+ strokeOpacity?: number;
+ strokeWidth?: number;
+ textFill?: string | any; // func
+}
+
+export class PriceCoordinate extends React.Component {
+
+ public static defaultProps = {
+ yAxisPad: 0,
+ rectWidth: 50,
+ rectHeight: 20,
+ orient: "left",
+ at: "left",
+ price: 0,
+ dx: 0,
+ arrowWidth: 0,
+ fill: "#BAB8b8",
+ opacity: 1,
+ lineOpacity: 0.2,
+ lineStroke: "#000000",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 13,
+ textFill: "#FFFFFF",
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ strokeDasharray: "Solid",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ drawOnCanvas(ctx, props);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const props = this.helper(this.props, moreProps);
+ return renderSVG(props);
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const { width } = moreProps;
+ const { chartConfig: { yScale } } = moreProps;
+ const [lowerYValue, upperYValue] = yScale.domain();
+
+ const { price, stroke, strokeDasharray, strokeOpacity, strokeWidth } = props;
+ const { orient, at, rectWidth, rectHeight, displayFormat, dx } = props;
+ const { fill, opacity, fontFamily, fontSize, textFill, arrowWidth, lineOpacity, lineStroke } = props;
+
+ const x1 = 0;
+ const x2 = width;
+ const edgeAt = (at === "right")
+ ? width
+ : 0;
+
+ const type = "horizontal";
+
+ const y = yScale(price);
+ const show = (price <= upperYValue && price >= lowerYValue);
+
+ const coordinate = displayFormat(yScale.invert(y));
+ const hideLine = false;
+
+ const coordinateProps = {
+ coordinate,
+ show,
+ type,
+ orient,
+ edgeAt,
+ hideLine,
+ lineOpacity,
+ lineStroke,
+ lineStrokeDasharray: strokeDasharray,
+ stroke,
+ strokeOpacity,
+ strokeWidth,
+ fill: functor(fill)(price),
+ textFill: functor(textFill)(price),
+ opacity, fontFamily, fontSize,
+ rectWidth,
+ rectHeight,
+ arrowWidth,
+ dx,
+ x1,
+ x2,
+ y1: y,
+ y2: y,
+ };
+ return coordinateProps;
+ }
+}
diff --git a/packages/react-financial-charts/src/coordinates/index.ts b/packages/react-financial-charts/src/coordinates/index.ts
new file mode 100644
index 000000000..b8e14d1c0
--- /dev/null
+++ b/packages/react-financial-charts/src/coordinates/index.ts
@@ -0,0 +1,8 @@
+export * from "./EdgeIndicator";
+export * from "./CurrentCoordinate";
+export * from "./MouseCoordinateX";
+export { MouseCoordinateXV2 } from "./MouseCoordinateXV2";
+
+export { MouseCoordinateY } from "./MouseCoordinateY";
+export * from "./CrossHairCursor";
+export * from "./PriceCoordinate";
diff --git a/packages/react-financial-charts/src/index.ts b/packages/react-financial-charts/src/index.ts
new file mode 100644
index 000000000..579ae713a
--- /dev/null
+++ b/packages/react-financial-charts/src/index.ts
@@ -0,0 +1,2 @@
+export { ChartCanvas } from "./ChartCanvas";
+export { Chart } from "./Chart";
diff --git a/packages/react-financial-charts/src/indicator/atr.ts b/packages/react-financial-charts/src/indicator/atr.ts
new file mode 100644
index 000000000..f56da489a
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/atr.ts
@@ -0,0 +1,33 @@
+import { atr } from "../calculator";
+import { merge, rebind } from "../utils";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "ATR";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = atr();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.atr = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/baseIndicator.ts b/packages/react-financial-charts/src/indicator/baseIndicator.ts
new file mode 100644
index 000000000..c606a5745
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/baseIndicator.ts
@@ -0,0 +1,49 @@
+import { overlayColors } from "../utils";
+
+let i = 0;
+
+export default function () {
+
+ let id = i++;
+ let accessor;
+ let stroke;
+ let fill;
+ let echo;
+ let type;
+
+ // tslint:disable-next-line: no-empty
+ function baseIndicator() {
+ }
+
+ baseIndicator.id = function (x) {
+ if (!arguments.length) { return id; }
+ id = x;
+ return baseIndicator;
+ };
+ baseIndicator.accessor = function (x) {
+ if (!arguments.length) { return accessor; }
+ accessor = x;
+ return baseIndicator;
+ };
+ baseIndicator.stroke = function (x) {
+ if (!arguments.length) { return !stroke ? stroke = overlayColors(id) : stroke; }
+ stroke = x;
+ return baseIndicator;
+ };
+ baseIndicator.fill = function (x) {
+ if (!arguments.length) { return !fill ? fill = overlayColors(id) : fill; }
+ fill = x;
+ return baseIndicator;
+ };
+ baseIndicator.echo = function (x) {
+ if (!arguments.length) { return echo; }
+ echo = x;
+ return baseIndicator;
+ };
+ baseIndicator.type = function (x) {
+ if (!arguments.length) { return type; }
+ type = x;
+ return baseIndicator;
+ };
+ return baseIndicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/bollingerBand.ts b/packages/react-financial-charts/src/indicator/bollingerBand.ts
new file mode 100644
index 000000000..cb92ca79d
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/bollingerBand.ts
@@ -0,0 +1,33 @@
+import { merge, rebind } from "../utils";
+
+import { bollingerband } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "BollingerBand";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = bollingerband();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.bollingerBand = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/change.ts b/packages/react-financial-charts/src/indicator/change.ts
new file mode 100644
index 000000000..bd54e35d1
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/change.ts
@@ -0,0 +1,35 @@
+import { merge, rebind } from "../utils";
+
+import { change } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "Change";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = change();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => {
+ datum.absoluteChange = i.absoluteChange;
+ datum.percentChange = i.percentChange;
+ });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/compare.ts b/packages/react-financial-charts/src/indicator/compare.ts
new file mode 100644
index 000000000..f019efcff
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/compare.ts
@@ -0,0 +1,36 @@
+
+import { merge, rebind } from "../utils";
+
+import { compare } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "Compare";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.compare);
+
+ const underlyingAlgorithm = compare();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.compare = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/defaultOptionsForAppearance.ts b/packages/react-financial-charts/src/indicator/defaultOptionsForAppearance.ts
new file mode 100644
index 000000000..852039a38
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/defaultOptionsForAppearance.ts
@@ -0,0 +1,77 @@
+export const themes = {
+ light: {
+ BollingerBand: {
+ stroke: {
+ top: "#964B00",
+ middle: "#000000",
+ bottom: "#964B00",
+ },
+ fill: "#4682B4",
+ },
+ ElderImpulse: {
+ stroke: {
+ up: "#6BA583",
+ down: "#FF0000",
+ neutral: "#0000FF",
+ },
+ },
+ MACD: {
+ fill: {
+ divergence: "#4682B4",
+ },
+ stroke: {
+ macd: "#FF0000",
+ signal: "#00F300",
+ },
+ },
+ FullStochasticOscillator: {
+ stroke: {
+ top: "#37a600",
+ middle: "#b8ab00",
+ bottom: "#37a600",
+ dLine: "#17becf",
+ kLine: "#ff7f0e",
+ },
+ },
+ },
+ dark: {
+ BollingerBand: {
+ stroke: {
+ top: "#964B00",
+ middle: "#FF6600",
+ bottom: "#964B00",
+ },
+ fill: "#4682B4",
+ },
+ ElderImpulse: {
+ stroke: {
+ up: "#6BA583",
+ down: "#FF0000",
+ neutral: "#0000FF",
+ },
+ },
+ MACD: {
+ fill: {
+ divergence: "#FF6600",
+ },
+ stroke: {
+ macd: "#ea2bff",
+ signal: "#74d400",
+ },
+ },
+ FullStochasticOscillator: {
+ stroke: {
+ top: "#37a600",
+ middle: "#b8ab00",
+ bottom: "#37a600",
+ dLine: "#ea2bff",
+ kLine: "#74d400",
+ },
+ },
+ },
+};
+
+export const BollingerBand = themes.light.BollingerBand;
+export const ElderImpulse = themes.light.ElderImpulse;
+export const MACD = themes.light.MACD;
+export const FullStochasticOscillator = themes.light.FullStochasticOscillator;
diff --git a/packages/react-financial-charts/src/indicator/elderImpulse.ts b/packages/react-financial-charts/src/indicator/elderImpulse.ts
new file mode 100644
index 000000000..b3f6ec3bf
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/elderImpulse.ts
@@ -0,0 +1,68 @@
+import { isDefined, isNotDefined, merge, rebind, slidingWindow } from "../utils";
+
+import baseIndicator from "./baseIndicator";
+import { ElderImpulse as appearanceOptions } from "./defaultOptionsForAppearance";
+
+const ALGORITHM_TYPE = "ElderImpulse";
+
+export default function () {
+
+ let macdSource;
+ let emaSource;
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .stroke(appearanceOptions.stroke)
+ .fill(undefined);
+
+ const underlyingAlgorithm = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .undefinedValue("neutral")
+ .accumulator(([prev, curr]) => {
+ if (isNotDefined(macdSource)) { throw new Error(`macdSource not defined for ${ALGORITHM_TYPE} calculator`); }
+ if (isNotDefined(emaSource)) { throw new Error(`emaSource not defined for ${ALGORITHM_TYPE} calculator`); }
+
+ if (isDefined(macdSource(prev)) && isDefined(emaSource(prev))) {
+ const prevMACDDivergence = macdSource(prev).divergence;
+ const currMACDDivergence = macdSource(curr).divergence;
+
+ const prevEMA = emaSource(prev);
+ const currEMA = emaSource(curr);
+
+ if (currMACDDivergence >= prevMACDDivergence
+ && currEMA >= prevEMA) { return "up"; }
+
+ if (currMACDDivergence <= prevMACDDivergence
+ && currEMA <= prevEMA) { return "down"; }
+ }
+ return "neutral";
+ });
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.elderImpulse = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ const newData = options.merge
+ ? mergedAlgorithm(data)
+ : underlyingAlgorithm(data);
+
+ return newData;
+ };
+ indicator.macdSource = function (x) {
+ if (!arguments.length) { return macdSource; }
+ macdSource = x;
+ return indicator;
+ };
+ indicator.emaSource = function (x) {
+ if (!arguments.length) { return emaSource; }
+ emaSource = x;
+ return indicator;
+ };
+ rebind(indicator, base, "id", "echo", "type", "stroke");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/elderRay.ts b/packages/react-financial-charts/src/indicator/elderRay.ts
new file mode 100644
index 000000000..da9555642
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/elderRay.ts
@@ -0,0 +1,34 @@
+import { elderRay } from "../calculator";
+import { merge, rebind } from "../utils";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "ElderRay";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.elderRay);
+
+ const underlyingAlgorithm = elderRay();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.elderRay = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/ema.ts b/packages/react-financial-charts/src/indicator/ema.ts
new file mode 100644
index 000000000..66110731e
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/ema.ts
@@ -0,0 +1,34 @@
+import { merge, rebind } from "../utils";
+
+import { ema } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "EMA";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.ema);
+
+ const underlyingAlgorithm = ema();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.ema = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options", "undefinedLength");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/forceIndex.ts b/packages/react-financial-charts/src/indicator/forceIndex.ts
new file mode 100644
index 000000000..0023410c6
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/forceIndex.ts
@@ -0,0 +1,35 @@
+import { merge, rebind } from "../utils";
+
+import { forceIndex } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "ForceIndex";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.forceIndex);
+
+ const underlyingAlgorithm = forceIndex();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.forceIndex = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/heikinAshi.ts b/packages/react-financial-charts/src/indicator/heikinAshi.ts
new file mode 100644
index 000000000..dd2c1c748
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/heikinAshi.ts
@@ -0,0 +1,35 @@
+import { heikinAshi } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+import { merge, rebind } from "../utils";
+
+const ALGORITHM_TYPE = "HeikinAshi";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.ha);
+
+ const underlyingAlgorithm = heikinAshi();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => {
+ return { ...datum, ...i };
+ });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, mergedAlgorithm, "merge");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/index.ts b/packages/react-financial-charts/src/indicator/index.ts
new file mode 100644
index 000000000..3b98b7b01
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/index.ts
@@ -0,0 +1,27 @@
+export { default as ema } from "./ema";
+export { default as sma } from "./sma";
+export { default as wma } from "./wma";
+export { default as tma } from "./tma";
+export { default as bollingerBand } from "./bollingerBand";
+export { default as heikinAshi } from "./heikinAshi";
+export { default as kagi } from "./kagi";
+export { default as pointAndFigure } from "./pointAndFigure";
+export { default as renko } from "./renko";
+export { default as macd } from "./macd";
+export { default as rsi } from "./rsi";
+export { default as atr } from "./atr";
+export { default as stochasticOscillator } from "./stochasticOscillator";
+export { default as forceIndex } from "./forceIndex";
+export { default as sar } from "./sar";
+export { default as elderRay } from "./elderRay";
+export { default as change } from "./change";
+export { default as elderImpulse } from "./elderImpulse";
+export { default as compare } from "./compare";
+
+import * as defaultOptionsForComputation from "../calculator/defaultOptionsForComputation";
+import * as defaultOptionsForAppearance from "./defaultOptionsForAppearance";
+
+export {
+ defaultOptionsForComputation,
+ defaultOptionsForAppearance
+};
diff --git a/packages/react-financial-charts/src/indicator/kagi.ts b/packages/react-financial-charts/src/indicator/kagi.ts
new file mode 100644
index 000000000..3fccdf801
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/kagi.ts
@@ -0,0 +1,22 @@
+import { rebind } from "../utils";
+
+import { kagi } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "Kagi";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = kagi();
+
+ const indicator = underlyingAlgorithm;
+
+ rebind(indicator, base, "id", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "dateAccessor", "dateMutator");
+ rebind(indicator, underlyingAlgorithm, "options");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/macd.ts b/packages/react-financial-charts/src/indicator/macd.ts
new file mode 100644
index 000000000..33995e182
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/macd.ts
@@ -0,0 +1,38 @@
+import { merge, rebind } from "../utils";
+
+import { macd } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+import { MACD as appearanceOptions } from "./defaultOptionsForAppearance";
+
+const ALGORITHM_TYPE = "MACD";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .fill(appearanceOptions.fill)
+ .stroke(appearanceOptions.stroke)
+ .accessor((d) => d.macd);
+
+ const underlyingAlgorithm = macd();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.macd = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options", "undefinedLength");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/pointAndFigure.ts b/packages/react-financial-charts/src/indicator/pointAndFigure.ts
new file mode 100644
index 000000000..673f13956
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/pointAndFigure.ts
@@ -0,0 +1,22 @@
+import { rebind } from "../utils";
+
+import { pointAndFigure } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "PointAndFigure";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = pointAndFigure();
+
+ const indicator = underlyingAlgorithm;
+
+ rebind(indicator, base, "id", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "dateAccessor", "dateMutator");
+ rebind(indicator, underlyingAlgorithm, "options");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/renko.ts b/packages/react-financial-charts/src/indicator/renko.ts
new file mode 100644
index 000000000..27208b8f1
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/renko.ts
@@ -0,0 +1,22 @@
+import { rebind } from "../utils";
+
+import { renko } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "Renko";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = renko();
+
+ const indicator = underlyingAlgorithm;
+
+ rebind(indicator, base, "id", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "dateAccessor", "dateMutator");
+ rebind(indicator, underlyingAlgorithm, "options");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/rsi.ts b/packages/react-financial-charts/src/indicator/rsi.ts
new file mode 100644
index 000000000..889490892
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/rsi.ts
@@ -0,0 +1,34 @@
+import { merge, rebind } from "../utils";
+
+import { rsi } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "RSI";
+
+export default function () {
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.rsi);
+
+ const underlyingAlgorithm = rsi();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.rsi = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options", "undefinedLength");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/sar.ts b/packages/react-financial-charts/src/indicator/sar.ts
new file mode 100644
index 000000000..f438b80c3
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/sar.ts
@@ -0,0 +1,36 @@
+import { merge, rebind } from "../utils";
+
+import { sar } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "SMA";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.sar);
+
+ const underlyingAlgorithm = sar();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.sar = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "undefinedLength");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/sma.ts b/packages/react-financial-charts/src/indicator/sma.ts
new file mode 100644
index 000000000..a4b1fda15
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/sma.ts
@@ -0,0 +1,34 @@
+import { merge, rebind } from "../utils";
+
+import { sma } from "../calculator";
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "SMA";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.sma);
+
+ const underlyingAlgorithm = sma();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.sma = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "undefinedLength");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/stochasticOscillator.ts b/packages/react-financial-charts/src/indicator/stochasticOscillator.ts
new file mode 100644
index 000000000..036dc7ef7
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/stochasticOscillator.ts
@@ -0,0 +1,33 @@
+import { merge, rebind } from "../utils";
+
+import { sto } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "STO";
+
+export default function () {
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE);
+
+ const underlyingAlgorithm = sto();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.sto = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "options", "undefinedLength");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/tma.ts b/packages/react-financial-charts/src/indicator/tma.ts
new file mode 100644
index 000000000..e7d14575e
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/tma.ts
@@ -0,0 +1,35 @@
+import { merge, rebind } from "../utils";
+
+import { tma } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "TMA";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.tma);
+
+ const underlyingAlgorithm = tma();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.tma = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "undefinedLength");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/indicator/wma.ts b/packages/react-financial-charts/src/indicator/wma.ts
new file mode 100644
index 000000000..9d531897d
--- /dev/null
+++ b/packages/react-financial-charts/src/indicator/wma.ts
@@ -0,0 +1,36 @@
+import { merge, rebind } from "../utils";
+
+import { wma } from "../calculator";
+
+import baseIndicator from "./baseIndicator";
+
+const ALGORITHM_TYPE = "WMA";
+
+export default function () {
+
+ const base = baseIndicator()
+ .type(ALGORITHM_TYPE)
+ .accessor((d) => d.wma);
+
+ const underlyingAlgorithm = wma();
+
+ const mergedAlgorithm = merge()
+ .algorithm(underlyingAlgorithm)
+ // @ts-ignore
+ .merge((datum, i) => { datum.wma = i; });
+
+ const indicator = function (data, options = { merge: true }) {
+ if (options.merge) {
+ if (!base.accessor()) { throw new Error(`Set an accessor to ${ALGORITHM_TYPE} before calculating`); }
+ return mergedAlgorithm(data);
+ }
+ return underlyingAlgorithm(data);
+ };
+
+ rebind(indicator, base, "id", "accessor", "stroke", "fill", "echo", "type");
+ rebind(indicator, underlyingAlgorithm, "undefinedLength");
+ rebind(indicator, underlyingAlgorithm, "options");
+ rebind(indicator, mergedAlgorithm, "merge", "skipUndefined");
+
+ return indicator;
+}
diff --git a/packages/react-financial-charts/src/interactive/Brush.tsx b/packages/react-financial-charts/src/interactive/Brush.tsx
new file mode 100644
index 000000000..d15376317
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/Brush.tsx
@@ -0,0 +1,207 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import {
+ getStrokeDasharray,
+ hexToRGBA,
+ isDefined,
+ noop,
+} from "../utils";
+
+interface BrushProps {
+ enabled: boolean;
+ onStart: any; // func
+ onBrush: any; // func
+ type?: "1D" | "2D";
+ stroke?: string;
+ fill?: string;
+ strokeOpacity?: number;
+ fillOpacity?: number;
+ interactiveState: object;
+ strokeDashArray?: string;
+}
+
+interface BrushState {
+ end?: any;
+ rect: any | null;
+ selected?: boolean;
+ start?: any;
+ x1y1?: any;
+}
+
+export class Brush extends React.Component {
+
+ public static defaultProps = {
+ type: "2D",
+ stroke: "#000000",
+ fillOpacity: 0.3,
+ strokeOpacity: 1,
+ fill: "#3h3h3h",
+ onBrush: noop,
+ onStart: noop,
+ strokeDashArray: "ShortDash",
+ };
+
+ private zoomHappening?: boolean;
+
+ constructor(props: BrushProps, context) {
+ super(props, context);
+
+ this.terminate = this.terminate.bind(this);
+ this.state = {
+ rect: null,
+ };
+ }
+
+ public terminate() {
+ this.zoomHappening = false;
+ this.setState({
+ x1y1: null,
+ start: null,
+ end: null,
+ rect: null,
+ });
+ }
+
+ public render() {
+ const { enabled } = this.props;
+ if (!enabled) {
+ return null;
+ }
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx) => {
+ const { rect } = this.state;
+ if (isDefined(rect)) {
+ const { x, y, height, width } = rect;
+ const { stroke, fill, strokeDashArray } = this.props;
+ const { strokeOpacity, fillOpacity } = this.props;
+
+ const dashArray = getStrokeDasharray(strokeDashArray)
+ .split(",")
+ .map((d) => +d);
+
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+ ctx.fillStyle = hexToRGBA(fill, fillOpacity);
+ ctx.setLineDash(dashArray);
+ ctx.beginPath();
+ ctx.fillRect(x, y, width, height);
+ ctx.strokeRect(x, y, width, height);
+ }
+ }
+
+ private readonly handleZoomStart = (moreProps) => {
+ this.zoomHappening = false;
+ const {
+ mouseXY: [, mouseY],
+ currentItem,
+ chartConfig: { yScale },
+ xAccessor,
+ xScale,
+ } = moreProps;
+
+ const x1y1 = [
+ xScale(xAccessor(currentItem)),
+ mouseY,
+ ];
+
+ this.setState({
+ selected: true,
+ x1y1,
+ start: {
+ item: currentItem,
+ xValue: xAccessor(currentItem),
+ yValue: yScale.invert(mouseY),
+ },
+ });
+ }
+
+ private readonly handleDrawSquare = (moreProps) => {
+ if (this.state.x1y1 == null) { return; }
+
+ this.zoomHappening = true;
+
+ const {
+ mouseXY: [, mouseY],
+ currentItem,
+ chartConfig: { yScale },
+ xAccessor,
+ xScale,
+ } = moreProps;
+
+ const [x2, y2] = [
+ xScale(xAccessor(currentItem)),
+ mouseY,
+ ];
+
+ const { x1y1: [x1, y1] } = this.state;
+
+ const x = Math.min(x1, x2);
+ const y = Math.min(y1, y2);
+ const height = Math.abs(y2 - y1);
+ const width = Math.abs(x2 - x1);
+
+ this.setState({
+ selected: true,
+ end: {
+ item: currentItem,
+ xValue: xAccessor(currentItem),
+ yValue: yScale.invert(mouseY),
+ },
+ rect: {
+ x, y, height, width,
+ },
+ });
+ }
+
+ private readonly handleZoomComplete = (moreProps) => {
+ if (this.zoomHappening) {
+ const { onBrush } = this.props;
+ const { start, end } = this.state;
+ onBrush({ start, end }, moreProps);
+ }
+ this.setState({
+ selected: false,
+ rect: null,
+ });
+ }
+
+ private readonly renderSVG = () => {
+ const { rect } = this.state;
+ if (isDefined(rect)) {
+ const { x, y, height, width } = rect;
+ const { stroke, strokeDashArray } = this.props;
+ const { strokeOpacity, fillOpacity } = this.props;
+
+ const dashArray = getStrokeDasharray(strokeDashArray);
+
+ return (
+
+ );
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/ClickCallback.tsx b/packages/react-financial-charts/src/interactive/ClickCallback.tsx
new file mode 100644
index 000000000..bad4bc82c
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/ClickCallback.tsx
@@ -0,0 +1,51 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import { noop } from "../utils";
+
+interface ClickCallbackProps {
+ disablePan: boolean;
+ onMouseDown?: any; // func
+ onClick?: any; // func
+ onDoubleClick?: any; // func
+ onContextMenu?: any; // func
+ onMouseMove?: any; // func
+ onPan?: any; // func
+ onPanEnd?: any; // func
+}
+
+export class ClickCallback extends React.Component {
+
+ public static defaultProps = {
+ disablePan: false,
+ };
+
+ public render() {
+ const {
+ onMouseDown,
+ onClick,
+ onDoubleClick,
+ onContextMenu,
+ onMouseMove,
+ onPan,
+ onPanEnd,
+ } = this.props;
+
+ return (
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/DrawingObjectSelector.tsx b/packages/react-financial-charts/src/interactive/DrawingObjectSelector.tsx
new file mode 100644
index 000000000..29bf0f6c5
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/DrawingObjectSelector.tsx
@@ -0,0 +1,105 @@
+import * as React from "react";
+import { head, isDefined, mapObject, noop } from "../utils";
+import { getMorePropsForChart, getSelected } from "./utils";
+
+import GenericComponent, { getMouseCanvas } from "../GenericComponent";
+
+interface DrawingObjectSelectorProps {
+ readonly getInteractiveNodes: any; // func
+ readonly onSelect: any; // func
+ readonly onDoubleClick: any; // func
+ readonly drawingObjectMap: object;
+ readonly enabled: boolean;
+}
+
+export class DrawingObjectSelector extends React.Component {
+
+ public static defaultProps = {
+ enabled: true,
+ onDoubleClick: noop,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly getInteraction = (moreProps) => {
+ const { getInteractiveNodes, drawingObjectMap } = this.props;
+ const interactiveNodes = getInteractiveNodes();
+ const interactives = mapObject(interactiveNodes, (each) => {
+ const key = drawingObjectMap[each.type];
+
+ const valueArray = isDefined(key)
+ ? each.node.props[key]
+ : undefined;
+
+ const valuePresent = isDefined(valueArray)
+ && Array.isArray(valueArray)
+ && valueArray.length > 0;
+ if (valuePresent) {
+ // console.log("Value present for ", each.type, each.chartId);
+ const morePropsForChart = getMorePropsForChart(
+ moreProps, each.chartId,
+ );
+
+ const objects = each.node.getSelectionState(morePropsForChart);
+
+ return {
+ type: each.type,
+ chartId: each.chartId,
+ objects,
+ };
+ }
+ return {
+ type: each.type,
+ chartId: each.chartId,
+ objects: [],
+ };
+ });
+
+ return interactives;
+ }
+
+ private readonly handleClick = (moreProps, e) => {
+ e.preventDefault();
+ const { onSelect } = this.props;
+ const { enabled } = this.props;
+ if (!enabled) { return; }
+
+ const interactives = this.getInteraction(moreProps);
+
+ onSelect(interactives, moreProps);
+ }
+
+ private readonly handleDoubleClick = (moreProps, e) => {
+ e.preventDefault();
+ const { onDoubleClick } = this.props;
+ const { enabled } = this.props;
+ if (!enabled) { return; }
+
+ const interactives = this.getInteraction(moreProps);
+ const allSelected = getSelected(interactives);
+
+ if (allSelected.length > 0) {
+ const selected = head(allSelected);
+ const item = {
+ type: selected.type,
+ chartId: selected.chartId,
+ object: head(selected.objects),
+ };
+ const morePropsForChart = getMorePropsForChart(
+ moreProps, selected.chartId,
+ );
+ onDoubleClick(item, morePropsForChart);
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/EquidistantChannel.tsx b/packages/react-financial-charts/src/interactive/EquidistantChannel.tsx
new file mode 100644
index 000000000..11bacfec4
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/EquidistantChannel.tsx
@@ -0,0 +1,254 @@
+import * as React from "react";
+
+import { isDefined, isNotDefined, noop } from "../utils";
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import { MouseLocationIndicator } from "./components/MouseLocationIndicator";
+import { getSlope, getYIntercept } from "./components/StraightLine";
+import {
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+import { EachEquidistantChannel } from "./wrapper/EachEquidistantChannel";
+
+interface EquidistantChannelProps {
+ enabled: boolean;
+ onStart: any; // func
+ onComplete: any; // func
+ onSelect: any; // func
+ currentPositionStroke?: string;
+ currentPositionStrokeWidth?: number;
+ currentPositionOpacity?: number;
+ currentPositionRadius?: number;
+ hoverText: object;
+ channels: any[];
+ appearance: {
+ stroke: string;
+ strokeOpacity: number;
+ strokeWidth: number;
+ fill: string;
+ fillOpacity: number;
+ edgeStroke: string;
+ edgeFill: string;
+ edgeFill2: string;
+ edgeStrokeWidth: number;
+ r: number;
+ };
+}
+
+interface EquidistantChannelState {
+ current?: any;
+ override?: any;
+}
+
+export class EquidistantChannel extends React.Component {
+
+ public static defaultProps = {
+ onStart: noop,
+ onComplete: noop,
+ onSelect: noop,
+ currentPositionStroke: "#000000",
+ currentPositionOpacity: 1,
+ currentPositionStrokeWidth: 3,
+ currentPositionRadius: 4,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: 18,
+ bgWidth: 120,
+ text: "Click to select object",
+ },
+ channels: [],
+ appearance: {
+ stroke: "#000000",
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ fill: "#8AAFE2",
+ fillOpacity: 0.7,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ edgeFill2: "#250B98",
+ edgeStrokeWidth: 1,
+ r: 5,
+ },
+ };
+
+ // @ts-ignore
+ private terminate: () => void;
+ private saveNodeType;
+ // @ts-ignore
+ private getSelectionState;
+ private mouseMoved;
+
+ public constructor(props) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.getSelectionState = isHoverForInteractiveType("channels")
+ .bind(this);
+
+ this.state = {
+ };
+ }
+
+ public render() {
+ const { appearance } = this.props;
+ const { enabled } = this.props;
+ const { currentPositionRadius, currentPositionStroke } = this.props;
+ const { currentPositionOpacity, currentPositionStrokeWidth } = this.props;
+ const { channels, hoverText } = this.props;
+ const { current, override } = this.state;
+ const overrideIndex = isDefined(override) ? override.index : null;
+
+ const tempChannel = isDefined(current) && isDefined(current.endXY)
+ ?
+ : null;
+
+ return
+ {channels.map((each, idx) => {
+ const eachAppearance = isDefined(each.appearance)
+ ? { ...appearance, ...each.appearance }
+ : appearance;
+
+ return ;
+ })}
+ {tempChannel}
+
+ ;
+ }
+
+ private readonly handleDragChannel = (index, newXYValue) => {
+ this.setState({
+ override: {
+ index,
+ ...newXYValue,
+ },
+ });
+ }
+
+ private readonly handleDragChannelComplete = (moreProps) => {
+ const { override } = this.state;
+ const { channels } = this.props;
+
+ if (isDefined(override)) {
+ const { index, ...rest } = override;
+ const newChannels = channels
+ .map((each, idx) => idx === index
+ ? { ...each, ...rest, selected: true }
+ : each);
+
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onComplete(newChannels, moreProps);
+ });
+ }
+ }
+
+ private readonly handleStart = (xyValue) => {
+ const { current } = this.state;
+
+ if (isNotDefined(current) || isNotDefined(current.startXY)) {
+ this.mouseMoved = false;
+ this.setState({
+ current: {
+ startXY: xyValue,
+ endXY: null,
+ },
+ }, () => {
+ this.props.onStart();
+ });
+ }
+ }
+
+ private readonly handleEnd = (xyValue, moreProps, e) => {
+ const { current } = this.state;
+ const { channels, appearance } = this.props;
+
+ if (this.mouseMoved
+ && isDefined(current)
+ && isDefined(current.startXY)
+ ) {
+
+ if (isNotDefined(current.dy)) {
+ this.setState({
+ current: {
+ ...current,
+ dy: 0,
+ },
+ });
+ } else {
+ const newChannels = [
+ ...channels.map((d) => ({ ...d, selected: false })),
+ {
+ ...current, selected: true,
+ appearance,
+ },
+ ];
+
+ this.setState({
+ current: null,
+ }, () => {
+
+ this.props.onComplete(newChannels, moreProps, e);
+ });
+ }
+ }
+ }
+
+ private readonly handleDrawChannel = (xyValue) => {
+ const { current } = this.state;
+
+ if (isDefined(current)
+ && isDefined(current.startXY)) {
+ this.mouseMoved = true;
+ if (isNotDefined(current.dy)) {
+ this.setState({
+ current: {
+ startXY: current.startXY,
+ endXY: xyValue,
+ },
+ });
+ } else {
+ const m = getSlope(current.startXY, current.endXY);
+ const b = getYIntercept(m, current.endXY);
+
+ // @ts-ignore
+ const y = m * xyValue[0] + b;
+ const dy = xyValue[1] - y;
+
+ this.setState({
+ current: {
+ ...current,
+ dy,
+ },
+ });
+ }
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/FibonacciRetracement.tsx b/packages/react-financial-charts/src/interactive/FibonacciRetracement.tsx
new file mode 100644
index 000000000..4ac7fb06f
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/FibonacciRetracement.tsx
@@ -0,0 +1,304 @@
+import * as React from "react";
+
+import { isDefined, isNotDefined, noop } from "../utils";
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import { MouseLocationIndicator } from "./components/MouseLocationIndicator";
+import {
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+import { EachFibRetracement } from "./wrapper/EachFibRetracement";
+
+interface FibonacciRetracementProps {
+ enabled: boolean;
+ width?: number;
+ onStart?: any; // func
+ onComplete?: any; // func
+ onSelect?: any; // func
+ type:
+ "EXTEND" | // extends from -Infinity to +Infinity
+ "RAY" | // extends to +/-Infinity in one direction
+ "BOUND"; // extends between the set bounds
+ hoverText: object;
+ currentPositionStroke?: string;
+ currentPositionStrokeWidth?: number;
+ currentPositionOpacity?: number;
+ currentPositionRadius?: number;
+ retracements: any[];
+ appearance: {
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ fontFamily: string;
+ fontSize: number;
+ fontFill: string;
+ edgeStroke: string;
+ edgeFill: string;
+ nsEdgeFill: string;
+ edgeStrokeWidth: number;
+ r: number;
+ };
+}
+
+interface FibonacciRetracementState {
+ current?: any;
+ override?: any;
+}
+
+export class FibonacciRetracement extends React.Component {
+
+ public static defaultProps = {
+ enabled: true,
+ type: "RAY",
+ retracements: [],
+ onStart: noop,
+ onComplete: noop,
+ onSelect: noop,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: "auto",
+ bgWidth: "auto",
+ text: "Click to select object",
+ selectedText: "",
+ },
+ currentPositionStroke: "#000000",
+ currentPositionOpacity: 1,
+ currentPositionStrokeWidth: 3,
+ currentPositionRadius: 4,
+ appearance: {
+ stroke: "#000000",
+ strokeWidth: 1,
+ strokeOpacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 11,
+ fontFill: "#000000",
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ nsEdgeFill: "#000000",
+ edgeStrokeWidth: 1,
+ r: 5,
+ },
+ };
+
+ // @ts-ignore
+ private getSelectionState;
+ private mouseMoved;
+ private saveNodeType;
+
+ // @ts-ignore
+ private terminate;
+
+ constructor(props) {
+ super(props);
+
+ this.handleEdge1Drag = this.handleEdge1Drag.bind(this);
+ this.handleEdge2Drag = this.handleEdge2Drag.bind(this);
+
+ this.terminate = terminate.bind(this);
+ this.getSelectionState = isHoverForInteractiveType("retracements")
+ .bind(this);
+
+ this.saveNodeType = saveNodeType.bind(this);
+ this.state = {};
+ }
+
+ public render() {
+ const { current, override } = this.state;
+ const { retracements } = this.props;
+
+ const {
+ appearance,
+ type,
+ } = this.props;
+ const {
+ currentPositionStroke,
+ currentPositionOpacity,
+ currentPositionStrokeWidth,
+ currentPositionRadius,
+ } = this.props;
+
+ const { enabled, hoverText } = this.props;
+ const overrideIndex = isDefined(override) ? override.index : null;
+ const hoverTextWidthDefault = {
+ ...FibonacciRetracement.defaultProps.hoverText,
+ ...hoverText,
+ };
+
+ const currentRetracement = isDefined(current) && isDefined(current.x2)
+ ?
+ : null;
+ return (
+
+ {retracements.map((each, idx) => {
+ const eachAppearance = isDefined(each.appearance)
+ ? { ...appearance, ...each.appearance }
+ : appearance;
+
+ const eachHoverText = isDefined(each.hoverText)
+ ? { ...hoverTextWidthDefault, ...each.hoverText }
+ : hoverTextWidthDefault;
+
+ return (
+
+ );
+ })}
+ {currentRetracement}
+
+
+ );
+ }
+
+ private readonly handleDrawRetracement = (xyValue) => {
+ const { current } = this.state;
+ if (isDefined(current) && isDefined(current.x1)) {
+ this.mouseMoved = true;
+ this.setState({
+ current: {
+ ...current,
+ x2: xyValue[0],
+ y2: xyValue[1],
+ },
+ });
+ }
+ }
+
+ private readonly handleEdge1Drag = (echo, newXYValue, origXYValue) => {
+ const { retracements } = this.props;
+ const { index } = echo;
+
+ const dx = origXYValue.x1Value - newXYValue.x1Value;
+
+ this.setState({
+ override: {
+ index,
+ x1: retracements[index].x1 - dx,
+ y1: retracements[index].y1,
+ x2: retracements[index].x2,
+ y2: retracements[index].y2,
+ },
+ });
+ }
+
+ private readonly handleDrag = (index, xy) => {
+ this.setState({
+ override: {
+ index,
+ ...xy,
+ },
+ });
+ }
+
+ private readonly handleEdge2Drag = (echo, newXYValue, origXYValue) => {
+ const { retracements } = this.props;
+ const { index } = echo;
+
+ const dx = origXYValue.x2Value - newXYValue.x2Value;
+
+ this.setState({
+ override: {
+ index,
+ x1: retracements[index].x1,
+ y1: retracements[index].y1,
+ x2: retracements[index].x2 - dx,
+ y2: retracements[index].y2,
+ },
+ });
+ }
+
+ private readonly handleDragComplete = (moreProps) => {
+ const { retracements } = this.props;
+ const { override } = this.state;
+ if (isDefined(override)) {
+ const { index, ...rest } = override;
+
+ const newRetracements = retracements.map(
+ (each, idx) =>
+ (idx === index
+ ? { ...each, ...rest, selected: true }
+ : each),
+ );
+ this.setState(
+ {
+ override: null,
+ },
+ () => {
+ this.props.onComplete(newRetracements, moreProps);
+ },
+ );
+ }
+ }
+
+ private readonly handleStart = (xyValue, moreProps) => {
+ const { current } = this.state;
+ if (isNotDefined(current) || isNotDefined(current.x1)) {
+ this.mouseMoved = false;
+ this.setState(
+ {
+ current: {
+ x1: xyValue[0],
+ y1: xyValue[1],
+ x2: null,
+ y2: null,
+ },
+ },
+ () => {
+ this.props.onStart(moreProps);
+ },
+ );
+ }
+ }
+
+ private readonly handleEnd = (xyValue, moreProps, e) => {
+ const { retracements, appearance, type } = this.props;
+ const { current } = this.state;
+
+ if (this.mouseMoved && isDefined(current) && isDefined(current.x1)) {
+ const newRetracements = retracements.concat({
+ ...current,
+ x2: xyValue[0],
+ y2: xyValue[1],
+ selected: true,
+ appearance,
+ type,
+ });
+
+ this.setState(
+ {
+ current: null,
+ },
+ () => {
+ this.props.onComplete(newRetracements, moreProps, e);
+ },
+ );
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/GannFan.tsx b/packages/react-financial-charts/src/interactive/GannFan.tsx
new file mode 100644
index 000000000..f061c4116
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/GannFan.tsx
@@ -0,0 +1,237 @@
+import * as React from "react";
+
+import { isDefined, isNotDefined, noop } from "../utils";
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import { MouseLocationIndicator } from "./components/MouseLocationIndicator";
+import {
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+import { EachGannFan } from "./wrapper/EachGannFan";
+
+interface GannFanProps {
+ enabled: boolean;
+ onStart: any; // func
+ onComplete: any; // func
+ onSelect?: any; // func
+ currentPositionStroke?: string;
+ currentPositionStrokeWidth?: number;
+ currentPositionOpacity?: number;
+ currentPositionRadius?: number;
+ appearance: {
+ stroke: string;
+ strokeOpacity: number;
+ fillOpacity: number;
+ strokeWidth: number;
+ edgeStroke: string;
+ edgeFill: string;
+ edgeStrokeWidth: number;
+ r: number;
+ fill: string[],
+ fontFamily: string;
+ fontSize: number;
+ fontFill: string;
+ };
+ hoverText: object;
+ fans: any[];
+}
+
+interface GannFanState {
+ current?: any;
+ override?: any;
+}
+
+export class GannFan extends React.Component {
+
+ public static defaultProps = {
+ appearance: {
+ stroke: "#000000",
+ fillOpacity: 0.2,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ edgeStrokeWidth: 1,
+ r: 5,
+ fill: [
+ "#e41a1c",
+ "#377eb8",
+ "#4daf4a",
+ "#984ea3",
+ "#ff7f00",
+ "#ffff33",
+ "#a65628",
+ "#f781bf",
+ ],
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fontFill: "#000000",
+ },
+ onStart: noop,
+ onComplete: noop,
+ onSelect: noop,
+ currentPositionStroke: "#000000",
+ currentPositionOpacity: 1,
+ currentPositionStrokeWidth: 3,
+ currentPositionRadius: 4,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: 18,
+ bgWidth: 120,
+ text: "Click to select object",
+ },
+ fans: [],
+ };
+
+ private mouseMoved;
+ // @ts-ignore
+ private getSelectionState;
+ private saveNodeType;
+
+ // @ts-ignore
+ private terminate;
+
+ public constructor(props) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.getSelectionState = isHoverForInteractiveType("fans")
+ .bind(this);
+
+ this.state = {};
+ }
+
+ public render() {
+ const { enabled, appearance } = this.props;
+ const { currentPositionRadius, currentPositionStroke } = this.props;
+ const { currentPositionOpacity, currentPositionStrokeWidth } = this.props;
+ const { hoverText, fans } = this.props;
+ const { current, override } = this.state;
+ const overrideIndex = isDefined(override) ? override.index : null;
+
+ const tempChannel = isDefined(current) && isDefined(current.endXY)
+ ?
+ : null;
+
+ return (
+
+ {fans.map((each, idx) => {
+ const eachAppearance = isDefined(each.appearance)
+ ? { ...appearance, ...each.appearance }
+ : appearance;
+
+ return ;
+ })}
+ {tempChannel}
+
+
+ );
+ }
+
+ private readonly handleEnd = (xyValyue, moreProps, e) => {
+ const { current } = this.state;
+ const { fans, appearance } = this.props;
+
+ if (this.mouseMoved
+ && isDefined(current)
+ && isDefined(current.startXY)
+ ) {
+ const newfans = [
+ ...fans.map((d) => ({ ...d, selected: false })),
+ { ...current, selected: true, appearance },
+ ];
+ this.setState({
+ current: null,
+ }, () => {
+ this.props.onComplete(newfans, moreProps, e);
+ });
+ }
+ }
+
+ private readonly handleStart = (xyValue) => {
+ const { current } = this.state;
+
+ if (isNotDefined(current) || isNotDefined(current.startXY)) {
+ this.mouseMoved = false;
+
+ this.setState({
+ current: {
+ startXY: xyValue,
+ endXY: null,
+ },
+ }, () => {
+ this.props.onStart();
+ });
+ }
+ }
+
+ private readonly handleDrawFan = (xyValue) => {
+ const { current } = this.state;
+
+ if (isDefined(current) && isDefined(current.startXY)) {
+ this.mouseMoved = true;
+
+ this.setState({
+ current: {
+ startXY: current.startXY,
+ endXY: xyValue,
+ },
+ });
+ }
+ }
+
+ private readonly handleDragFanComplete = (moreProps) => {
+ const { override } = this.state;
+ const { fans } = this.props;
+
+ if (isDefined(override)) {
+ const { index, ...rest } = override;
+ const newfans = fans
+ .map((each, idx) => idx === index
+ ? { ...each, ...rest, selected: true }
+ : each);
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onComplete(newfans, moreProps);
+ });
+ }
+ }
+
+ private readonly handleDragFan = (index, newXYValue) => {
+ this.setState({
+ override: {
+ index,
+ ...newXYValue,
+ },
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/InteractiveText.tsx b/packages/react-financial-charts/src/interactive/InteractiveText.tsx
new file mode 100644
index 000000000..528cf35bc
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/InteractiveText.tsx
@@ -0,0 +1,192 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import { isDefined, noop } from "../utils";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getMouseCanvas } from "../GenericComponent";
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import {
+ getValueFromOverride,
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+import { EachText } from "./wrapper/EachText";
+
+interface InteractiveTextProps {
+ onChoosePosition: any; // func
+ onDragComplete: any; // func
+ onSelect?: any; // func
+ defaultText: {
+ bgFill: string;
+ bgOpacity: number;
+ bgStrokeWidth?: number;
+ bgStroke?: string;
+ textFill: string;
+ fontFamily: string;
+ fontWeight: string;
+ fontStyle: string;
+ fontSize: number;
+ text: string;
+ };
+ hoverText: object;
+ textList: any[];
+ enabled: boolean;
+}
+
+interface InteractiveTextState {
+ current?: any;
+ override?: any;
+}
+
+export class InteractiveText extends React.Component {
+
+ public static defaultProps = {
+ onChoosePosition: noop,
+ onDragComplete: noop,
+ onSelect: noop,
+ defaultText: {
+ bgFill: "#D3D3D3",
+ bgOpacity: 1,
+ bgStrokeWidth: 1,
+ textFill: "#F10040",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fontStyle: "normal",
+ fontWeight: "normal",
+ text: "Lorem ipsum...",
+ },
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: "auto",
+ bgWidth: "auto",
+ text: "Click to select object",
+ selectedText: "",
+ },
+ textList: [],
+ };
+
+ public static contextTypes = {
+ subscribe: PropTypes.func.isRequired,
+ unsubscribe: PropTypes.func.isRequired,
+ generateSubscriptionId: PropTypes.func.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
+ };
+
+ // @ts-ignore
+ private getSelectionState;
+ private saveNodeType;
+
+ // @ts-ignore
+ private terminate;
+
+ constructor(props) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+
+ this.saveNodeType = saveNodeType.bind(this);
+ this.getSelectionState = isHoverForInteractiveType("textList")
+ .bind(this);
+
+ this.state = {};
+ }
+
+ public render() {
+ const { textList, defaultText, hoverText } = this.props;
+ const { override } = this.state;
+ return
+ {textList.map((each, idx) => {
+ const defaultHoverText = InteractiveText.defaultProps.hoverText;
+ const props = {
+ ...defaultText,
+ ...each,
+ hoverText: {
+ ...defaultHoverText,
+ ...hoverText,
+ ...(each.hoverText || {}),
+ },
+ };
+ return ;
+ })}
+ ;
+ ;
+ }
+
+ private readonly handleDraw = (moreProps, e) => {
+ const { enabled } = this.props;
+ if (enabled) {
+ const {
+ mouseXY: [, mouseY],
+ chartConfig: { yScale },
+ xAccessor,
+ currentItem,
+ } = moreProps;
+
+ const xyValue = [xAccessor(currentItem), yScale.invert(mouseY)];
+
+ const { defaultText, onChoosePosition } = this.props;
+
+ const newText = {
+ ...defaultText,
+ position: xyValue,
+ };
+ onChoosePosition(newText, moreProps, e);
+ }
+ }
+
+ private readonly handleDragComplete = (moreProps) => {
+ const { override } = this.state;
+ if (isDefined(override)) {
+ const { textList } = this.props;
+ const newTextList = textList
+ .map((each, idx) => {
+ const selected = (idx === override.index);
+ return selected
+ ? {
+ ...each,
+ position: override.position,
+ selected,
+ }
+ : {
+ ...each,
+ selected,
+ };
+ });
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onDragComplete(newTextList, moreProps);
+ });
+ }
+ }
+
+ private readonly handleDrag = (index, position) => {
+ this.setState({
+ override: {
+ index,
+ position,
+ },
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/InteractiveYCoordinate.tsx b/packages/react-financial-charts/src/interactive/InteractiveYCoordinate.tsx
new file mode 100644
index 000000000..d894c683b
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/InteractiveYCoordinate.tsx
@@ -0,0 +1,216 @@
+import * as PropTypes from "prop-types";
+import * as React from "react";
+
+import { format } from "d3-format";
+import { isDefined, noop, strokeDashTypes } from "../utils";
+
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import {
+ getValueFromOverride,
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+import { EachInteractiveYCoordinate } from "./wrapper/EachInteractiveYCoordinate";
+
+interface InteractiveYCoordinateProps {
+ onChoosePosition: any; // func
+ onDragComplete: any; // func
+ onSelect?: any; // func
+ onDelete?: any; // func
+ defaultPriceCoordinate: {
+ bgFill: string;
+ bgOpacity: number;
+ stroke: string;
+ strokeDasharray: strokeDashTypes;
+ strokeOpacity: number;
+ strokeWidth: number;
+ textFill: string;
+ fontFamily: string;
+ fontWeight: string;
+ fontStyle: string;
+ fontSize: number;
+ text: string;
+ textBox: {
+ height: number;
+ left: number;
+ padding: {
+ left: number;
+ right: number;
+ };
+ closeIcon: {
+ padding: {
+ left: number;
+ right: number;
+ };
+ width: number;
+ };
+ };
+ edge: {
+ stroke: string;
+ strokeOpacity: number;
+ strokeWidth: number;
+ fill: string;
+ fillOpacity: number;
+ };
+ };
+ hoverText: object;
+ yCoordinateList: any[];
+ enabled: boolean;
+}
+
+interface InteractiveYCoordinateState {
+ current?: any;
+ override?: any;
+}
+
+export class InteractiveYCoordinate extends React.Component {
+
+ public static defaultProps = {
+ onChoosePosition: noop,
+ onDragComplete: noop,
+ onSelect: noop,
+ onDelete: noop,
+ defaultPriceCoordinate: {
+ bgFill: "#FFFFFF",
+ bgOpacity: 1,
+
+ stroke: "#6574CD",
+ strokeOpacity: 1,
+ strokeDasharray: "ShortDash2",
+ strokeWidth: 1,
+
+ textFill: "#6574CD",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fontStyle: "normal",
+ fontWeight: "normal",
+ text: "Alert",
+ textBox: {
+ height: 24,
+ left: 20,
+ padding: { left: 10, right: 5 },
+ closeIcon: {
+ padding: { left: 5, right: 8 },
+ width: 8,
+ },
+ },
+ edge: {
+ stroke: "#6574CD",
+ strokeOpacity: 1,
+ strokeWidth: 1,
+
+ fill: "#FFFFFF",
+ fillOpacity: 1,
+ orient: "right",
+ at: "right",
+ arrowWidth: 10,
+ dx: 0,
+ rectWidth: 50,
+ rectHeight: 20,
+ displayFormat: format(".2f"),
+ },
+ },
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: 18,
+ bgWidth: 175,
+ text: "Click and drag the edge circles",
+ },
+ yCoordinateList: [],
+ };
+
+ public static contextTypes = {
+ subscribe: PropTypes.func.isRequired,
+ unsubscribe: PropTypes.func.isRequired,
+ generateSubscriptionId: PropTypes.func.isRequired,
+ chartId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
+ };
+
+ // @ts-ignore
+ private getSelectionState;
+ private saveNodeType;
+
+ // @ts-ignore
+ private terminate;
+
+ constructor(props) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+
+ this.saveNodeType = saveNodeType.bind(this);
+ this.getSelectionState = isHoverForInteractiveType("yCoordinateList")
+ .bind(this);
+
+ this.state = {};
+ }
+
+ public render() {
+ const { yCoordinateList } = this.props;
+ const { override } = this.state;
+ return (
+
+ {yCoordinateList.map((each, idx) => {
+ const props = each;
+ return (
+
+ );
+ })}
+
+ );
+ }
+
+ private readonly handleDelete = (index, moreProps) => {
+ const { onDelete, yCoordinateList } = this.props;
+
+ onDelete(yCoordinateList[index], moreProps);
+ }
+
+ private readonly handleDragComplete = (moreProps) => {
+ const { override } = this.state;
+ if (isDefined(override)) {
+ const { yCoordinateList } = this.props;
+ const newAlertList = yCoordinateList
+ .map((each, idx) => {
+ const selected = (idx === override.index);
+ return selected
+ ? {
+ ...each,
+ yValue: override.yValue,
+ selected,
+ }
+ : {
+ ...each,
+ selected,
+ };
+ });
+ const draggedAlert = newAlertList[override.index];
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onDragComplete(newAlertList, moreProps, draggedAlert);
+ });
+ }
+ }
+
+ private readonly handleDrag = (index, yValue) => {
+ this.setState({
+ override: {
+ index,
+ yValue,
+ },
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/StandardDeviationChannel.tsx b/packages/react-financial-charts/src/interactive/StandardDeviationChannel.tsx
new file mode 100644
index 000000000..1fbc2570b
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/StandardDeviationChannel.tsx
@@ -0,0 +1,257 @@
+import * as React from "react";
+
+import { isDefined, isNotDefined, noop } from "../utils";
+
+import {
+ getValueFromOverride,
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import { MouseLocationIndicator } from "./components/MouseLocationIndicator";
+import { EachLinearRegressionChannel } from "./wrapper/EachLinearRegressionChannel";
+
+interface StandardDeviationChannelProps {
+ enabled: boolean;
+ snapTo?: any; // func
+ onStart?: any; // func
+ onComplete: any; // func
+ onSelect?: any; // func
+ currentPositionStroke?: string;
+ currentPositionStrokeWidth?: number;
+ currentPositionOpacity?: number;
+ currentPositionRadius?: number;
+ appearance: {
+ stroke?: string;
+ strokeOpacity?: number;
+ strokeWidth?: number;
+ fill?: string;
+ fillOpacity?: number;
+ edgeStrokeWidth?: number;
+ edgeStroke?: string;
+ edgeFill?: string;
+ r?: number;
+ };
+ hoverText: object;
+ channels: any[];
+}
+
+interface StandardDeviationChannelState {
+ current?: any;
+ override?: any;
+}
+
+export class StandardDeviationChannel extends React.Component {
+
+ public static defaultProps = {
+ snapTo: (d) => d.close,
+ appearance: {
+ stroke: "#000000",
+ fillOpacity: 0.2,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ fill: "#8AAFE2",
+ edgeStrokeWidth: 2,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ r: 5,
+ },
+ onStart: noop,
+ onComplete: noop,
+ onSelect: noop,
+ currentPositionStroke: "#000000",
+ currentPositionOpacity: 1,
+ currentPositionStrokeWidth: 3,
+ currentPositionRadius: 4,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: "auto",
+ bgWidth: "auto",
+ text: "Click and drag the edge circles",
+ selectedText: "",
+ },
+ channels: [],
+ };
+
+ // @ts-ignore
+ private getSelectionState;
+ private mouseMoved;
+ private saveNodeType;
+
+ // @ts-ignore
+ private terminate;
+
+ public constructor(props) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.getSelectionState = isHoverForInteractiveType("channels")
+ .bind(this);
+
+ this.state = {};
+ }
+
+ public render() {
+ const { appearance } = this.props;
+ const { enabled, snapTo } = this.props;
+ const { currentPositionRadius, currentPositionStroke } = this.props;
+ const { currentPositionOpacity, currentPositionStrokeWidth } = this.props;
+ const { hoverText, channels } = this.props;
+ const { current, override } = this.state;
+
+ const eachDefaultAppearance = {
+ ...StandardDeviationChannel.defaultProps.appearance,
+ ...appearance,
+ };
+
+ const hoverTextDefault = {
+ ...StandardDeviationChannel.defaultProps.hoverText,
+ ...hoverText,
+ };
+
+ const tempLine = isDefined(current) && isDefined(current.end)
+ ?
+ : null;
+
+ return
+ {channels.map((each, idx) => {
+ const eachAppearance = isDefined(each.appearance)
+ ? { ...eachDefaultAppearance, ...each.appearance }
+ : eachDefaultAppearance;
+
+ const eachHoverText = isDefined(each.hoverText)
+ ? { ...hoverTextDefault, ...each.hoverText }
+ : hoverTextDefault;
+
+ return ;
+ })}
+ {tempLine}
+
+ ;
+ }
+
+ private handleEnd = (xyValue, moreProps, e) => {
+ const { current } = this.state;
+ const { appearance, channels } = this.props;
+
+ if (this.mouseMoved
+ && isDefined(current)
+ && isDefined(current.start)
+ ) {
+ const newChannels = [
+ ...channels.map((d) => ({ ...d, selected: false })),
+ {
+ start: current.start,
+ end: xyValue,
+ selected: true,
+ appearance,
+ },
+ ];
+
+ this.setState({
+ current: null,
+ }, () => {
+ this.props.onComplete(newChannels, moreProps, e);
+ });
+ }
+ }
+
+ private readonly handleStart = (xyValue) => {
+ const { current } = this.state;
+
+ if (isNotDefined(current) || isNotDefined(current.start)) {
+ this.mouseMoved = false;
+
+ this.setState({
+ current: {
+ start: xyValue,
+ end: null,
+ },
+ }, () => {
+ this.props.onStart();
+ });
+ }
+ }
+
+ private readonly handleDrawLine = (xyValue) => {
+ const { current } = this.state;
+
+ if (isDefined(current) && isDefined(current.start)) {
+ this.mouseMoved = true;
+ this.setState({
+ current: {
+ start: current.start,
+ end: xyValue,
+ },
+ });
+ }
+ }
+
+ private readonly handleDragLineComplete = (moreProps) => {
+ const { override } = this.state;
+ const { channels } = this.props;
+ if (isDefined(override)) {
+
+ const newChannels = channels
+ .map((each, idx) => idx === override.index
+ ? {
+ ...each,
+ start: [override.x1Value, override.y1Value],
+ end: [override.x2Value, override.y2Value],
+ selected: true,
+ }
+ : each);
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onComplete(newChannels, moreProps);
+ });
+ }
+ }
+
+ private readonly handleDragLine = (index, newXYValue) => {
+ this.setState({
+ override: {
+ index,
+ ...newXYValue,
+ },
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/TrendLine.tsx b/packages/react-financial-charts/src/interactive/TrendLine.tsx
new file mode 100644
index 000000000..060b08d2e
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/TrendLine.tsx
@@ -0,0 +1,267 @@
+import * as React from "react";
+
+import { isDefined, isNotDefined, noop, strokeDashTypes } from "../utils";
+
+import {
+ getValueFromOverride,
+ isHoverForInteractiveType,
+ saveNodeType,
+ terminate,
+} from "./utils";
+
+import { HoverTextNearMouse } from "./components/HoverTextNearMouse";
+import { MouseLocationIndicator } from "./components/MouseLocationIndicator";
+import StraightLine from "./components/StraightLine";
+import { EachTrendLine } from "./wrapper/EachTrendLine";
+
+interface TrendLineProps {
+ snap: boolean;
+ enabled: boolean;
+ snapTo?: any; // func
+ shouldDisableSnap: any; // func
+ onStart: any; // func
+ onComplete: any; // func
+ onSelect?: any; // func
+ currentPositionStroke?: string;
+ currentPositionStrokeWidth?: number;
+ currentPositionstrokeOpacity?: number;
+ currentPositionRadius?: number;
+ type:
+ "XLINE" | // extends from -Infinity to +Infinity
+ "RAY" | // extends to +/-Infinity in one direction
+ "LINE"; // extends between the set bounds
+ hoverText: object;
+ trends: any[];
+ appearance: {
+ stroke: string;
+ strokeOpacity: number;
+ strokeWidth: number;
+ strokeDasharray: strokeDashTypes;
+ edgeStrokeWidth: number;
+ edgeFill: string;
+ edgeStroke: string;
+ };
+}
+
+interface TrendLineState {
+ current?: any;
+ override?: any;
+ trends?: any;
+}
+
+export class TrendLine extends React.Component {
+
+ public static defaultProps = {
+ type: "XLINE",
+ onStart: noop,
+ onComplete: noop,
+ onSelect: noop,
+ currentPositionStroke: "#000000",
+ currentPositionstrokeOpacity: 1,
+ currentPositionStrokeWidth: 3,
+ currentPositionRadius: 0,
+ shouldDisableSnap: (e) => (e.button === 2 || e.shiftKey),
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: "auto",
+ bgWidth: "auto",
+ text: "Click to select object",
+ selectedText: "",
+ },
+ trends: [],
+ appearance: {
+ stroke: "#000000",
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ strokeDasharray: "Solid",
+ edgeStrokeWidth: 1,
+ edgeFill: "#FFFFFF",
+ edgeStroke: "#000000",
+ r: 6,
+ },
+ };
+
+ // @ts-ignore
+ private getSelectionState;
+ private mouseMoved;
+ private saveNodeType;
+ // @ts-ignore
+ private terminate;
+
+ public constructor(props: TrendLineProps) {
+ super(props);
+
+ this.terminate = terminate.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.getSelectionState = isHoverForInteractiveType("trends")
+ .bind(this);
+
+ this.state = {
+ };
+ }
+
+ public render() {
+ const { appearance } = this.props;
+ const { enabled, snap, shouldDisableSnap, snapTo, type } = this.props;
+ const { currentPositionRadius, currentPositionStroke } = this.props;
+ const { currentPositionstrokeOpacity, currentPositionStrokeWidth } = this.props;
+ const { hoverText, trends } = this.props;
+ const { current, override } = this.state;
+
+ const tempLine = isDefined(current) && isDefined(current.end)
+ ?
+ : null;
+
+ return
+ {trends.map((each, idx) => {
+ const eachAppearance = isDefined(each.appearance)
+ ? { ...appearance, ...each.appearance }
+ : appearance;
+
+ const hoverTextWithDefault = {
+ ...TrendLine.defaultProps.hoverText,
+ ...hoverText,
+ };
+
+ return ;
+ })}
+ {tempLine}
+
+ ;
+ }
+
+ private readonly handleEnd = (xyValue, moreProps, e) => {
+ const { current } = this.state;
+ const { trends, appearance, type } = this.props;
+
+ if (this.mouseMoved
+ && isDefined(current)
+ && isDefined(current.start)
+ ) {
+ const newTrends = [
+ ...trends.map((d) => ({ ...d, selected: false })),
+ {
+ start: current.start,
+ end: xyValue,
+ selected: true,
+ appearance,
+ type,
+ },
+ ];
+ this.setState({
+ current: null,
+ trends: newTrends,
+ }, () => {
+ this.props.onComplete(newTrends, moreProps, e);
+ });
+ }
+ }
+
+ private readonly handleStart = (xyValue, moreProps, e) => {
+ const { current } = this.state;
+
+ if (isNotDefined(current) || isNotDefined(current.start)) {
+ this.mouseMoved = false;
+
+ this.setState({
+ current: {
+ start: xyValue,
+ end: null,
+ },
+ }, () => {
+ this.props.onStart(moreProps, e);
+ });
+ }
+ }
+
+ private readonly handleDrawLine = (xyValue) => {
+ const { current } = this.state;
+ if (isDefined(current) && isDefined(current.start)) {
+ this.mouseMoved = true;
+ this.setState({
+ current: {
+ start: current.start,
+ end: xyValue,
+ },
+ });
+ }
+ }
+
+ private readonly handleDragLineComplete = (moreProps) => {
+ const { override } = this.state;
+ if (isDefined(override)) {
+ const { trends } = this.props;
+ const newTrends = trends
+ .map((each, idx) => idx === override.index
+ ? {
+ ...each,
+ start: [override.x1Value, override.y1Value],
+ end: [override.x2Value, override.y2Value],
+ selected: true,
+ }
+ : {
+ ...each,
+ selected: false,
+ });
+
+ this.setState({
+ override: null,
+ }, () => {
+ this.props.onComplete(newTrends, moreProps);
+ });
+ }
+ }
+
+ private readonly handleDragLine = (index, newXYValue) => {
+ this.setState({
+ override: {
+ index,
+ ...newXYValue,
+ },
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/ChannelWithArea.tsx b/packages/react-financial-charts/src/interactive/components/ChannelWithArea.tsx
new file mode 100644
index 000000000..0594a9475
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/ChannelWithArea.tsx
@@ -0,0 +1,258 @@
+import { path as d3Path } from "d3-path";
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+import { generateLine, isHovering } from "./StraightLine";
+
+import { hexToRGBA, isDefined, isNotDefined, noop } from "../../utils";
+
+interface ChannelWithAreaProps {
+ startXY?: number[];
+ endXY?: number[];
+ dy?: number;
+ interactiveCursorClass?: string;
+ stroke: string;
+ strokeWidth: number;
+ fill: string;
+ fillOpacity: number;
+ strokeOpacity: number;
+ type:
+ "XLINE" | // extends from -Infinity to +Infinity
+ "RAY" | // extends to +/-Infinity in one direction
+ "LINE"; // extends between the set bounds
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ defaultClassName?: string;
+ tolerance: number;
+ selected: boolean;
+}
+
+export class ChannelWithArea extends React.Component {
+
+ public static defaultProps = {
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ type: "LINE",
+ strokeWidth: 1,
+ tolerance: 4,
+ selected: false,
+ };
+
+ public render() {
+ const { selected, interactiveCursorClass } = this.props;
+ const { onDragStart, onDrag, onDragComplete, onHover, onUnHover } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { stroke, strokeWidth, fillOpacity, fill, strokeOpacity } = this.props;
+ const { line1, line2 } = helper(this.props, moreProps);
+
+ if (line1 !== undefined) {
+ const { x1, y1, x2, y2 } = line1;
+ const line = line2 !== undefined
+ ?
+ : null;
+ const area = isDefined(line2)
+ ?
+ : null;
+
+ return (
+
+
+ {line}
+ {area}
+
+ );
+ }
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { stroke, strokeWidth, fillOpacity, strokeOpacity, fill } = this.props;
+ const { line1, line2 } = helper(this.props, moreProps);
+
+ if (line1 !== undefined) {
+ const { x1, y1, x2, y2 } = line1;
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+
+ if (line2 !== undefined) {
+ const {
+ y1: line2Y1,
+ y2: line2Y2,
+ } = line2;
+
+ ctx.beginPath();
+ ctx.moveTo(x1, line2Y1);
+ ctx.lineTo(x2, line2Y2);
+ ctx.stroke();
+
+ ctx.fillStyle = hexToRGBA(fill, fillOpacity);
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+
+ ctx.lineTo(x2, y2);
+ ctx.lineTo(x2, line2Y2);
+ ctx.lineTo(x1, line2Y1);
+
+ ctx.closePath();
+ ctx.fill();
+ }
+ }
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { tolerance, onHover } = this.props;
+
+ if (isDefined(onHover)) {
+
+ const { line1, line2 } = helper(this.props, moreProps);
+
+ if (line1 !== undefined && line2 !== undefined) {
+ const { mouseXY, xScale, chartConfig: { yScale } } = moreProps;
+
+ const line1Hovering = isHovering({
+ x1Value: line1.x1,
+ y1Value: line1.y1,
+ x2Value: line1.x2,
+ y2Value: line1.y2,
+ type: "LINE",
+ mouseXY,
+ tolerance,
+ xScale,
+ yScale,
+ });
+
+ const line2Hovering = isHovering({
+ x1Value: line2.x1,
+ y1Value: line2.y1,
+ x2Value: line2.x2,
+ y2Value: line2.y2,
+ type: "LINE",
+ mouseXY,
+ tolerance,
+ xScale,
+ yScale,
+ });
+
+ return line1Hovering || line2Hovering;
+ }
+ }
+ return false;
+ }
+}
+
+function getPath(line1, line2) {
+ const ctx = d3Path();
+ ctx.moveTo(line1.x1, line1.y1);
+ ctx.lineTo(line1.x2, line1.y2);
+ ctx.lineTo(line1.x2, line2.y2);
+ ctx.lineTo(line1.x1, line2.y1);
+
+ ctx.closePath();
+ return ctx.toString();
+}
+
+function getLines(props: ChannelWithAreaProps, moreProps) {
+ const { startXY, endXY, dy, type } = props;
+ const { xScale } = moreProps;
+
+ if (isNotDefined(startXY) || isNotDefined(endXY)) {
+ return {};
+ }
+ const line1 = generateLine({
+ type,
+ start: startXY,
+ end: endXY,
+ xScale,
+ yScale: undefined,
+ });
+ const line2 = isDefined(dy)
+ ? {
+ ...line1,
+ y1: line1.y1 + dy,
+ y2: line1.y2 + dy,
+ }
+ : undefined;
+
+ return {
+ line1,
+ line2,
+ };
+}
+
+function helper(props: ChannelWithAreaProps, moreProps) {
+ const lines = getLines(props, moreProps);
+ const { xScale, chartConfig: { yScale } } = moreProps;
+
+ const line1 = lines.line1 !== undefined
+ ? {
+ x1: xScale(lines.line1.x1),
+ y1: yScale(lines.line1.y1),
+ x2: xScale(lines.line1.x2),
+ y2: yScale(lines.line1.y2),
+ }
+ : undefined;
+
+ const line2 = lines.line2 !== undefined
+ ? {
+ x1: line1!.x1,
+ y1: yScale(lines.line2.y1),
+ x2: line1!.x2,
+ y2: yScale(lines.line2.y2),
+ }
+ : undefined;
+
+ return {
+ lines,
+ line1,
+ line2,
+ };
+}
diff --git a/packages/react-financial-charts/src/interactive/components/ClickableCircle.tsx b/packages/react-financial-charts/src/interactive/components/ClickableCircle.tsx
new file mode 100644
index 000000000..110397927
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/ClickableCircle.tsx
@@ -0,0 +1,124 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+import { hexToRGBA, isDefined, noop } from "../../utils";
+
+interface ClickableCircleProps {
+ readonly xyProvider?: any; // func
+ readonly onDragStart: any; // func
+ readonly onDrag: any; // func
+ readonly onDragComplete: any; // func
+ readonly strokeWidth: number;
+ readonly stroke: string;
+ readonly fill: string;
+ readonly r: number;
+ readonly cx?: number;
+ readonly cy?: number;
+ readonly className: string;
+ readonly show: boolean;
+ readonly strokeOpacity: number;
+ readonly fillOpacity: number;
+ readonly interactiveCursorClass?: string;
+}
+
+export class ClickableCircle extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-interactive-line-edge",
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ onMove: noop,
+ show: false,
+ fillOpacity: 1,
+ strokeOpacity: 1,
+ };
+
+ public render() {
+ const { interactiveCursorClass } = this.props;
+ const { show } = this.props;
+ const { onDragStart, onDrag, onDragComplete } = this.props;
+
+ if (!show) {
+ return null;
+ }
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { stroke, strokeWidth, fill } = this.props;
+ const { fillOpacity, strokeOpacity } = this.props;
+ const { r } = this.props;
+
+ const [x, y] = this.helper(this.props, moreProps);
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { stroke, strokeWidth, fill } = this.props;
+ const { fillOpacity, strokeOpacity } = this.props;
+ const { r } = this.props;
+
+ const [x, y] = this.helper(this.props, moreProps);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.fillStyle = hexToRGBA(fill, fillOpacity);
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, 2 * Math.PI, false);
+ ctx.fill();
+ ctx.stroke();
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { mouseXY } = moreProps;
+ const r = this.props.r + 7;
+ const [x, y] = this.helper(this.props, moreProps);
+
+ const [mx, my] = mouseXY;
+ const hover = (x - r) < mx && mx < (x + r)
+ && (y - r) < my && my < (y + r);
+
+ return hover;
+ }
+
+ private readonly helper = (props, moreProps) => {
+ const { xyProvider, cx, cy } = props;
+
+ if (isDefined(xyProvider)) {
+ return xyProvider(moreProps);
+ }
+
+ const { xScale, chartConfig: { yScale } } = moreProps;
+
+ const x = xScale(cx);
+ const y = yScale(cy);
+ return [x, y];
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/ClickableShape.tsx b/packages/react-financial-charts/src/interactive/components/ClickableShape.tsx
new file mode 100644
index 000000000..1db5d4acf
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/ClickableShape.tsx
@@ -0,0 +1,126 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+
+import { hexToRGBA } from "../../utils";
+import { isHovering2 } from "./StraightLine";
+
+interface ClickableShapeProps {
+ fontWeight: string;
+ fontFamily: string;
+ fontStyle: string;
+ fontSize: number;
+ stroke: string;
+ strokeOpacity: number;
+ strokeWidth: number;
+ text: string;
+ textBox: {
+ closeIcon: any;
+ left: number;
+ padding: any;
+ };
+ hovering?: boolean;
+ interactiveCursorClass?: string;
+ show?: boolean;
+ onHover?: any; // func
+ onUnHover?: any; // func
+ onClick?: any; // func
+ yValue: number;
+}
+
+export class ClickableShape extends React.Component {
+
+ public static defaultProps = {
+ show: false,
+ fillOpacity: 1,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ };
+
+ private closeIcon;
+
+ public render() {
+ const { interactiveCursorClass } = this.props;
+ const { show } = this.props;
+ const { onHover, onUnHover, onClick } = this.props;
+
+ if (!show) {
+ return null;
+ }
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = () => {
+ throw new Error("svg not implemented");
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { stroke, strokeWidth, strokeOpacity, hovering, textBox } = this.props;
+
+ const [x, y] = this.helper(this.props, moreProps, ctx);
+
+ this.closeIcon = { x, y };
+ ctx.beginPath();
+
+ ctx.lineWidth = hovering ? strokeWidth + 1 : strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+ const halfWidth = textBox.closeIcon.width / 2;
+ ctx.moveTo(x - halfWidth, y - halfWidth);
+ ctx.lineTo(x + halfWidth, y + halfWidth);
+ ctx.moveTo(x - halfWidth, y + halfWidth);
+ ctx.lineTo(x + halfWidth, y - halfWidth);
+ ctx.stroke();
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { mouseXY } = moreProps;
+ if (this.closeIcon) {
+ const { textBox } = this.props;
+ const { x, y } = this.closeIcon;
+ const halfWidth = textBox.closeIcon.width / 2;
+
+ const start1 = [x - halfWidth, y - halfWidth];
+ const end1 = [x + halfWidth, y + halfWidth];
+ const start2 = [x - halfWidth, y + halfWidth];
+ const end2 = [x + halfWidth, y - halfWidth];
+
+ if (isHovering2(start1, end1, mouseXY, 3) || isHovering2(start2, end2, mouseXY, 3)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private readonly helper = (props: ClickableShapeProps, moreProps, ctx) => {
+ const { yValue, text, textBox } = props;
+ const { fontFamily, fontStyle, fontWeight, fontSize } = props;
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
+
+ const { chartConfig: { yScale } } = moreProps;
+
+ const x = textBox.left
+ + textBox.padding.left
+ + ctx.measureText(text).width
+ + textBox.padding.right
+ + textBox.closeIcon.padding.left
+ + textBox.closeIcon.width / 2;
+
+ const y = yScale(yValue);
+
+ return [x, y];
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/GannFan.tsx b/packages/react-financial-charts/src/interactive/components/GannFan.tsx
new file mode 100644
index 000000000..16613eb7a
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/GannFan.tsx
@@ -0,0 +1,297 @@
+import { pairs } from "d3-array";
+import { path as d3Path } from "d3-path";
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+import { generateLine, isHovering2 } from "./StraightLine";
+
+import {
+ hexToRGBA, isDefined,
+ isNotDefined, noop,
+} from "../../utils";
+
+interface GannFanProps {
+ startXY: number[];
+ endXY: number[];
+ interactiveCursorClass?: string;
+ stroke: string;
+ strokeWidth: number;
+ fill: string[];
+ strokeOpacity: number;
+ fillOpacity: number;
+ fontFamily: string;
+ fontSize: number;
+ fontFill: string;
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ defaultClassName?: string;
+ tolerance: number;
+ selected: boolean;
+}
+
+export class GannFan extends React.Component {
+
+ public static defaultProps = {
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ strokeWidth: 1,
+ tolerance: 4,
+ selected: false,
+ };
+
+ public render() {
+ const { selected, interactiveCursorClass } = this.props;
+ const { onDragStart, onDrag, onDragComplete, onHover, onUnHover } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { stroke, strokeWidth, fillOpacity, fill, strokeOpacity } = this.props;
+
+ const lines = this.helper(this.props, moreProps);
+ const pairsOfLines = pairs(lines);
+
+ return (
+
+ {lines.map((each, idx) => {
+ const { x1, y1, x2, y2 } = each;
+ return (
+
+ );
+ })}
+ {pairsOfLines.map(([line1, line2], idx) => {
+ const ctx = d3Path();
+ ctx.moveTo(line1.x1, line1.y1);
+ ctx.lineTo(line1.x2, line1.y2);
+ ctx.lineTo(line2.x2, line2.y2);
+ ctx.closePath();
+ return (
+
+ );
+ })}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const {
+ stroke, strokeWidth, strokeOpacity,
+ fill, fillOpacity,
+ fontFamily, fontSize, fontFill,
+ } = this.props;
+
+ const lines = this.helper(this.props, moreProps);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = fontFill;
+
+ lines.forEach((line) => {
+ const {
+ x1, y1, x2, y2, label,
+ } = line;
+
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.fillText(label.text, label.x, label.y);
+ });
+ const pairsOfLines = pairs(lines);
+
+ pairsOfLines.forEach(([line1, line2], idx) => {
+ ctx.fillStyle = hexToRGBA(fill[idx], fillOpacity);
+
+ ctx.beginPath();
+ ctx.moveTo(line1.x1, line1.y1);
+ ctx.lineTo(line1.x2, line1.y2);
+ ctx.lineTo(line2.x2, line2.y2);
+ ctx.closePath();
+ ctx.fill();
+ });
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { tolerance, onHover } = this.props;
+ const { mouseXY } = moreProps;
+ const [mouseX, mouseY] = mouseXY;
+
+ let hovering = false;
+ if (isDefined(onHover)) {
+
+ const lines = this.helper(this.props, moreProps);
+
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < lines.length; i++) {
+ const line1 = lines[i];
+
+ const left = Math.min(line1.x1, line1.x2);
+ const right = Math.max(line1.x1, line1.x2);
+ const top = Math.min(line1.y1, line1.y2);
+ const bottom = Math.max(line1.y1, line1.y2);
+
+ const isWithinLineBounds = mouseX >= left && mouseX <= right
+ && mouseY >= top && mouseY <= bottom;
+
+ hovering = isWithinLineBounds
+ && isHovering2(
+ [line1.x1, line1.y1],
+ [line1.x2, line1.y2],
+ mouseXY,
+ tolerance);
+
+ if (hovering) { break; }
+ }
+ }
+ return hovering;
+ }
+
+ private readonly getLineCoordinates = (start, endX, endY, text) => {
+ const end = [
+ endX,
+ endY,
+ ];
+ return {
+ start, end, text,
+ };
+ }
+
+ private readonly helper = (props: GannFanProps, moreProps) => {
+ const { startXY, endXY } = props;
+
+ const {
+ xScale,
+ chartConfig: { yScale },
+ } = moreProps;
+ if (isNotDefined(startXY) || isNotDefined(endXY)) {
+ return [];
+ }
+ const [x1, y1] = startXY;
+ const [x2, y2] = endXY;
+
+ const dx = x2 - x1;
+ const dy = y2 - y1;
+
+ if (dx !== 0 && dy !== 0) {
+ const halfY = this.getLineCoordinates(
+ startXY,
+ x2,
+ y1 + dy / 2,
+ "2/1",
+ );
+ const oneThirdY = this.getLineCoordinates(
+ startXY,
+ x2,
+ y1 + dy / 3,
+ "3/1",
+ );
+ const oneFourthY = this.getLineCoordinates(
+ startXY,
+ x2,
+ y1 + dy / 4,
+ "4/1",
+ );
+ const oneEighthY = this.getLineCoordinates(
+ startXY,
+ x2,
+ y1 + dy / 8,
+ "8/1",
+ );
+ const halfX = this.getLineCoordinates(
+ startXY,
+ x1 + dx / 2,
+ y2,
+ "1/2",
+ );
+ const oneThirdX = this.getLineCoordinates(
+ startXY,
+ x1 + dx / 3,
+ y2,
+ "1/3",
+ );
+ const oneFourthX = this.getLineCoordinates(
+ startXY,
+ x1 + dx / 4,
+ y2,
+ "1/4",
+ );
+ const oneEighthX = this.getLineCoordinates(
+ startXY,
+ x1 + dx / 8,
+ y2,
+ "1/8",
+ );
+ const lines = [
+ oneEighthX,
+ oneFourthX,
+ oneThirdX,
+ halfX,
+ { start: startXY, end: endXY, text: "1/1" },
+ halfY,
+ oneThirdY,
+ oneFourthY,
+ oneEighthY,
+ ];
+ const lineCoods = lines.map((line) => {
+ // tslint:disable-next-line: no-shadowed-variable
+ const { x1, y1, x2, y2 } = generateLine({
+ type: "RAY",
+ start: line.start,
+ end: line.end,
+ xScale,
+ yScale,
+ });
+ return {
+ x1: xScale(x1),
+ y1: yScale(y1),
+ x2: xScale(x2),
+ y2: yScale(y2),
+ label: {
+ x: xScale(line.end[0]),
+ y: yScale(line.end[1]),
+ text: line.text,
+ },
+ };
+ });
+ return lineCoods;
+ }
+ return [];
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/HoverTextNearMouse.tsx b/packages/react-financial-charts/src/interactive/components/HoverTextNearMouse.tsx
new file mode 100644
index 000000000..6b3486c3e
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/HoverTextNearMouse.tsx
@@ -0,0 +1,197 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { isDefined } from "../../utils";
+
+const PADDING = 10;
+const MIN_WIDTH = PADDING;
+
+interface HoverTextNearMouseProps {
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ show: boolean;
+}
+
+interface HoverTextNearMouseState {
+ textHeight?: number;
+ textWidth?: number;
+}
+
+export class HoverTextNearMouse extends React.Component {
+
+ public static defaultProps = {
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ fill: "#000000",
+ bgFill: "#FA9325",
+ bgOpacity: 0.5,
+ };
+
+ private textNode;
+
+ public constructor(props: HoverTextNearMouseProps) {
+ super(props);
+
+ this.state = {
+ textWidth: undefined,
+ textHeight: undefined,
+ };
+ }
+
+ public componentDidMount() {
+ this.updateTextSize();
+ }
+
+ public componentDidUpdate() {
+ this.updateTextSize();
+ }
+
+ public render() {
+ const { text } = this.props;
+ if (text) {
+ return (
+
+ );
+ } else {
+ return null;
+ }
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const {
+ fontFamily,
+ fontSize,
+ fill,
+ bgFill,
+ bgOpacity,
+ } = this.props;
+
+ const textMetaData = helper({
+ ...this.props,
+ bgWidth: this.getBgWidth(),
+ bgHeight: this.getBgHeight(),
+ }, moreProps);
+
+ if (textMetaData !== undefined && isDefined(textMetaData)) {
+ const { rect, text } = textMetaData;
+ return (
+
+
+ {text.text}
+
+ );
+ }
+ }
+
+ private readonly getBgHeight = () => {
+ const { bgHeight } = this.props;
+ const { textHeight } = this.state;
+
+ if (bgHeight !== "auto") {
+ return bgHeight;
+ } else if (textHeight !== undefined) {
+ return textHeight + PADDING;
+ } else {
+ return MIN_WIDTH;
+ }
+ }
+
+ private readonly getBgWidth = () => {
+ const { bgWidth } = this.props;
+ const { textWidth } = this.state;
+
+ if (bgWidth !== "auto") {
+ return bgWidth;
+ } else if (textWidth !== undefined) {
+ return textWidth + PADDING;
+ } else {
+ return MIN_WIDTH;
+ }
+ }
+
+ private readonly updateTextSize = () => {
+ const { bgWidth, bgHeight } = this.props;
+ if (bgWidth === "auto" || bgHeight === "auto") {
+ const textNode = this.textNode;
+ if (textNode) {
+ const { width, height } = textNode.getBBox();
+ if (this.state.textWidth !== width || this.state.textHeight !== height) {
+ this.setState({
+ textWidth: width,
+ textHeight: height,
+ });
+ }
+ }
+ }
+ }
+
+ private readonly saveNode = (node) => {
+ this.textNode = node;
+ }
+}
+
+function helper(props, moreProps) {
+ const {
+ show,
+ bgWidth,
+ bgHeight,
+ } = props;
+
+ const {
+ mouseXY,
+ chartConfig: { height, width },
+ show: mouseInsideCanvas,
+ } = moreProps;
+
+ if (show && mouseInsideCanvas) {
+ const [x, y] = mouseXY;
+
+ const cx = x < width / 2
+ ? x + PADDING
+ : x - bgWidth - PADDING;
+
+ const cy = y < height / 2
+ ? y + PADDING
+ : y - bgHeight - PADDING;
+
+ const rect = {
+ x: cx,
+ y: cy,
+ width: bgWidth,
+ height: bgHeight,
+ };
+
+ const text = {
+ text: props.text,
+ x: cx + PADDING / 2,
+ y: cy + bgHeight / 2,
+ };
+
+ return {
+ rect,
+ text,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/InteractiveText.tsx b/packages/react-financial-charts/src/interactive/components/InteractiveText.tsx
new file mode 100644
index 000000000..e69ba9f1b
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/InteractiveText.tsx
@@ -0,0 +1,171 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+
+import { hexToRGBA, isDefined, noop } from "../../utils";
+
+interface InteractiveTextProps {
+ bgFill: string;
+ bgOpacity: number;
+ bgStrokeWidth: number;
+ bgStroke: string;
+ textFill: string;
+ fontFamily: string;
+ fontSize: number;
+ fontWeight: number | string;
+ fontStyle: string;
+ text: string;
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ position?: any;
+ defaultClassName?: string;
+ interactiveCursorClass?: string;
+ tolerance: number;
+ selected: boolean;
+}
+
+export class InteractiveText extends React.Component {
+
+ public static defaultProps = {
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ type: "SD", // standard dev
+ fontWeight: "normal", // standard dev
+ tolerance: 4,
+ selected: false,
+ };
+
+ private calculateTextWidth = true;
+ private textWidth;
+
+ public UNSAFE_componentWillReceiveProps(nextProps) {
+ this.calculateTextWidth = (
+ nextProps.text !== this.props.text
+ || nextProps.fontStyle !== this.props.fontStyle
+ || nextProps.fontWeight !== this.props.fontWeight
+ || nextProps.fontSize !== this.props.fontSize
+ || nextProps.fontFamily !== this.props.fontFamily
+ );
+ }
+
+ public render() {
+ const { selected, interactiveCursorClass } = this.props;
+ const { onHover, onUnHover } = this.props;
+ const { onDragStart, onDrag, onDragComplete } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { onHover } = this.props;
+
+ if (
+ isDefined(onHover)
+ && isDefined(this.textWidth)
+ && !this.calculateTextWidth
+ ) {
+ const { rect } = this.helper(this.props, moreProps, this.textWidth);
+ const { mouseXY: [x, y] } = moreProps;
+
+ if (
+ x >= rect.x
+ && y >= rect.y
+ && x <= rect.x + rect.width
+ && y <= rect.y + rect.height
+ ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const {
+ bgFill,
+ bgOpacity,
+ bgStrokeWidth,
+ bgStroke,
+ textFill,
+ fontFamily,
+ fontSize,
+ fontStyle,
+ fontWeight,
+ text,
+ } = this.props;
+
+ if (this.calculateTextWidth) {
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
+ const { width } = ctx.measureText(text);
+ this.textWidth = width;
+ this.calculateTextWidth = false;
+ }
+
+ const { selected } = this.props;
+
+ const { x, y, rect } = this.helper(this.props, moreProps, this.textWidth);
+
+ ctx.fillStyle = hexToRGBA(bgFill, bgOpacity);
+
+ ctx.beginPath();
+ ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
+
+ if (selected) {
+ ctx.strokeStyle = bgStroke;
+ ctx.lineWidth = bgStrokeWidth;
+ ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
+ }
+
+ ctx.fillStyle = textFill;
+ ctx.textBaseline = "middle";
+ ctx.textAlign = "center";
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
+
+ ctx.beginPath();
+ ctx.fillText(text, x, y);
+ }
+
+ private readonly renderSVG = () => {
+ throw new Error("svg not implemented");
+ }
+
+ private readonly helper = (props, moreProps, textWidth) => {
+ const { position, fontSize } = props;
+
+ const { xScale, chartConfig: { yScale } } = moreProps;
+
+ const [xValue, yValue] = position;
+ const x = xScale(xValue);
+ const y = yScale(yValue);
+
+ const rect = {
+ x: x - textWidth / 2 - fontSize,
+ y: y - fontSize,
+ width: textWidth + fontSize * 2,
+ height: fontSize * 2,
+ };
+
+ return {
+ x, y, rect,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/InteractiveYCoordinate.tsx b/packages/react-financial-charts/src/interactive/components/InteractiveYCoordinate.tsx
new file mode 100644
index 000000000..7b16fdc38
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/InteractiveYCoordinate.tsx
@@ -0,0 +1,212 @@
+import * as React from "react";
+
+import { drawOnCanvas } from "../../coordinates/EdgeCoordinateV3";
+import { getYCoordinate } from "../../coordinates/MouseCoordinateY";
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+import { getStrokeDasharrayCanvas, hexToRGBA, isDefined, noop } from "../../utils";
+
+interface InteractiveYCoordinateProps {
+ bgFill: string;
+ bgOpacity: number;
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ strokeDasharray: string;
+ textFill: string;
+ fontFamily: string;
+ fontSize: number;
+ fontWeight: number | string;
+ fontStyle: string;
+ text: string;
+ edge: object;
+ textBox: {
+ closeIcon: any;
+ padding: any;
+ };
+ yValue: number;
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ defaultClassName?: string;
+ interactiveCursorClass?: string;
+ tolerance: number;
+ selected: boolean;
+ hovering: boolean;
+}
+
+export class InteractiveYCoordinate extends React.Component {
+
+ public static defaultProps = {
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ fontWeight: "normal", // standard dev
+ strokeWidth: 1,
+ tolerance: 4,
+ selected: false,
+ hovering: false,
+ };
+
+ private width;
+
+ public render() {
+ const { interactiveCursorClass } = this.props;
+ const { onHover, onUnHover } = this.props;
+ const { onDragStart, onDrag, onDragComplete } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = () => {
+ throw new Error("svg not implemented");
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const {
+ bgFill,
+ bgOpacity,
+
+ textFill,
+ fontFamily,
+ fontSize,
+
+ fontStyle,
+ fontWeight,
+ stroke,
+ strokeWidth,
+ strokeOpacity,
+ strokeDasharray,
+ text,
+ textBox,
+ edge,
+ } = this.props;
+
+ const { selected, hovering } = this.props;
+
+ const values = helper(this.props, moreProps);
+ if (values == null) { return; }
+
+ const { x1, x2, y, rect } = values;
+
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+
+ ctx.beginPath();
+ if (selected || hovering) {
+ ctx.lineWidth = strokeWidth + 1;
+ } else {
+ ctx.lineWidth = strokeWidth;
+ }
+ ctx.textBaseline = "middle";
+ ctx.textAlign = "start";
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
+
+ this.width = textBox.padding.left
+ + ctx.measureText(text).width
+ + textBox.padding.right
+ + textBox.closeIcon.padding.left
+ + textBox.closeIcon.width
+ + textBox.closeIcon.padding.right;
+
+ ctx.setLineDash(getStrokeDasharrayCanvas(strokeDasharray));
+ ctx.moveTo(x1, y);
+ ctx.lineTo(rect.x, y);
+
+ ctx.moveTo(rect.x + this.width, y);
+ ctx.lineTo(x2, y);
+ ctx.stroke();
+
+ ctx.setLineDash([]);
+
+ ctx.fillStyle = hexToRGBA(bgFill, bgOpacity);
+
+ ctx.fillRect(rect.x, rect.y, this.width, rect.height);
+ ctx.strokeRect(rect.x, rect.y, this.width, rect.height);
+
+ ctx.fillStyle = textFill;
+
+ ctx.beginPath();
+ ctx.fillText(text, rect.x + 10, y);
+ const newEdge = {
+ ...edge,
+ textFill,
+ fontFamily,
+ fontSize,
+ opacity: bgOpacity,
+ };
+
+ // @ts-ignore
+ const yValue = edge.displayFormat(this.props.yValue);
+ const yCoord = getYCoordinate(y, yValue, newEdge, moreProps);
+ drawOnCanvas(ctx, yCoord);
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { onHover } = this.props;
+
+ if (isDefined(onHover)) {
+ const values = helper(this.props, moreProps);
+ if (values == null) { return false; }
+
+ const { x1, x2, y, rect } = values;
+ const { mouseXY: [mouseX, mouseY] } = moreProps;
+
+ if (
+ mouseX >= rect.x
+ && mouseX <= rect.x + this.width
+ && mouseY >= rect.y
+ && mouseY <= rect.y + rect.height
+ ) {
+ return true;
+ }
+ if (
+ x1 <= mouseX
+ && x2 >= mouseX
+ && Math.abs(mouseY - y) < 4
+ ) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+function helper(props, moreProps) {
+ const { yValue, textBox } = props;
+
+ const { chartConfig: { width, yScale, height } } = moreProps;
+
+ const y = Math.round(yScale(yValue));
+
+ if (y >= 0 && y <= height) {
+ const rect = {
+ x: textBox.left,
+ y: y - textBox.height / 2,
+ height: textBox.height,
+ };
+ return {
+ x1: 0,
+ x2: width,
+ y,
+ rect,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/LinearRegressionChannelWithArea.tsx b/packages/react-financial-charts/src/interactive/components/LinearRegressionChannelWithArea.tsx
new file mode 100644
index 000000000..16f0e4d2c
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/LinearRegressionChannelWithArea.tsx
@@ -0,0 +1,221 @@
+import { deviation, sum } from "d3-array";
+import { path as d3Path } from "d3-path";
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+import { isHovering2 } from "./StraightLine";
+
+import { getClosestItemIndexes, hexToRGBA, isDefined, noop, zipper } from "../../utils";
+
+interface LinearRegressionChannelWithAreaProps {
+ x1Value: any;
+ x2Value: any;
+ type:
+ "SD" | // standard deviation channel
+ "Raff"; // Raff Regression Channel
+ interactiveCursorClass?: string;
+ stroke: string;
+ strokeWidth: number;
+ fill: string;
+ fillOpacity: number;
+ strokeOpacity: number;
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ defaultClassName?: string;
+ tolerance: number;
+ selected: boolean;
+}
+
+export class LinearRegressionChannelWithArea extends React.Component {
+
+ public static defaultProps = {
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ type: "SD", // standard dev
+ strokeWidth: 1,
+ tolerance: 4,
+ selected: false,
+ };
+
+ public render() {
+ const { selected, interactiveCursorClass } = this.props;
+ const { onHover, onUnHover } = this.props;
+
+ return ;
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { stroke, strokeWidth, fillOpacity, strokeOpacity, fill } = this.props;
+ const { x1, y1, x2, y2, dy } = helper(this.props, moreProps);
+ const line = {
+ strokeWidth,
+ stroke,
+ strokeOpacity,
+ };
+ const ctx = d3Path();
+ ctx.moveTo(x1, y1 - dy);
+ ctx.lineTo(x2, y2 - dy);
+ ctx.lineTo(x2, y2 + dy);
+ ctx.lineTo(x1, y1 + dy);
+ ctx.closePath();
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { stroke, strokeWidth, fillOpacity, strokeOpacity, fill } = this.props;
+ const { x1, y1, x2, y2, dy } = helper(this.props, moreProps);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+ ctx.fillStyle = hexToRGBA(fill, fillOpacity);
+
+ ctx.beginPath();
+ ctx.moveTo(x1, y1 - dy);
+ ctx.lineTo(x2, y2 - dy);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(x2, y2 + dy);
+ ctx.lineTo(x1, y1 + dy);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(x1, y1 - dy);
+ ctx.lineTo(x2, y2 - dy);
+ ctx.lineTo(x2, y2 + dy);
+ ctx.lineTo(x1, y1 + dy);
+ ctx.closePath();
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(x2, y2);
+ ctx.lineTo(x1, y1);
+ ctx.stroke();
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { tolerance, onHover } = this.props;
+
+ if (isDefined(onHover)) {
+ const { mouseXY } = moreProps;
+
+ const { x1, y1, x2, y2, dy } = helper(this.props, moreProps);
+ const yDiffs = [-dy, 0, dy];
+
+ const hovering = yDiffs.reduce((result, diff) => result || isHovering2(
+ [x1, y1 + diff], [x2, y2 + diff], mouseXY, tolerance,
+ ), false);
+ return hovering;
+ }
+ return false;
+ }
+}
+
+export function edge1Provider(props) {
+ return function (moreProps) {
+ const { x1, y1 } = helper(props, moreProps);
+ return [x1, y1];
+ };
+}
+
+export function edge2Provider(props) {
+ return function (moreProps) {
+ const { x2, y2 } = helper(props, moreProps);
+ return [x2, y2];
+ };
+}
+
+function helper(props, moreProps) {
+ const { x1Value, x2Value, type } = props;
+
+ const { xScale, chartConfig: { yScale }, fullData } = moreProps;
+ const { xAccessor } = moreProps;
+
+ const { left } = getClosestItemIndexes(fullData, x1Value, xAccessor);
+ const { right } = getClosestItemIndexes(fullData, x2Value, xAccessor);
+
+ const startIndex = Math.min(left, right);
+ const endIndex = Math.max(left, right) + 1;
+
+ const array = fullData.slice(startIndex, endIndex);
+
+ const xs = array.map((d) => xAccessor(d).valueOf());
+ const ys = array.map((d) => d.close);
+ const n = array.length;
+
+ const combine = zipper()
+ .combine((x, y) => x * y);
+
+ // @ts-ignore
+ const xys = combine(xs, ys);
+ const xSquareds = xs.map((x) => Math.pow(x, 2));
+
+ const b = (n * sum(xys) - sum(xs) * sum(ys)) / (n * sum(xSquareds) - Math.pow(sum(xs), 2));
+ const a = (sum(ys) - b * sum(xs)) / n;
+
+ const newy1 = a + b * x1Value;
+ const newy2 = a + b * x2Value;
+
+ const x1 = xScale(x1Value);
+ const y1 = yScale(newy1);
+ const x2 = xScale(x2Value);
+ const y2 = yScale(newy2);
+
+ const stdDev = type === "SD"
+ ? deviation(array, (d) => d.close)
+ : 0;
+
+ const dy = yScale(newy1 - stdDev) - y1;
+
+ return {
+ x1, y1, x2, y2, dy,
+ };
+}
diff --git a/packages/react-financial-charts/src/interactive/components/MouseLocationIndicator.tsx b/packages/react-financial-charts/src/interactive/components/MouseLocationIndicator.tsx
new file mode 100644
index 000000000..e4fe4543d
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/MouseLocationIndicator.tsx
@@ -0,0 +1,149 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+
+import { functor, getClosestValue, isDefined, noop, shallowEqual } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+
+interface MouseLocationIndicatorProps {
+ enabled: boolean;
+ snap: boolean;
+ shouldDisableSnap: any; // func;
+ snapTo?: any; // func;
+ onMouseMove: any; // func;
+ onMouseDown: any; // func;
+ onClick: any; // func;
+ r?: number;
+ stroke: string;
+ strokeWidth: number;
+ opacity: number;
+ disablePan: boolean;
+}
+
+export class MouseLocationIndicator extends React.Component {
+
+ public static defaultProps = {
+ onMouseMove: noop,
+ onMouseDown: noop,
+ onClick: noop,
+ shouldDisableSnap: functor(false),
+ stroke: "#000000",
+ strokeWidth: 1,
+ opacity: 1,
+ disablePan: true,
+ };
+
+ private mutableState;
+
+ constructor(props) {
+ super(props);
+ this.renderSVG = this.renderSVG.bind(this);
+ this.drawOnCanvas = this.drawOnCanvas.bind(this);
+
+ this.handleMousePosChange = this.handleMousePosChange.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handleClick = this.handleClick.bind(this);
+ this.xy = this.xy.bind(this);
+
+ this.mutableState = {};
+ }
+
+ public render() {
+ const { enabled, disablePan } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly xy = (moreProps, e) => {
+ const { xAccessor, plotData } = moreProps;
+ const { mouseXY, currentItem, xScale, chartConfig: { yScale } } = moreProps;
+ const { enabled, snap, shouldDisableSnap, snapTo } = this.props;
+
+ if (enabled && isDefined(currentItem) && isDefined(e)) {
+ const xValue = snap && !shouldDisableSnap(e)
+ ? xAccessor(currentItem)
+ : getXValue(xScale, xAccessor, mouseXY, plotData);
+ const yValue = snap && !shouldDisableSnap(e)
+ ? getClosestValue(snapTo(currentItem), yScale.invert(mouseXY[1]))
+ : yScale.invert(mouseXY[1]);
+
+ const x = xScale(xValue);
+ const y = yScale(yValue);
+
+ return { xValue, yValue, x, y };
+ }
+ }
+
+ private readonly handleClick = (moreProps, e) => {
+ const pos = this.xy(moreProps, e);
+ if (pos !== undefined && isDefined(pos)) {
+ const { xValue, yValue, x, y } = pos;
+ this.mutableState = { x, y };
+ this.props.onClick([xValue, yValue], moreProps, e);
+ }
+ }
+
+ private readonly handleMouseDown = (moreProps, e) => {
+ const pos = this.xy(moreProps, e);
+ if (pos !== undefined && isDefined(pos)) {
+ const { xValue, yValue, x, y } = pos;
+ this.mutableState = { x, y };
+ this.props.onMouseDown([xValue, yValue], moreProps, e);
+ }
+ }
+
+ private readonly handleMousePosChange = (moreProps, e) => {
+ if (!shallowEqual(moreProps.mousXY, moreProps.prevMouseXY)) {
+ const pos = this.xy(moreProps, e);
+ if (pos !== undefined && isDefined(pos)) {
+ const { xValue, yValue, x, y } = pos;
+ this.mutableState = { x, y };
+ this.props.onMouseMove([xValue, yValue], e);
+ }
+ }
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { enabled, r, stroke, strokeWidth } = this.props;
+ const { x, y } = this.mutableState;
+ const { show } = moreProps;
+ if (enabled && show && isDefined(x)) {
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = stroke;
+ ctx.moveTo(x, y);
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, 2 * Math.PI, false);
+ ctx.stroke();
+ }
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { enabled, r, stroke, strokeWidth, opacity } = this.props;
+ const { x, y } = this.mutableState;
+ const { show } = moreProps;
+
+ return enabled && show && isDefined(x)
+ ?
+ : null;
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/components/StraightLine.tsx b/packages/react-financial-charts/src/interactive/components/StraightLine.tsx
new file mode 100644
index 000000000..cfa2a90d8
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/StraightLine.tsx
@@ -0,0 +1,328 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+
+import {
+ getStrokeDasharray,
+ hexToRGBA,
+ isDefined,
+ noop,
+ strokeDashTypes,
+} from "../../utils";
+
+interface StraightLineProps {
+ x1Value: any;
+ x2Value: any;
+ y1Value: any;
+ y2Value: any;
+
+ interactiveCursorClass?: string;
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ strokeDasharray: strokeDashTypes;
+ type:
+ "XLINE" | // extends from -Infinity to +Infinity
+ "RAY" | // extends to +/-Infinity in one direction
+ "LINE"; // extends between the set bounds
+
+ onEdge1Drag: any; // func
+ onEdge2Drag: any; // func
+ onDragStart: any; // func
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ defaultClassName?: string;
+ r: number;
+ edgeFill: string;
+ edgeStroke: string;
+ edgeStrokeWidth: number;
+ withEdge: boolean;
+ children: any; // func
+ tolerance: number;
+ selected: boolean;
+}
+
+class StraightLine extends React.Component {
+
+ public static defaultProps = {
+ onEdge1Drag: noop,
+ onEdge2Drag: noop,
+ onDragStart: noop,
+ onDrag: noop,
+ onDragComplete: noop,
+ edgeStrokeWidth: 3,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ r: 10,
+ withEdge: false,
+ strokeWidth: 1,
+ strokeDasharray: "Solid",
+ children: noop,
+ tolerance: 7,
+ selected: false,
+ };
+
+ public render() {
+ const { selected, interactiveCursorClass } = this.props;
+ const { onDragStart, onDrag, onDragComplete, onHover, onUnHover } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { tolerance, onHover } = this.props;
+
+ if (isDefined(onHover)) {
+ const { x1Value, x2Value, y1Value, y2Value, type } = this.props;
+ const { mouseXY, xScale } = moreProps;
+ const { chartConfig: { yScale } } = moreProps;
+
+ const hovering = isHovering({
+ x1Value, y1Value,
+ x2Value, y2Value,
+ mouseXY,
+ type,
+ tolerance,
+ xScale,
+ yScale,
+ });
+
+ return hovering;
+ }
+ return false;
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { stroke, strokeWidth, strokeOpacity, strokeDasharray } = this.props;
+
+ const lineWidth = strokeWidth;
+
+ const { x1, y1, x2, y2 } = helper(this.props, moreProps);
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { stroke, strokeWidth, strokeOpacity, strokeDasharray } = this.props;
+ const { x1, y1, x2, y2 } = helper(this.props, moreProps);
+
+ ctx.lineWidth = strokeWidth;
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+ ctx.setLineDash(getStrokeDasharray(strokeDasharray).split(","));
+
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ }
+}
+
+export function isHovering2(start, end, [mouseX, mouseY], tolerance) {
+ const m = getSlope(start, end);
+
+ if (m !== undefined && isDefined(m)) {
+ const b = getYIntercept(m, end);
+ const y = m * mouseX + b;
+ return (mouseY < y + tolerance)
+ && mouseY > (y - tolerance)
+ && mouseX > Math.min(start[0], end[0]) - tolerance
+ && mouseX < Math.max(start[0], end[0]) + tolerance;
+ } else {
+ return mouseY >= Math.min(start[1], end[1])
+ && mouseY <= Math.max(start[1], end[1])
+ && mouseX < start[0] + tolerance
+ && mouseX > start[0] - tolerance;
+ }
+}
+
+export function isHovering({
+ x1Value, y1Value,
+ x2Value, y2Value,
+ mouseXY,
+ type,
+ tolerance,
+ xScale,
+ yScale,
+}) {
+
+ const line = generateLine({
+ type,
+ start: [x1Value, y1Value],
+ end: [x2Value, y2Value],
+ xScale,
+ yScale,
+ });
+
+ const start = [xScale(line.x1), yScale(line.y1)];
+ const end = [xScale(line.x2), yScale(line.y2)];
+
+ const m = getSlope(start, end);
+ const [mouseX, mouseY] = mouseXY;
+
+ if (m !== undefined && isDefined(m)) {
+ const b = getYIntercept(m, end);
+ const y = m * mouseX + b;
+
+ return mouseY < (y + tolerance)
+ && mouseY > (y - tolerance)
+ && mouseX > Math.min(start[0], end[0]) - tolerance
+ && mouseX < Math.max(start[0], end[0]) + tolerance;
+ } else {
+ return mouseY >= Math.min(start[1], end[1])
+ && mouseY <= Math.max(start[1], end[1])
+ && mouseX < start[0] + tolerance
+ && mouseX > start[0] - tolerance;
+ }
+}
+
+function helper(props, moreProps) {
+ const { x1Value, x2Value, y1Value, y2Value, type } = props;
+
+ const { xScale, chartConfig: { yScale } } = moreProps;
+
+ const modLine = generateLine({
+ type,
+ start: [x1Value, y1Value],
+ end: [x2Value, y2Value],
+ xScale,
+ yScale,
+ });
+
+ const x1 = xScale(modLine.x1);
+ const y1 = yScale(modLine.y1);
+ const x2 = xScale(modLine.x2);
+ const y2 = yScale(modLine.y2);
+
+ return {
+ x1, y1, x2, y2,
+ };
+}
+
+export function getSlope(start, end) {
+ const m /* slope */ = end[0] === start[0]
+ ? undefined
+ : (end[1] - start[1]) / (end[0] - start[0]);
+ return m;
+}
+export function getYIntercept(m, end) {
+ const b /* y intercept */ = -1 * m * end[0] + end[1];
+ return b;
+}
+
+export function generateLine({
+ type, start, end, xScale, yScale,
+}) {
+ const m /* slope */ = getSlope(start, end);
+ // console.log(end[0] - start[0], m)
+ const b /* y intercept */ = getYIntercept(m, start);
+
+ switch (type) {
+ case "XLINE":
+ return getXLineCoordinates({
+ start, end, xScale, yScale, m, b,
+ });
+ case "RAY":
+ return getRayCoordinates({
+ start, end, xScale, yScale, m, b,
+ });
+ default:
+ case "LINE":
+ return getLineCoordinates({
+ start, end,
+ });
+ }
+}
+
+function getXLineCoordinates({
+ start, end, xScale, yScale, m, b,
+}) {
+ const [xBegin, xFinish] = xScale.domain();
+ const [yBegin, yFinish] = yScale.domain();
+
+ if (end[0] === start[0]) {
+ return {
+ x1: end[0], y1: yBegin,
+ x2: end[0], y2: yFinish,
+ };
+ }
+ const [x1, x2] = end[0] > start[0]
+ ? [xBegin, xFinish]
+ : [xFinish, xBegin];
+
+ return {
+ x1, y1: m * x1 + b,
+ x2, y2: m * x2 + b,
+ };
+}
+
+function getRayCoordinates({
+ start, end, xScale, yScale, m, b,
+}) {
+ const [xBegin, xFinish] = xScale.domain();
+ const [yBegin, yFinish] = yScale.domain();
+
+ const x1 = start[0];
+ if (end[0] === start[0]) {
+ return {
+ x1,
+ y1: start[1],
+ x2: x1,
+ y2: end[1] > start[1] ? yFinish : yBegin,
+ };
+ }
+
+ const x2 = end[0] > start[0]
+ ? xFinish
+ : xBegin;
+
+ return {
+ x1, y1: m * x1 + b,
+ x2, y2: m * x2 + b,
+ };
+}
+
+function getLineCoordinates({
+ start, end,
+}) {
+
+ const [x1, y1] = start;
+ const [x2, y2] = end;
+ if (end[0] === start[0]) {
+ return {
+ x1,
+ y1: start[1],
+ x2: x1,
+ y2: end[1],
+ };
+ }
+
+ return {
+ x1, y1,
+ x2, y2,
+ };
+}
+
+export default StraightLine;
diff --git a/packages/react-financial-charts/src/interactive/components/Text.tsx b/packages/react-financial-charts/src/interactive/components/Text.tsx
new file mode 100644
index 000000000..36da57ec8
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/components/Text.tsx
@@ -0,0 +1,74 @@
+import * as React from "react";
+
+import GenericChartComponent from "../../GenericChartComponent";
+import { getMouseCanvas } from "../../GenericComponent";
+
+interface TextProps {
+ xyProvider: (moreProps: any) => number[];
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ children: string;
+ selected: boolean;
+}
+
+export class Text extends React.Component {
+
+ public static defaultProps = {
+ selected: false,
+ };
+
+ public render() {
+ const { selected } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly isHover = () => {
+ return false;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const {
+ xyProvider,
+ fontFamily,
+ fontSize,
+ fill,
+ children,
+ } = this.props;
+ const [x, y] = xyProvider(moreProps);
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = fill;
+
+ ctx.beginPath();
+ ctx.fillText(children, x, y);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const {
+ xyProvider,
+ fontFamily,
+ fontSize,
+ fill,
+ children,
+ } = this.props;
+ const [x, y] = xyProvider(moreProps);
+
+ return {children};
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/index.ts b/packages/react-financial-charts/src/interactive/index.ts
new file mode 100644
index 000000000..03ea2aa7d
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/index.ts
@@ -0,0 +1,10 @@
+export { TrendLine } from "./TrendLine";
+export { FibonacciRetracement } from "./FibonacciRetracement";
+export { EquidistantChannel } from "./EquidistantChannel";
+export { StandardDeviationChannel } from "./StandardDeviationChannel";
+export { GannFan } from "./GannFan";
+export { ClickCallback } from "./ClickCallback";
+export { Brush } from "./Brush";
+export { InteractiveText } from "./InteractiveText";
+export { InteractiveYCoordinate } from "./InteractiveYCoordinate";
+export { DrawingObjectSelector } from "./DrawingObjectSelector";
diff --git a/packages/react-financial-charts/src/interactive/utils.ts b/packages/react-financial-charts/src/interactive/utils.ts
new file mode 100644
index 000000000..561fd5ca2
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/utils.ts
@@ -0,0 +1,103 @@
+import {
+ find,
+ isDefined,
+ isNotDefined,
+ mapObject,
+} from "../utils";
+
+export function getValueFromOverride(override, index, key, defaultValue) {
+ if (isDefined(override) && override.index === index) {
+ return override[key];
+ }
+ return defaultValue;
+}
+
+export function terminate() {
+ // @ts-ignore
+ this.setState({
+ current: null,
+ override: null,
+ });
+}
+
+export function saveNodeType(type) {
+ return (node) => {
+ // @ts-ignore
+ if (isNotDefined(node) && isDefined(this.nodes[type])) {
+ // @ts-ignore
+ delete this.nodes[type];
+ } else {
+ // @ts-ignore
+ this.nodes[type] = node;
+ }
+ // console.error(this.nodes)
+ };
+}
+export function isHoverForInteractiveType(interactiveType) {
+ return function (moreProps) { // this has to be function as it is bound to this
+
+ // @ts-ignore
+ if (isDefined(this.nodes)) {
+ // @ts-ignore
+ const selecedNodes = this.nodes
+ .map((node) => node.isHover(moreProps));
+ // @ts-ignore
+ const interactive = this.props[interactiveType].map((t, idx) => {
+ return {
+ ...t,
+ selected: selecedNodes[idx],
+ };
+ });
+ return interactive;
+ }
+ };
+}
+
+export function isHover(moreProps) {
+ // @ts-ignore
+ const hovering = mapObject(this.nodes, (node) => node.isHover(moreProps))
+ .reduce((a, b) => {
+ return a || b;
+ });
+ return hovering;
+}
+
+function getMouseXY(moreProps, [ox, oy]) {
+ if (Array.isArray(moreProps.mouseXY)) {
+ const { mouseXY: [x, y] } = moreProps;
+ const mouseXY = [
+ x - ox,
+ y - oy,
+ ];
+ return mouseXY;
+ }
+ return moreProps.mouseXY;
+}
+
+export function getMorePropsForChart(moreProps, chartId) {
+ const { chartConfig: chartConfigList } = moreProps;
+ const chartConfig = find(chartConfigList, (each) => each.id === chartId);
+
+ const { origin } = chartConfig;
+ const mouseXY = getMouseXY(moreProps, origin);
+ return {
+ ...moreProps,
+ chartConfig,
+ mouseXY,
+ };
+}
+
+export function getSelected(interactives) {
+ const selected = interactives
+ .map((each) => {
+ const objects = each.objects.filter((obj) => {
+ return obj.selected;
+ });
+ return {
+ ...each,
+ objects,
+ };
+ })
+ .filter((each) => each.objects.length > 0);
+ return selected;
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachEquidistantChannel.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachEquidistantChannel.tsx
new file mode 100644
index 000000000..62bfc79c5
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachEquidistantChannel.tsx
@@ -0,0 +1,310 @@
+import * as React from "react";
+
+import { isDefined, noop } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { ChannelWithArea } from "../components/ChannelWithArea";
+import { ClickableCircle } from "../components/ClickableCircle";
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+
+interface EachEquidistantChannelProps {
+ readonly startXY: number[];
+ readonly endXY: number[];
+ readonly dy?: number;
+ readonly interactive: boolean;
+ readonly selected: boolean;
+ readonly hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ };
+ readonly appearance: {
+ stroke: string;
+ fillOpacity: number;
+ strokeOpacity: number;
+ strokeWidth: number;
+ fill: string;
+ edgeStroke: string;
+ edgeFill: string;
+ edgeFill2: string;
+ edgeStrokeWidth: number;
+ r: number;
+ };
+ readonly index?: number;
+ readonly onDrag: any; // func
+ readonly onDragComplete: any; // func
+}
+
+interface EachEquidistantChannelState {
+ hover: boolean;
+}
+
+export class EachEquidistantChannel extends React.Component {
+
+ public static defaultProps = {
+ yDisplayFormat: (d) => d.toFixed(2),
+ interactive: true,
+ selected: false,
+ onDrag: noop,
+ onDragComplete: noop,
+ hoverText: {
+ enable: false,
+ },
+ };
+
+ private dragStart;
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ constructor(props: EachEquidistantChannelProps) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const { startXY, endXY, dy } = this.props;
+ const { interactive, hoverText, appearance } = this.props;
+ const {
+ edgeFill, edgeFill2,
+ stroke, strokeWidth, strokeOpacity,
+ fill, fillOpacity,
+ } = appearance;
+ const { selected } = this.props;
+ const { onDragComplete } = this.props;
+ const { hover } = this.state;
+ const { enable: hoverTextEnabled, ...restHoverTextProps } = hoverText;
+
+ const hoverHandler = interactive
+ ? { onHover: this.handleHover, onUnHover: this.handleHover }
+ : {};
+
+ const line1Edge = isDefined(startXY) && isDefined(endXY)
+ ?
+ {this.getEdgeCircle({
+ xy: startXY,
+ dragHandler: this.handleLine1Edge1Drag,
+ cursor: "react-stockcharts-move-cursor",
+ fill: edgeFill,
+ edge: "line1edge1",
+ })}
+ {this.getEdgeCircle({
+ xy: endXY,
+ dragHandler: this.handleLine1Edge2Drag,
+ cursor: "react-stockcharts-move-cursor",
+ fill: edgeFill,
+ edge: "line1edge2",
+ })}
+
+ : null;
+ const line2Edge = dy !== undefined && isDefined(dy)
+ ?
+ {this.getEdgeCircle({
+ xy: [startXY[0], startXY[1] + dy],
+ dragHandler: this.handleChannelHeightChange,
+ cursor: "react-stockcharts-ns-resize-cursor",
+ fill: edgeFill2,
+ edge: "line2edge1",
+ })}
+ {this.getEdgeCircle({
+ xy: [endXY[0], endXY[1] + dy],
+ dragHandler: this.handleChannelHeightChange,
+ cursor: "react-stockcharts-ns-resize-cursor",
+ fill: edgeFill2,
+ edge: "line2edge2",
+ })}
+
+ : null;
+
+ return
+
+ {line1Edge}
+ {line2Edge}
+
+ ;
+ }
+
+ private readonly getEdgeCircle = ({ xy, dragHandler, cursor, fill, edge }) => {
+ const { hover } = this.state;
+ const { appearance } = this.props;
+ const { edgeStroke, edgeStrokeWidth, r } = appearance;
+ const { selected } = this.props;
+ const { onDragComplete } = this.props;
+
+ return ;
+ }
+
+ private readonly handleChannelHeightChange = (moreProps) => {
+ const { index, onDrag } = this.props;
+
+ const {
+ startXY, endXY,
+ } = this.dragStart;
+
+ const { chartConfig: { yScale } } = moreProps;
+ const { startPos, mouseXY } = moreProps;
+
+ const y2 = yScale(endXY[1]);
+
+ const dy = startPos[1] - mouseXY[1];
+
+ const newY2Value = yScale.invert(y2 - dy);
+
+ const newDy = newY2Value - endXY[1] + this.dragStart.dy;
+
+ onDrag(index, {
+ startXY,
+ endXY,
+ dy: newDy,
+ });
+ }
+
+ private readonly handleLine1Edge2Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ endXY,
+ } = this.dragStart;
+
+ const {
+ startPos, mouseXY, xAccessor,
+ xScale, fullData,
+ chartConfig: { yScale },
+ } = moreProps;
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const x1 = xScale(endXY[0]);
+ const y1 = yScale(endXY[1]);
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+
+ onDrag(index, {
+ startXY: this.dragStart.startXY,
+ endXY: [newX1Value, newY1Value],
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleLine1Edge1Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ startXY,
+ } = this.dragStart;
+
+ const {
+ startPos, mouseXY, xAccessor,
+ xScale, fullData,
+ chartConfig: { yScale },
+ } = moreProps;
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const x1 = xScale(startXY[0]);
+ const y1 = yScale(startXY[1]);
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+
+ onDrag(index, {
+ startXY: [newX1Value, newY1Value],
+ endXY: this.dragStart.endXY,
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleChannelDrag = (moreProps) => {
+ const { index, onDrag } = this.props;
+
+ const {
+ startXY, endXY,
+ } = this.dragStart;
+
+ const { xScale, chartConfig: { yScale }, xAccessor, fullData } = moreProps;
+ const { startPos, mouseXY } = moreProps;
+
+ const x1 = xScale(startXY[0]);
+ const y1 = yScale(startXY[1]);
+ const x2 = xScale(endXY[0]);
+ const y2 = yScale(endXY[1]);
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+ const newX2Value = getXValue(xScale, xAccessor, [x2 - dx, y2 - dy], fullData);
+ const newY2Value = yScale.invert(y2 - dy);
+
+ // const newDy = newY2Value - endXY[1] + this.dragStart.dy;
+
+ onDrag(index, {
+ startXY: [newX1Value, newY1Value],
+ endXY: [newX2Value, newY2Value],
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleDragStart = () => {
+ const {
+ startXY, endXY, dy,
+ } = this.props;
+
+ this.dragStart = {
+ startXY, endXY, dy,
+ };
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachFibRetracement.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachFibRetracement.tsx
new file mode 100644
index 000000000..369475841
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachFibRetracement.tsx
@@ -0,0 +1,354 @@
+import * as React from "react";
+
+import { head, last, noop } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { ClickableCircle } from "../components/ClickableCircle";
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+import StraightLine, { generateLine } from "../components/StraightLine";
+import { Text } from "../components/Text";
+import { getNewXY } from "./EachTrendLine";
+
+interface EachFibRetracementProps {
+ x1: any;
+ x2: any;
+ y1: number;
+ y2: number;
+ yDisplayFormat: any; // func
+ type: string;
+ selected: boolean;
+ appearance: {
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ fontFamily: string;
+ fontSize: number;
+ fontFill: string;
+ edgeStroke: string;
+ edgeFill: string;
+ nsEdgeFill: string;
+ edgeStrokeWidth: number;
+ r: number;
+ };
+ interactive: boolean;
+ hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ selectedText: string;
+ };
+ index?: number;
+ onDrag: any; // func
+ onDragComplete: any; // func
+}
+
+interface EachFibRetracementState {
+ hover: boolean;
+}
+
+export class EachFibRetracement extends React.Component {
+
+ public static defaultProps = {
+ yDisplayFormat: (d) => d.toFixed(2),
+ interactive: true,
+ appearance: {
+ stroke: "#000000",
+ strokeWidth: 1,
+ strokeOpacity: 1,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 10,
+ fontFill: "#000000",
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ nsEdgeFill: "#000000",
+ edgeStrokeWidth: 1,
+ r: 5,
+ },
+ selected: false,
+ onDrag: noop,
+ onDragComplete: noop,
+ hoverText: {
+ enable: false,
+ },
+ };
+
+ private dragStart;
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ public constructor(props) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const { x1, x2, y1, y2 } = this.props;
+ const { interactive, yDisplayFormat, type, appearance } = this.props;
+ const { stroke, strokeWidth, strokeOpacity } = appearance;
+ const { fontFamily, fontSize, fontFill } = appearance;
+ const { edgeStroke, edgeFill, nsEdgeFill, edgeStrokeWidth, r } = appearance;
+ const { hoverText, selected } = this.props;
+ const { hover } = this.state;
+ const { onDragComplete } = this.props;
+ const lines = helper({ x1, x2, y1, y2 });
+
+ const {
+ enable: hoverTextEnabled,
+ selectedText: hoverTextSelected,
+ text: hoverTextUnselected,
+ ...restHoverTextProps
+ } = hoverText;
+
+ const lineType = type === "EXTEND" ? "XLINE" : type === "BOUND" ? "LINE" : "RAY";
+ const dir = head(lines).y1 > last(lines).y1 ? 3 : -1.3;
+
+ return (
+
+ {lines.map((line, j) => {
+ const text = `${yDisplayFormat(line.y)} (${line.percent.toFixed(2)}%)`;
+
+ const xyProvider = ({ xScale, chartConfig }) => {
+ const { yScale } = chartConfig;
+ const { x1: lineX1, y1: lineY1, x2: lineX2 } = generateLine({
+ type: lineType,
+ start: [line.x1, line.y],
+ end: [line.x2, line.y],
+ xScale,
+ yScale,
+ });
+
+ const x = xScale(Math.min(lineX1, lineX2)) + 10;
+ const y = yScale(lineY1) + dir * 4;
+ return [x, y];
+ };
+
+ const firstOrLast = (j === 0) || (j === lines.length - 1);
+
+ const interactiveCursorClass = firstOrLast
+ ? "react-stockcharts-ns-resize-cursor"
+ : "react-stockcharts-move-cursor";
+
+ const interactiveEdgeCursorClass = firstOrLast
+ ? "react-stockcharts-ns-resize-cursor"
+ : "react-stockcharts-ew-resize-cursor";
+
+ const dragHandler = j === 0
+ ? this.handleLineNSResizeTop
+ : j === lines.length - 1
+ ? this.handleLineNSResizeBottom
+ : this.handleLineMove;
+
+ const edge1DragHandler = j === 0
+ ? this.handleLineNSResizeTop
+ : j === lines.length - 1
+ ? this.handleLineNSResizeBottom
+ : this.handleEdge1Drag;
+ const edge2DragHandler = j === 0
+ ? this.handleLineNSResizeTop
+ : j === lines.length - 1
+ ? this.handleLineNSResizeBottom
+ : this.handleEdge2Drag;
+
+ const hoverHandler = interactive
+ ? { onHover: this.handleHover, onUnHover: this.handleHover }
+ : {};
+ return
+
+ {text}
+
+
+ ;
+ })}
+
+
+ );
+ }
+
+ private readonly handleEdge2Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ x1, y1, y2,
+ } = this.props;
+
+ const [x2] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1,
+ y1,
+ x2,
+ y2,
+ });
+ }
+
+ private readonly handleEdge1Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ y1, x2, y2,
+ } = this.props;
+
+ const [x1] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1,
+ y1,
+ x2,
+ y2,
+ });
+ }
+
+ private readonly handleLineNSResizeBottom = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ x1, y1, x2,
+ } = this.props;
+
+ const [, y2] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1,
+ y1,
+ x2,
+ y2,
+ });
+ }
+
+ private readonly handleLineNSResizeTop = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ x1, x2, y2,
+ } = this.props;
+
+ const [, y1] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1,
+ y1,
+ x2,
+ y2,
+ });
+ }
+
+ private readonly handleLineMove = (moreProps) => {
+ const { index, onDrag } = this.props;
+
+ const {
+ x1: x1Value, y1: y1Value, x2: x2Value, y2: y2Value,
+ } = this.dragStart;
+
+ const { xScale, chartConfig: { yScale }, xAccessor, fullData } = moreProps;
+ const { startPos, mouseXY } = moreProps;
+
+ const x1 = xScale(x1Value);
+ const y1 = yScale(y1Value);
+ const x2 = xScale(x2Value);
+ const y2 = yScale(y2Value);
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+ const newX2Value = getXValue(xScale, xAccessor, [x2 - dx, y2 - dy], fullData);
+ const newY2Value = yScale.invert(y2 - dy);
+
+ onDrag(index, {
+ x1: newX1Value,
+ y1: newY1Value,
+ x2: newX2Value,
+ y2: newY2Value,
+ });
+ }
+
+ private readonly handleLineDragStart = () => {
+ const {
+ x1, y1, x2, y2,
+ } = this.props;
+
+ this.dragStart = {
+ x1, y1, x2, y2,
+ };
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+}
+
+function helper({ x1, y1, x2, y2 }) {
+ const dy = y2 - y1;
+ const retracements = [100, 61.8, 50, 38.2, 23.6, 0]
+ .map((each) => ({
+ percent: each,
+ x1,
+ x2,
+ y: (y2 - (each / 100) * dy),
+ }));
+
+ return retracements;
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachGannFan.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachGannFan.tsx
new file mode 100644
index 000000000..98108103e
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachGannFan.tsx
@@ -0,0 +1,300 @@
+import * as React from "react";
+
+import { isDefined, noop } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { ClickableCircle } from "../components/ClickableCircle";
+import { GannFan } from "../components/GannFan";
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+
+interface EachGannFanProps {
+ startXY: number[];
+ endXY: number[];
+ dy?: number;
+ interactive: boolean;
+ selected: boolean;
+ appearance: {
+ stroke: string;
+ strokeOpacity: number;
+ fillOpacity: number;
+ strokeWidth: number;
+ edgeStroke: string;
+ edgeFill: string;
+ edgeStrokeWidth: number;
+ r: number;
+ fill: string[];
+ fontFamily: string;
+ fontSize: number;
+ fontFill: string;
+ };
+ hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ selectedText: string;
+ };
+ index?: number;
+ onDrag: any; // func
+ onDragComplete: any; // func
+}
+
+interface EachGannFanState {
+ hover: boolean;
+}
+
+export class EachGannFan extends React.Component {
+
+ public static defaultProps = {
+ yDisplayFormat: (d) => d.toFixed(2),
+ interactive: true,
+ selected: false,
+ appearance: {
+ stroke: "#000000",
+ fillOpacity: 0.2,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ edgeStrokeWidth: 1,
+ r: 5,
+ fill: [
+ "#1f77b4",
+ "#ff7f0e",
+ "#2ca02c",
+ "#d62728",
+ "#9467bd",
+ "#8c564b",
+ "#e377c2",
+ "#7f7f7f",
+ ],
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 10,
+ fontFill: "#000000",
+ },
+ onDrag: noop,
+ onDragComplete: noop,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: 18,
+ bgWidth: 120,
+ text: "Click to select object",
+ },
+ };
+
+ // @ts-ignore
+ private isHover;
+ private dragStart;
+ private saveNodeType;
+
+ constructor(props) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const { startXY, endXY } = this.props;
+ const { interactive, appearance } = this.props;
+ const {
+ edgeFill,
+ stroke, strokeWidth, strokeOpacity,
+ fill, fillOpacity,
+ } = appearance;
+ const { fontFamily, fontSize, fontFill } = appearance;
+ const { hoverText, selected } = this.props;
+ const { onDragComplete } = this.props;
+ const { hover } = this.state;
+ const { enable: hoverTextEnabled, ...restHoverTextProps } = hoverText;
+
+ const hoverHandler = interactive
+ ? { onHover: this.handleHover, onUnHover: this.handleHover }
+ : {};
+
+ const line1Edge = isDefined(startXY) && isDefined(endXY)
+ ?
+ {this.getEdgeCircle({
+ xy: startXY,
+ dragHandler: this.handleLine1Edge1Drag,
+ cursor: "react-stockcharts-move-cursor",
+ fill: edgeFill,
+ edge: "edge1",
+ })}
+ {this.getEdgeCircle({
+ xy: endXY,
+ dragHandler: this.handleLine1Edge2Drag,
+ cursor: "react-stockcharts-move-cursor",
+ fill: edgeFill,
+ edge: "edge2",
+ })}
+
+ : null;
+
+ return (
+
+
+ {line1Edge}
+
+
+ );
+ }
+
+ private readonly getEdgeCircle = ({ xy, dragHandler, cursor, fill, edge }) => {
+ const { hover } = this.state;
+ const { selected, appearance } = this.props;
+ const { edgeStroke, edgeStrokeWidth, r } = appearance;
+ const { onDragComplete } = this.props;
+
+ return ;
+ }
+
+ private readonly handleLine1Edge2Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ endXY,
+ } = this.dragStart;
+
+ const {
+ startPos, mouseXY, xAccessor,
+ xScale, fullData,
+ chartConfig: { yScale },
+ } = moreProps;
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const x1 = xScale(endXY[0]);
+ const y1 = yScale(endXY[1]);
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+
+ onDrag(index, {
+ startXY: this.dragStart.startXY,
+ endXY: [newX1Value, newY1Value],
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleLine1Edge1Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ startXY,
+ } = this.dragStart;
+
+ const {
+ startPos, mouseXY, xAccessor,
+ xScale, fullData,
+ chartConfig: { yScale },
+ } = moreProps;
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const x1 = xScale(startXY[0]);
+ const y1 = yScale(startXY[1]);
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+
+ onDrag(index, {
+ startXY: [newX1Value, newY1Value],
+ endXY: this.dragStart.endXY,
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleFanDrag = (moreProps) => {
+ const { index, onDrag } = this.props;
+
+ const {
+ startXY, endXY,
+ } = this.dragStart;
+
+ const { xScale, chartConfig: { yScale }, xAccessor, fullData } = moreProps;
+ const { startPos, mouseXY } = moreProps;
+
+ const x1 = xScale(startXY[0]);
+ const y1 = yScale(startXY[1]);
+ const x2 = xScale(endXY[0]);
+ const y2 = yScale(endXY[1]);
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+ const newX2Value = getXValue(xScale, xAccessor, [x2 - dx, y2 - dy], fullData);
+ const newY2Value = yScale.invert(y2 - dy);
+
+ // const newDy = newY2Value - endXY[1] + this.dragStart.dy;
+
+ onDrag(index, {
+ startXY: [newX1Value, newY1Value],
+ endXY: [newX2Value, newY2Value],
+ dy: this.dragStart.dy,
+ });
+ }
+
+ private readonly handleDragStart = () => {
+ const {
+ startXY, endXY, dy,
+ } = this.props;
+
+ this.dragStart = {
+ startXY, endXY, dy,
+ };
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachInteractiveYCoordinate.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachInteractiveYCoordinate.tsx
new file mode 100644
index 000000000..f4ab1800d
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachInteractiveYCoordinate.tsx
@@ -0,0 +1,203 @@
+import * as React from "react";
+
+import { noop } from "../../utils";
+import { isHover, saveNodeType } from "../utils";
+
+import { ClickableShape } from "../components/ClickableShape";
+import { InteractiveYCoordinate } from "../components/InteractiveYCoordinate";
+
+interface EachInteractiveYCoordinateProps {
+ index?: number;
+ draggable: boolean;
+ yValue: number;
+ bgFill: string;
+ bgOpacity: number;
+ stroke: string;
+ strokeWidth: number;
+ strokeOpacity: number;
+ strokeDasharray: string;
+ textFill: string;
+ fontWeight: string;
+ fontFamily: string;
+ fontStyle: string;
+ fontSize: number;
+ text: string;
+ selected: boolean;
+ edge: object;
+ textBox: {
+ closeIcon: any;
+ left: number;
+ padding: any;
+ };
+ onDrag: any; // func
+ onDragComplete: any; // func
+ onDelete: any; // func
+}
+
+interface EachInteractiveYCoordinateState {
+ closeIconHover: boolean;
+ hover: boolean;
+}
+
+export class EachInteractiveYCoordinate extends React.Component {
+
+ public static defaultProps = {
+ onDrag: noop,
+ onDragComplete: noop,
+ strokeWidth: 1,
+ opacity: 1,
+ selected: false,
+ fill: "#FFFFFF",
+ draggable: false,
+ };
+
+ private dragStartPosition;
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ public constructor(props) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ closeIconHover: false,
+ };
+ }
+
+ public render() {
+ const {
+ yValue,
+ bgFill,
+ bgOpacity,
+ textFill,
+ fontFamily,
+ fontSize,
+ fontWeight,
+ fontStyle,
+ text,
+ // hoverText,
+ selected,
+ onDragComplete,
+ stroke,
+ strokeOpacity,
+ strokeDasharray,
+ strokeWidth,
+ edge,
+ textBox,
+ draggable,
+ } = this.props;
+
+ const { hover, closeIconHover } = this.state;
+
+ const hoverHandler = {
+ onHover: this.handleHover,
+ onUnHover: this.handleHover,
+ };
+
+ const dragProps = draggable
+ ? {
+ onDragStart: this.handleDragStart,
+ onDrag: this.handleDrag,
+ onDragComplete,
+ }
+ : {};
+ return (
+
+
+
+
+ );
+ }
+
+ private readonly handleCloseIconHover = (moreProps) => {
+ if (this.state.closeIconHover !== moreProps.hovering) {
+ this.setState({
+ closeIconHover: moreProps.hovering,
+ });
+ }
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ closeIconHover: moreProps.hovering ? this.state.closeIconHover : false,
+ });
+ }
+ }
+
+ private readonly handleDelete = (moreProps) => {
+ const { index, onDelete } = this.props;
+ onDelete(index, moreProps);
+ }
+
+ private readonly handleDrag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ mouseXY: [, mouseY],
+ chartConfig: { yScale },
+ } = moreProps;
+
+ const { dy } = this.dragStartPosition;
+
+ const newYValue = yScale.invert(mouseY - dy);
+
+ onDrag(index, newYValue);
+ }
+
+ private readonly handleDragStart = (moreProps) => {
+ const {
+ yValue,
+ } = this.props;
+ const { mouseXY } = moreProps;
+ const { chartConfig: { yScale } } = moreProps;
+ const [, mouseY] = mouseXY;
+
+ const dy = mouseY - yScale(yValue);
+
+ this.dragStartPosition = {
+ yValue, dy,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachLinearRegressionChannel.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachLinearRegressionChannel.tsx
new file mode 100644
index 000000000..8b815081c
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachLinearRegressionChannel.tsx
@@ -0,0 +1,221 @@
+import * as React from "react";
+
+import { noop } from "../../utils";
+import { getCurrentItem } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+import {
+ edge1Provider,
+ edge2Provider,
+ LinearRegressionChannelWithArea,
+} from "../components/LinearRegressionChannelWithArea";
+
+import { ClickableCircle } from "../components/ClickableCircle";
+
+interface EachLinearRegressionChannelProps {
+ defaultClassName?: string;
+ x1Value: any;
+ x2Value: any;
+ index?: number;
+ appearance: {
+ stroke: string;
+ fillOpacity: number;
+ strokeOpacity: number;
+ strokeWidth: number;
+ fill: string;
+ edgeStrokeWidth: number;
+ edgeStroke: string;
+ edgeFill: string;
+ r: number;
+ };
+ edgeInteractiveCursor?: string;
+ onDrag: any; // func
+ onDragComplete: any; // func
+ snapTo?: any; // func
+ interactive: boolean;
+ selected: boolean;
+ hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ selectedText: string;
+ };
+}
+
+interface EachLinearRegressionChannelState {
+ hover: boolean;
+}
+
+export class EachLinearRegressionChannel extends React.Component {
+
+ public static defaultProps = {
+ onDrag: noop,
+ onDragComplete: noop,
+ appearance: {
+ stroke: "#000000",
+ fillOpacity: 0.7,
+ strokeOpacity: 1,
+ strokeWidth: 1,
+ fill: "#8AAFE2",
+ edgeStrokeWidth: 2,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ r: 5,
+ },
+ interactive: true,
+ selected: false,
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: 18,
+ bgWidth: 175,
+ text: "Click and drag the edge circles",
+ },
+ };
+
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ constructor(props) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const {
+ x1Value,
+ x2Value,
+ appearance,
+ edgeInteractiveCursor,
+ hoverText,
+ interactive,
+ selected,
+ onDragComplete,
+ } = this.props;
+ const {
+ stroke,
+ strokeWidth,
+ strokeOpacity,
+ fill,
+ fillOpacity,
+ r,
+ edgeStrokeWidth,
+ edgeFill,
+ edgeStroke,
+ } = appearance;
+ const { hover } = this.state;
+
+ const hoverHandler = interactive
+ ? { onHover: this.handleHover, onUnHover: this.handleHover }
+ : {};
+
+ const {
+ enable: hoverTextEnabled,
+ selectedText: hoverTextSelected,
+ text: hoverTextUnselected,
+ ...restHoverTextProps
+ } = hoverText;
+
+ return
+
+
+
+
+ ;
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+
+ private readonly handleEdge2Drag = (moreProps) => {
+ const { index, onDrag, snapTo } = this.props;
+ const {
+ x1Value,
+ } = this.props;
+
+ const [x2Value] = getNewXY(moreProps, snapTo);
+
+ onDrag(index, {
+ x1Value,
+ x2Value,
+ });
+ }
+
+ private readonly handleEdge1Drag = (moreProps) => {
+ const { index, onDrag, snapTo } = this.props;
+ const {
+ x2Value,
+ } = this.props;
+
+ const [x1Value] = getNewXY(moreProps, snapTo);
+
+ onDrag(index, {
+ x1Value,
+ x2Value,
+ });
+ }
+}
+
+export function getNewXY(moreProps, snapTo) {
+ const { xScale, xAccessor, plotData, mouseXY } = moreProps;
+
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+ const x = xAccessor(currentItem);
+ const y = snapTo(currentItem);
+
+ return [x, y];
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachText.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachText.tsx
new file mode 100644
index 000000000..376b106b1
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachText.tsx
@@ -0,0 +1,193 @@
+import * as React from "react";
+
+import { noop } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+import { InteractiveText } from "../components/InteractiveText";
+
+interface EachTextProps {
+ index?: number;
+ position?: any;
+ bgFill: string;
+ bgOpacity: number;
+ bgStrokeWidth: number;
+ bgStroke?: string;
+ textFill: string;
+ fontWeight: string;
+ fontFamily: string;
+ fontStyle: string;
+ fontSize: number;
+ text: string;
+ selected: boolean;
+ onDrag: any; // func
+ onDragComplete: any; // func
+ hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ selectedText: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ };
+}
+
+interface EachTextState {
+ hover: boolean;
+}
+
+export class EachText extends React.Component {
+
+ public static defaultProps = {
+ onDrag: noop,
+ onDragComplete: noop,
+ bgOpacity: 1,
+ bgStrokeWidth: 1,
+ selected: false,
+ fill: "#8AAFE2",
+ hoverText: {
+ ...HoverTextNearMouse.defaultProps,
+ enable: true,
+ bgHeight: "auto",
+ bgWidth: "auto",
+ text: "Click to select object",
+ },
+ };
+
+ private dragStartPosition;
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ constructor(props) {
+ super(props);
+
+ this.handleHover = this.handleHover.bind(this);
+
+ this.handleDragStart = this.handleDragStart.bind(this);
+ this.handleDrag = this.handleDrag.bind(this);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const {
+ position,
+ bgFill,
+ bgOpacity,
+ bgStroke,
+ bgStrokeWidth,
+ textFill,
+ fontFamily,
+ fontSize,
+ fontWeight,
+ fontStyle,
+ text,
+ hoverText,
+ selected,
+ onDragComplete,
+ } = this.props;
+ const { hover } = this.state;
+
+ const hoverHandler = {
+ onHover: this.handleHover,
+ onUnHover: this.handleHover,
+ };
+
+ const {
+ enable: hoverTextEnabled,
+ selectedText: hoverTextSelected,
+ text: hoverTextUnselected,
+ ...restHoverTextProps
+ } = hoverText;
+
+ return (
+
+
+
+
+ );
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+
+ private readonly handleDrag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ mouseXY: [, mouseY],
+ chartConfig: { yScale },
+ xAccessor,
+ mouseXY,
+ plotData,
+ xScale,
+ } = moreProps;
+
+ const { dx, dy } = this.dragStartPosition;
+ const xValue = xScale.invert(
+ xScale(getXValue(xScale, xAccessor, mouseXY, plotData)) - dx,
+ );
+ // xScale.invert(xScale(xAccessor(currentItem)) - dx);
+ const xyValue = [
+ xValue,
+ yScale.invert(mouseY - dy),
+ ];
+
+ onDrag(index, xyValue);
+ }
+
+ private readonly handleDragStart = (moreProps) => {
+ const {
+ position,
+ } = this.props;
+ const { mouseXY } = moreProps;
+ const { chartConfig: { yScale }, xScale } = moreProps;
+ const [mouseX, mouseY] = mouseXY;
+
+ const [textCX, textCY] = position;
+ const dx = mouseX - xScale(textCX);
+ const dy = mouseY - yScale(textCY);
+
+ this.dragStartPosition = {
+ position, dx, dy,
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/interactive/wrapper/EachTrendLine.tsx b/packages/react-financial-charts/src/interactive/wrapper/EachTrendLine.tsx
new file mode 100644
index 000000000..1061ffd68
--- /dev/null
+++ b/packages/react-financial-charts/src/interactive/wrapper/EachTrendLine.tsx
@@ -0,0 +1,298 @@
+import * as React from "react";
+
+import { ascending as d3Ascending } from "d3-array";
+import { noop, strokeDashTypes } from "../../utils";
+import { getXValue } from "../../utils/ChartDataUtil";
+import { isHover, saveNodeType } from "../utils";
+
+import { ClickableCircle } from "../components/ClickableCircle";
+import { HoverTextNearMouse } from "../components/HoverTextNearMouse";
+import StraightLine from "../components/StraightLine";
+
+interface EachTrendLineProps {
+ x1Value: any;
+ x2Value: any;
+ y1Value: any;
+ y2Value: any;
+ index?: number;
+ type: "XLINE" | // extends from -Infinity to +Infinity
+ "RAY" | // extends to +/-Infinity in one direction
+ "LINE"; // extends between the set bounds
+ onDrag: any; // func
+ onEdge1Drag: any; // func
+ onEdge2Drag: any; // func
+ onDragComplete: any; // func
+ onSelect: any; // func
+ onUnSelect: any; // func
+ r: number;
+ strokeOpacity: number;
+ defaultClassName?: string;
+ selected?: boolean;
+ stroke: string;
+ strokeWidth: number;
+ strokeDasharray: strokeDashTypes;
+ edgeStrokeWidth: number;
+ edgeStroke: string;
+ edgeInteractiveCursor: string;
+ lineInteractiveCursor: string;
+ edgeFill: string;
+ hoverText: {
+ enable: boolean;
+ fontFamily: string;
+ fontSize: number;
+ fill: string;
+ text: string;
+ selectedText: string;
+ bgFill: string;
+ bgOpacity: number;
+ bgWidth: number | string;
+ bgHeight: number | string;
+ };
+}
+
+interface EachTrendLineState {
+ anchor?: string;
+ hover?: any;
+}
+
+export class EachTrendLine extends React.Component {
+
+ public static defaultProps = {
+ onDrag: noop,
+ onEdge1Drag: noop,
+ onEdge2Drag: noop,
+ onDragComplete: noop,
+ onSelect: noop,
+ onUnSelect: noop,
+ selected: false,
+ edgeStroke: "#000000",
+ edgeFill: "#FFFFFF",
+ edgeStrokeWidth: 2,
+ r: 5,
+ strokeWidth: 1,
+ strokeOpacity: 1,
+ strokeDasharray: "Solid",
+ hoverText: {
+ enable: false,
+ },
+ };
+
+ private dragStart;
+ // @ts-ignore
+ private isHover;
+ private saveNodeType;
+
+ constructor(props) {
+ super(props);
+
+ this.isHover = isHover.bind(this);
+ this.saveNodeType = saveNodeType.bind(this);
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ public render() {
+ const {
+ x1Value,
+ y1Value,
+ x2Value,
+ y2Value,
+ type,
+ stroke,
+ strokeWidth,
+ strokeOpacity,
+ strokeDasharray,
+ r,
+ edgeStrokeWidth,
+ edgeFill,
+ edgeStroke,
+ edgeInteractiveCursor,
+ lineInteractiveCursor,
+ hoverText,
+ selected,
+
+ onDragComplete,
+ } = this.props;
+
+ const {
+ enable: hoverTextEnabled,
+ selectedText: hoverTextSelected,
+ text: hoverTextUnselected,
+ ...restHoverTextProps
+ } = hoverText;
+
+ const { hover, anchor } = this.state;
+
+ return
+
+
+
+
+ ;
+ }
+
+ private readonly handleHover = (moreProps) => {
+ if (this.state.hover !== moreProps.hovering) {
+ this.setState({
+ hover: moreProps.hovering,
+ });
+ }
+ }
+
+ private readonly handleEdge2Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ x1Value, y1Value,
+ } = this.props;
+
+ const [x2Value, y2Value] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1Value,
+ y1Value,
+ x2Value,
+ y2Value,
+ });
+ }
+
+ private readonly handleEdge1Drag = (moreProps) => {
+ const { index, onDrag } = this.props;
+ const {
+ x2Value, y2Value,
+ } = this.props;
+
+ const [x1Value, y1Value] = getNewXY(moreProps);
+
+ onDrag(index, {
+ x1Value,
+ y1Value,
+ x2Value,
+ y2Value,
+ });
+ }
+
+ private readonly handleDragComplete = (...rest) => {
+ this.setState({
+ anchor: undefined,
+ });
+ this.props.onDragComplete(...rest);
+ }
+
+ private readonly handleEdge2DragStart = () => {
+ this.setState({
+ anchor: "edge1",
+ });
+ }
+
+ private readonly handleEdge1DragStart = () => {
+ this.setState({
+ anchor: "edge2",
+ });
+ }
+
+ private readonly handleLineDrag = (moreProps) => {
+ const { index, onDrag } = this.props;
+
+ const {
+ x1Value, y1Value,
+ x2Value, y2Value,
+ } = this.dragStart;
+
+ const { xScale, chartConfig: { yScale }, xAccessor, fullData } = moreProps;
+ const { startPos, mouseXY } = moreProps;
+
+ const x1 = xScale(x1Value);
+ const y1 = yScale(y1Value);
+ const x2 = xScale(x2Value);
+ const y2 = yScale(y2Value);
+
+ const dx = startPos[0] - mouseXY[0];
+ const dy = startPos[1] - mouseXY[1];
+
+ const newX1Value = getXValue(xScale, xAccessor, [x1 - dx, y1 - dy], fullData);
+ const newY1Value = yScale.invert(y1 - dy);
+ const newX2Value = getXValue(xScale, xAccessor, [x2 - dx, y2 - dy], fullData);
+ const newY2Value = yScale.invert(y2 - dy);
+
+ onDrag(index, {
+ x1Value: newX1Value,
+ y1Value: newY1Value,
+ x2Value: newX2Value,
+ y2Value: newY2Value,
+ });
+ }
+
+ private readonly handleLineDragStart = () => {
+ const {
+ x1Value, y1Value,
+ x2Value, y2Value,
+ } = this.props;
+
+ this.dragStart = {
+ x1Value, y1Value,
+ x2Value, y2Value,
+ };
+ }
+}
+
+export function getNewXY(moreProps) {
+ const { xScale, chartConfig: { yScale }, xAccessor, plotData, mouseXY } = moreProps;
+ const mouseY = mouseXY[1];
+
+ const x = getXValue(xScale, xAccessor, mouseXY, plotData);
+
+ const [small, big] = yScale.domain().slice().sort(d3Ascending);
+ const y = yScale.invert(mouseY);
+ const newY = Math.min(Math.max(y, small), big);
+
+ return [x, newY];
+}
diff --git a/packages/react-financial-charts/src/scale/discontinuousTimeScaleProvider.ts b/packages/react-financial-charts/src/scale/discontinuousTimeScaleProvider.ts
new file mode 100644
index 000000000..a7f6d09d2
--- /dev/null
+++ b/packages/react-financial-charts/src/scale/discontinuousTimeScaleProvider.ts
@@ -0,0 +1,225 @@
+import { timeFormat, timeFormatDefaultLocale } from "d3-time-format";
+
+import { identity, isNotDefined, slidingWindow, zipper } from "../utils";
+import financeDiscontinuousScale from "./financeDiscontinuousScale";
+import { defaultFormatters, levelDefinition } from "./levels";
+
+function evaluateLevel(d, date, i, formatters) {
+ return levelDefinition
+ .map((eachLevel, idx) => {
+ return {
+ level: levelDefinition.length - idx - 1,
+
+ // @ts-ignore
+ format: formatters[eachLevel(d, date, i)],
+ };
+ })
+ .find((l) => !!l.format);
+}
+
+const discontinuousIndexCalculator = slidingWindow()
+ .windowSize(2)
+ // @ts-ignore
+ .undefinedValue((d, idx, { initialIndex, formatters }) => {
+ const i = initialIndex;
+ const row = {
+ date: d.getTime(),
+ startOf30Seconds: false,
+ startOfMinute: false,
+ startOf5Minutes: false,
+ startOf15Minutes: false,
+ startOf30Minutes: false,
+ startOfHour: false,
+ startOfEighthOfADay: false,
+ startOfQuarterDay: false,
+ startOfHalfDay: false,
+ startOfDay: true,
+ startOfWeek: false,
+ startOfMonth: false,
+ startOfQuarter: false,
+ startOfYear: false,
+ };
+ const level = evaluateLevel(row, d, i, formatters);
+ return { ...row, index: i, ...level };
+ });
+
+const discontinuousIndexCalculatorLocalTime = discontinuousIndexCalculator
+ .accumulator(([prevDate, nowDate], i, idx, { initialIndex, formatters }) => {
+ const startOf30Seconds = nowDate.getSeconds() % 30 === 0;
+
+ const startOfMinute = nowDate.getMinutes() !== prevDate.getMinutes();
+ const startOf5Minutes = startOfMinute && nowDate.getMinutes() % 5 <= prevDate.getMinutes() % 5;
+ const startOf15Minutes = startOfMinute && nowDate.getMinutes() % 15 <= prevDate.getMinutes() % 15;
+ const startOf30Minutes = startOfMinute && nowDate.getMinutes() % 30 <= prevDate.getMinutes() % 30;
+
+ const startOfHour = nowDate.getHours() !== prevDate.getHours();
+
+ const startOfEighthOfADay = startOfHour && nowDate.getHours() % 3 === 0;
+ const startOfQuarterDay = startOfHour && nowDate.getHours() % 6 === 0;
+ const startOfHalfDay = startOfHour && nowDate.getHours() % 12 === 0;
+
+ const startOfDay = nowDate.getDay() !== prevDate.getDay();
+ // According to ISO calendar
+ // Sunday = 0, Monday = 1, ... Saturday = 6
+ // day of week of today < day of week of yesterday then today is start of week
+ const startOfWeek = nowDate.getDay() < prevDate.getDay();
+ // month of today != month of yesterday then today is start of month
+ const startOfMonth = nowDate.getMonth() !== prevDate.getMonth();
+ // if start of month and month % 3 === 0 then it is start of quarter
+ const startOfQuarter = startOfMonth && (nowDate.getMonth() % 3 <= prevDate.getMonth() % 3);
+ // year of today != year of yesterday then today is start of year
+ const startOfYear = nowDate.getFullYear() !== prevDate.getFullYear();
+
+ const row = {
+ date: nowDate.getTime(),
+ startOf30Seconds,
+ startOfMinute,
+ startOf5Minutes,
+ startOf15Minutes,
+ startOf30Minutes,
+ startOfHour,
+ startOfEighthOfADay,
+ startOfQuarterDay,
+ startOfHalfDay,
+ startOfDay,
+ startOfWeek,
+ startOfMonth,
+ startOfQuarter,
+ startOfYear,
+ };
+ const level = evaluateLevel(row, nowDate, i, formatters);
+
+ return { ...row, index: i + initialIndex, ...level };
+ });
+
+function doStuff(realDateAccessor, inputDateAccessor, initialIndex, formatters) {
+ return function (data) {
+ const dateAccessor = realDateAccessor(inputDateAccessor);
+ const calculate = discontinuousIndexCalculatorLocalTime
+ .source(dateAccessor)
+ .misc({ initialIndex, formatters });
+
+ const index = calculate(data).map((each) => {
+ const { format } = each;
+ return {
+ // ...each,
+ index: each.index,
+ level: each.level,
+ date: new Date(each.date),
+ format: timeFormat(format),
+ };
+ });
+
+ return { index };
+ };
+}
+
+export function discontinuousTimeScaleProviderBuilder() {
+ let initialIndex = 0;
+ let realDateAccessor = identity;
+ let inputDateAccessor = (d) => d.date;
+ let indexAccessor = (d) => d.idx;
+ let indexMutator = (d, idx) => ({ ...d, idx });
+ let withIndex;
+
+ let currentFormatters = defaultFormatters;
+
+ const discontinuousTimeScaleProvider = function (data) {
+
+ let index = withIndex;
+
+ if (isNotDefined(index)) {
+ const response = doStuff(
+ realDateAccessor,
+ inputDateAccessor,
+ initialIndex,
+ currentFormatters,
+ )(data);
+
+ index = response.index;
+ }
+
+ const inputIndex = index;
+
+ // @ts-ignore
+ const xScale = financeDiscontinuousScale(
+ inputIndex,
+ );
+
+ const mergedData = zipper()
+ .combine(indexMutator);
+
+ // @ts-ignore
+ const finalData = mergedData(data, inputIndex);
+
+ return {
+ data: finalData,
+ xScale,
+ xAccessor: (d) => d && indexAccessor(d).index,
+ displayXAccessor: realDateAccessor(inputDateAccessor),
+ };
+ };
+
+ discontinuousTimeScaleProvider.initialIndex = function (x) {
+ if (!arguments.length) {
+ return initialIndex;
+ }
+ initialIndex = x;
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.inputDateAccessor = function (x) {
+ if (!arguments.length) {
+ return inputDateAccessor;
+ }
+ inputDateAccessor = x;
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.indexAccessor = function (x) {
+ if (!arguments.length) {
+ return indexAccessor;
+ }
+ indexAccessor = x;
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.indexMutator = function (x) {
+ if (!arguments.length) {
+ return indexMutator;
+ }
+ indexMutator = x;
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.withIndex = function (x) {
+ if (!arguments.length) {
+ return withIndex;
+ }
+ withIndex = x;
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.utc = function () {
+ realDateAccessor = (dateAccessor) => (d) => {
+ const date = dateAccessor(d);
+ // The getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
+ const offsetInMillis = date.getTimezoneOffset() * 60 * 1000;
+ return new Date(date.getTime() + offsetInMillis);
+ };
+ return discontinuousTimeScaleProvider;
+ };
+ discontinuousTimeScaleProvider.setLocale = function (locale, formatters = null) {
+ if (locale) {
+ timeFormatDefaultLocale(locale);
+ }
+ if (formatters) {
+ // @ts-ignore
+ currentFormatters = formatters;
+ }
+ return discontinuousTimeScaleProvider;
+ };
+
+ discontinuousTimeScaleProvider.indexCalculator = function () {
+ return doStuff(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters);
+ };
+
+ return discontinuousTimeScaleProvider;
+}
+
+export default discontinuousTimeScaleProviderBuilder();
diff --git a/packages/react-financial-charts/src/scale/evaluator.ts b/packages/react-financial-charts/src/scale/evaluator.ts
new file mode 100644
index 000000000..d8f1dfadb
--- /dev/null
+++ b/packages/react-financial-charts/src/scale/evaluator.ts
@@ -0,0 +1,171 @@
+import {
+ getClosestItemIndexes,
+ getLogger,
+ head,
+ isDefined,
+ isNotDefined,
+ last,
+} from "../utils";
+
+const log = getLogger("evaluator");
+
+function getNewEnd(fallbackEnd, xAccessor, initialXScale, start) {
+ const {
+ lastItem, lastItemX,
+ } = fallbackEnd;
+ const lastItemXValue = xAccessor(lastItem);
+ const [rangeStart, rangeEnd] = initialXScale.range();
+
+ const newEnd = (rangeEnd - rangeStart) / (lastItemX - rangeStart) * (lastItemXValue - start) + start;
+ return newEnd;
+}
+
+function extentsWrapper(useWholeData, clamp, pointsPerPxThreshold, minPointsPerPxThreshold, flipXScale) {
+ function filterData(
+ data, inputDomain, xAccessor, initialXScale,
+ // @ts-ignore
+ { currentPlotData, currentDomain, fallbackStart, fallbackEnd } = {},
+ ) {
+ if (useWholeData) {
+ return { plotData: data, domain: inputDomain };
+ }
+
+ let left = head(inputDomain);
+ let right = last(inputDomain);
+ let clampedDomain = inputDomain;
+
+ let filteredData = getFilteredResponse(data, left, right, xAccessor);
+
+ if (filteredData.length === 1 && isDefined(fallbackStart)) {
+ left = fallbackStart;
+ right = getNewEnd(fallbackEnd, xAccessor, initialXScale, left);
+
+ clampedDomain = [
+ left,
+ right,
+ ];
+ filteredData = getFilteredResponse(data, left, right, xAccessor);
+ }
+
+ if (typeof clamp === "function") {
+ clampedDomain = clamp(clampedDomain, [xAccessor(head(data)), xAccessor(last(data))]);
+ } else {
+ if (clamp === "left" || clamp === "both" || clamp === true) {
+ clampedDomain = [
+ Math.max(left, xAccessor(head(data))),
+ clampedDomain[1],
+ ];
+ }
+
+ if (clamp === "right" || clamp === "both" || clamp === true) {
+ clampedDomain = [
+ clampedDomain[0],
+ Math.min(right, xAccessor(last(data))),
+ ];
+ }
+ }
+
+ if (clampedDomain !== inputDomain) {
+ filteredData = getFilteredResponse(data, clampedDomain[0], clampedDomain[1], xAccessor);
+ }
+
+ const realInputDomain = clampedDomain;
+ // [xAccessor(head(filteredData)), xAccessor(last(filteredData))];
+
+ const xScale = initialXScale.copy().domain(realInputDomain);
+
+ let width = Math.floor(xScale(xAccessor(last(filteredData)))
+ - xScale(xAccessor(head(filteredData))));
+
+ // prevent negative width when flipXScale
+ if (flipXScale && width < 0) {
+ width = width * -1;
+ }
+
+ let plotData;
+ let domain;
+
+ const chartWidth = last(xScale.range()) - head(xScale.range());
+
+ // @ts-ignore
+ log(`Trying to show ${filteredData.length} points in ${width}px,`
+ + ` I can show up to ${showMaxThreshold(width, pointsPerPxThreshold) - 1} points in that width. `
+ + `Also FYI the entire chart width is ${chartWidth}px and pointsPerPxThreshold is ${pointsPerPxThreshold}`);
+
+ if (canShowTheseManyPeriods(width, filteredData.length, pointsPerPxThreshold, minPointsPerPxThreshold)) {
+ plotData = filteredData;
+ domain = realInputDomain;
+
+ // @ts-ignore
+ log("AND IT WORKED");
+ } else {
+ if (chartWidth > showMaxThreshold(width, pointsPerPxThreshold) && isDefined(fallbackEnd)) {
+ plotData = filteredData;
+ const newEnd = getNewEnd(fallbackEnd, xAccessor, initialXScale, head(realInputDomain));
+ domain = [
+ head(realInputDomain),
+ newEnd,
+ ];
+
+ const newXScale = xScale.copy().domain(domain);
+ const newWidth = Math.floor(newXScale(xAccessor(last(plotData)))
+ - newXScale(xAccessor(head(plotData))));
+
+ // @ts-ignore
+ log(`and ouch, that is too much, so instead showing ${plotData.length} in ${newWidth}px`);
+ } else {
+ plotData = currentPlotData || filteredData.slice(filteredData.length - showMax(width, pointsPerPxThreshold));
+ domain = currentDomain || [xAccessor(head(plotData)), xAccessor(last(plotData))];
+
+ const newXScale = xScale.copy().domain(domain);
+ const newWidth = Math.floor(newXScale(xAccessor(last(plotData)))
+ - newXScale(xAccessor(head(plotData))));
+
+ // @ts-ignore
+ log(`and ouch, that is too much, so instead showing ${plotData.length} in ${newWidth}px`);
+ }
+ }
+ return { plotData, domain };
+ }
+ return { filterData };
+}
+
+function canShowTheseManyPeriods(width, arrayLength, maxThreshold, minThreshold) {
+ return arrayLength > showMinThreshold(width, minThreshold) && arrayLength < showMaxThreshold(width, maxThreshold);
+}
+
+function showMinThreshold(width, threshold) {
+ return Math.max(1, Math.ceil(width * threshold));
+}
+
+function showMaxThreshold(width, threshold) {
+ return Math.floor(width * threshold);
+}
+
+function showMax(width, threshold) {
+ return Math.floor(showMaxThreshold(width, threshold) * 0.97);
+}
+
+function getFilteredResponse(data, left, right, xAccessor) {
+ const newLeftIndex = getClosestItemIndexes(data, left, xAccessor).right;
+ const newRightIndex = getClosestItemIndexes(data, right, xAccessor).left;
+
+ const filteredData = data.slice(newLeftIndex, newRightIndex + 1);
+ // console.log(right, newRightIndex, dataForInterval.length);
+
+ return filteredData;
+}
+
+export default function ({
+ xScale, useWholeData, clamp,
+ pointsPerPxThreshold, minPointsPerPxThreshold,
+ flipXScale,
+}) {
+ return extentsWrapper(
+ useWholeData || isNotDefined(xScale.invert),
+ clamp,
+ pointsPerPxThreshold,
+ minPointsPerPxThreshold,
+ flipXScale,
+ );
+}
diff --git a/packages/react-financial-charts/src/scale/financeDiscontinuousScale.ts b/packages/react-financial-charts/src/scale/financeDiscontinuousScale.ts
new file mode 100644
index 000000000..7aad1219e
--- /dev/null
+++ b/packages/react-financial-charts/src/scale/financeDiscontinuousScale.ts
@@ -0,0 +1,148 @@
+import { ascending } from "d3-array";
+import { map, set } from "d3-collection";
+import { scaleLinear } from "d3-scale";
+
+import { head, isDefined, isNotDefined, last } from "../utils";
+import { levelDefinition } from "./levels";
+
+const MAX_LEVEL = levelDefinition.length - 1;
+
+export default function financeDiscontinuousScale(
+ index,
+ futureProvider,
+ backingLinearScale = scaleLinear(),
+) {
+
+ if (isNotDefined(index)) {
+ throw new Error("Use the discontinuousTimeScaleProvider to create financeDiscontinuousScale");
+ }
+
+ function scale(x) {
+ return backingLinearScale(x);
+ }
+ scale.invert = function (x) {
+ const inverted = backingLinearScale.invert(x);
+ return Math.round(inverted * 10000) / 10000;
+ };
+ scale.domain = function (x) {
+ if (!arguments.length) { return backingLinearScale.domain(); }
+ backingLinearScale.domain(x);
+ return scale;
+ };
+ scale.range = function (x) {
+ if (!arguments.length) { return backingLinearScale.range(); }
+ backingLinearScale.range(x);
+ return scale;
+ };
+ scale.rangeRound = function (x) {
+ return backingLinearScale.range(x);
+ };
+ scale.clamp = function (x) {
+ if (!arguments.length) { return backingLinearScale.clamp(); }
+ backingLinearScale.clamp(x);
+ return scale;
+ };
+ scale.interpolate = function (x) {
+ if (!arguments.length) { return backingLinearScale.interpolate(); }
+ backingLinearScale.interpolate(x);
+ return scale;
+ };
+ scale.ticks = function (m, flexTicks) {
+ const backingTicks = backingLinearScale.ticks(m);
+ const ticksMap = map();
+
+ const [domainStart, domainEnd] = backingLinearScale.domain();
+
+ const start = Math.max(Math.ceil(domainStart), head(index).index) + Math.abs(head(index).index);
+ const end = Math.min(Math.floor(domainEnd), last(index).index) + Math.abs(head(index).index);
+
+ if (Math.floor(domainEnd) > end) {
+ // console.log(end, domainEnd, index);
+ }
+
+ const desiredTickCount = Math.ceil((end - start) / (domainEnd - domainStart) * backingTicks.length);
+
+ for (let i = MAX_LEVEL; i >= 0; i--) {
+ const ticksAtLevel = ticksMap.get(i);
+ const temp = isNotDefined(ticksAtLevel)
+ ? []
+ : ticksAtLevel.slice();
+
+ for (let j = start; j <= end; j++) {
+ if (index[j].level === i) {
+ temp.push(index[j]);
+ }
+ }
+
+ ticksMap.set(i, temp);
+ }
+
+ let unsortedTicks = [];
+ for (let i = MAX_LEVEL; i >= 0; i--) {
+ if ((ticksMap.get(i).length + unsortedTicks.length) > desiredTickCount * 1.5) { break; }
+ unsortedTicks = unsortedTicks.concat(ticksMap.get(i).map((d) => d.index));
+ }
+
+ const ticks = unsortedTicks.sort(ascending);
+
+ // console.log(backingTicks.length, desiredTickCount, ticks, ticksMap);
+
+ if (!flexTicks && end - start > ticks.length) {
+ const ticksSet = set(ticks);
+
+ const d = Math.abs(head(index).index);
+
+ // ignore ticks within this distance
+ const distance = Math.ceil(
+ (backingTicks.length > 0
+ ? (last(backingTicks) - head(backingTicks)) / (backingTicks.length) / 4
+ : 1) * 1.5);
+
+ for (let i = 0; i < ticks.length - 1; i++) {
+ for (let j = i + 1; j < ticks.length; j++) {
+ if (ticks[j] - ticks[i] <= distance) {
+ ticksSet.remove(index[ticks[i] + d].level >= index[ticks[j] + d].level ? ticks[j] : ticks[i]);
+ }
+ }
+ }
+
+ const tickValues = ticksSet
+ .values()
+ .map((i) => parseInt(i, 10));
+
+ // console.log(ticks.length, tickValues, level);
+ // console.log(ticks, tickValues, distance);
+
+ return tickValues;
+ }
+
+ return ticks;
+ };
+ scale.tickFormat = function () {
+ return function (x) {
+ const d = Math.abs(head(index).index);
+ const { format, date } = index[Math.floor(x + d)];
+ return format(date);
+ };
+ };
+ scale.value = function (x) {
+ const d = Math.abs(head(index).index);
+ if (isDefined(index[Math.floor(x + d)])) {
+ const { date } = index[Math.floor(x + d)];
+ return date;
+ }
+ };
+ scale.nice = function (m) {
+ backingLinearScale.nice(m);
+ return scale;
+ };
+ scale.index = function (x) {
+ if (!arguments.length) { return index; }
+ index = x;
+ return scale;
+ };
+ scale.copy = function () {
+ return financeDiscontinuousScale(index, futureProvider, backingLinearScale.copy());
+ };
+ return scale;
+}
diff --git a/packages/react-financial-charts/src/scale/index.ts b/packages/react-financial-charts/src/scale/index.ts
new file mode 100644
index 000000000..010d12a42
--- /dev/null
+++ b/packages/react-financial-charts/src/scale/index.ts
@@ -0,0 +1,9 @@
+export {
+ default as discontinuousTimeScaleProvider,
+ discontinuousTimeScaleProviderBuilder,
+} from "./discontinuousTimeScaleProvider";
+export { default as financeDiscontinuousScale } from "./financeDiscontinuousScale";
+
+export function defaultScaleProvider(xScale) {
+ return (data, xAccessor) => ({ data, xScale, xAccessor, displayXAccessor: xAccessor });
+}
diff --git a/packages/react-financial-charts/src/scale/levels.ts b/packages/react-financial-charts/src/scale/levels.ts
new file mode 100644
index 000000000..d8a648abd
--- /dev/null
+++ b/packages/react-financial-charts/src/scale/levels.ts
@@ -0,0 +1,36 @@
+export const defaultFormatters = {
+ yearFormat: "%Y",
+ quarterFormat: "%b %Y",
+ monthFormat: "%b",
+ weekFormat: "%d %b",
+ dayFormat: "%a %d",
+ hourFormat: "%_I %p",
+ minuteFormat: "%I:%M %p",
+ secondFormat: "%I:%M:%S %p",
+ milliSecondFormat: "%L",
+};
+
+export const levelDefinition = [
+ /* eslint-disable no-unused-vars */
+ /* 19 */(d, date, i) => d.startOfYear && date.getFullYear() % 12 === 0 && "yearFormat",
+ /* 18 */(d, date, i) => d.startOfYear && date.getFullYear() % 4 === 0 && "yearFormat",
+ /* 17 */(d, date, i) => d.startOfYear && date.getFullYear() % 2 === 0 && "yearFormat",
+ /* 16 */(d, date, i) => d.startOfYear && "yearFormat",
+ /* 15 */(d, date, i) => d.startOfQuarter && "quarterFormat",
+ /* 14 */(d, date, i) => d.startOfMonth && "monthFormat",
+ /* 13 */(d, date, i) => d.startOfWeek && "weekFormat",
+ /* 12 */(d, date, i) => d.startOfDay && i % 2 === 0 && "dayFormat",
+ /* 11 */(d, date, i) => d.startOfDay && "dayFormat",
+ /* 10 */(d, date, i) => d.startOfHalfDay && "hourFormat", // 12h
+ /* 9 */(d, date, i) => d.startOfQuarterDay && "hourFormat", // 6h
+ /* 8 */(d, date, i) => d.startOfEighthOfADay && "hourFormat", // 3h
+ /* 7 */(d, date, i) => d.startOfHour && date.getHours() % 2 === 0 && "hourFormat", // 2h -- REMOVE THIS
+ /* 6 */(d, date, i) => d.startOfHour && "hourFormat", // 1h
+ /* 5 */(d, date, i) => d.startOf30Minutes && "minuteFormat",
+ /* 4 */(d, date, i) => d.startOf15Minutes && "minuteFormat",
+ /* 3 */(d, date, i) => d.startOf5Minutes && "minuteFormat",
+ /* 2 */(d, date, i) => d.startOfMinute && "minuteFormat",
+ /* 1 */(d, date, i) => d.startOf30Seconds && "secondFormat",
+ /* 0 */(d, date, i) => "secondFormat",
+ /* eslint-enable no-unused-vars */
+];
diff --git a/packages/react-financial-charts/src/series/AlternatingFillAreaSeries.tsx b/packages/react-financial-charts/src/series/AlternatingFillAreaSeries.tsx
new file mode 100644
index 000000000..7d851599f
--- /dev/null
+++ b/packages/react-financial-charts/src/series/AlternatingFillAreaSeries.tsx
@@ -0,0 +1,199 @@
+import * as React from "react";
+
+import { strokeDashTypes } from "../utils";
+import { AreaSeries } from "./AreaSeries";
+import { SVGComponent } from "./SVGComponent";
+
+interface AlternatingFillAreaSeriesProps {
+ stroke: {
+ top: string;
+ bottom: string;
+ };
+ strokeWidth: {
+ top: number;
+ bottom: number;
+ };
+ strokeOpacity: {
+ top: number;
+ bottom: number;
+ };
+ fill: {
+ top: string;
+ bottom: string;
+ };
+ fillOpacity: {
+ top: number,
+ bottom: number,
+ };
+ strokeDasharray: {
+ top: strokeDashTypes;
+ bottom: strokeDashTypes;
+ };
+ className?: string;
+ yAccessor: any; // func;
+ baseAt: number;
+ interpolation?: any; // func
+}
+
+export class AlternatingFillAreaSeries extends React.Component {
+
+ public static defaultProps = {
+ stroke: {
+ top: "#38C172",
+ bottom: "#E3342F",
+ },
+ strokeWidth: {
+ top: 2,
+ bottom: 2,
+ },
+ strokeOpacity: {
+ top: 1,
+ bottom: 1,
+ },
+ fill: {
+ top: "#A2F5BF",
+ bottom: "#EF5753",
+ },
+ fillOpacity: {
+ top: 0.5,
+ bottom: 0.5,
+ },
+ strokeDasharray: {
+ top: "Solid",
+ bottom: "Solid",
+ },
+ className: "react-stockcharts-alternating-area",
+ };
+
+ private clipPathId1: string;
+ private clipPathId2: string;
+
+ public constructor(props) {
+ super(props);
+ this.renderClip = this.renderClip.bind(this);
+ this.topClip = this.topClip.bind(this);
+ this.bottomClip = this.bottomClip.bind(this);
+ this.baseAt = this.baseAt.bind(this);
+
+ const id1 = String(Math.round(Math.random() * 10000 * 10000));
+ this.clipPathId1 = `alternating-area-clip-${id1}`;
+
+ const id2 = String(Math.round(Math.random() * 10000 * 10000));
+ this.clipPathId2 = `alternating-area-clip-${id2}`;
+ }
+
+ public topClip(ctx, moreProps) {
+ const { chartConfig } = moreProps;
+ const { baseAt } = this.props;
+ const { yScale, width } = chartConfig;
+
+ ctx.beginPath();
+ ctx.rect(
+ 0,
+ 0,
+ width,
+ yScale(baseAt),
+ );
+ ctx.clip();
+ }
+
+ public bottomClip(ctx, moreProps) {
+ const { chartConfig } = moreProps;
+ const { baseAt } = this.props;
+ const { yScale, width, height } = chartConfig;
+
+ ctx.beginPath();
+ ctx.rect(
+ 0,
+ yScale(baseAt),
+ width,
+ height - yScale(baseAt),
+ );
+ ctx.clip();
+ }
+
+ public renderClip(moreProps) {
+ const { chartConfig } = moreProps;
+ const { baseAt } = this.props;
+ const { yScale, width, height } = chartConfig;
+
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+
+ public baseAt(yScale) {
+ return yScale(this.props.baseAt);
+ }
+
+ public render() {
+ const { className, yAccessor, interpolation } = this.props;
+ const {
+ stroke,
+ strokeWidth,
+ strokeOpacity,
+ strokeDasharray,
+
+ fill,
+ fillOpacity,
+ } = this.props;
+
+ const style1 = { clipPath: `url(#${this.clipPathId1})` };
+ const style2 = { clipPath: `url(#${this.clipPathId2})` };
+
+ return (
+
+
+ {this.renderClip}
+
+
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/series/AreaOnlySeries.tsx b/packages/react-financial-charts/src/series/AreaOnlySeries.tsx
new file mode 100644
index 000000000..27adf8577
--- /dev/null
+++ b/packages/react-financial-charts/src/series/AreaOnlySeries.tsx
@@ -0,0 +1,112 @@
+import { area as d3Area } from "d3-shape";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { first, functor, hexToRGBA, isDefined } from "../utils";
+
+interface AreaOnlySeriesProps {
+ className?: string;
+ yAccessor: any; // func
+ stroke?: string;
+ fill?: string;
+ opacity?: number;
+ defined?: any; // func
+ base?: number | any; // func
+ interpolation?: any; // func
+ canvasClip?: any; // func
+ style?: React.CSSProperties;
+ canvasGradient?: any; // func
+}
+
+export class AreaOnlySeries extends React.Component {
+
+ public static defaultProps = {
+ className: "line",
+ fill: "none",
+ opacity: 1,
+ defined: (d) => !isNaN(d),
+ base: (yScale /* , d, moreProps */) => first(yScale.range()),
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { yAccessor, defined, base, style } = this.props;
+ const { stroke, fill, className = "line", opacity, interpolation } = this.props;
+
+ const { xScale, chartConfig: { yScale }, plotData, xAccessor } = moreProps;
+
+ const newBase = functor(base);
+ const areaSeries = d3Area()
+ .defined((d) => defined(yAccessor(d)))
+ .x((d) => Math.round(xScale(xAccessor(d))))
+ .y0((d) => newBase(yScale, d, moreProps))
+ .y1((d) => Math.round(yScale(yAccessor(d))));
+
+ if (isDefined(interpolation)) {
+ areaSeries.curve(interpolation);
+ }
+
+ const data = areaSeries(plotData);
+ const newClassName = className.concat(isDefined(stroke) ? "" : " line-stroke");
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { yAccessor, defined, base, canvasGradient } = this.props;
+ const { fill, stroke, opacity, interpolation, canvasClip } = this.props;
+
+ const { xScale, chartConfig: { yScale }, plotData, xAccessor } = moreProps;
+
+ if (canvasClip) {
+ ctx.save();
+ canvasClip(ctx, moreProps);
+ }
+
+ if (canvasGradient != null) {
+ ctx.fillStyle = canvasGradient(moreProps, ctx);
+ } else {
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ }
+ ctx.strokeStyle = stroke;
+
+ ctx.beginPath();
+ const newBase = functor(base);
+ const areaSeries = d3Area()
+ .defined((d) => defined(yAccessor(d)))
+ .x((d) => Math.round(xScale(xAccessor(d))))
+ .y0((d) => newBase(yScale, d, moreProps))
+ .y1((d) => Math.round(yScale(yAccessor(d))))
+ .context(ctx);
+
+ if (isDefined(interpolation)) {
+ areaSeries.curve(interpolation);
+ }
+ areaSeries(plotData);
+ ctx.fill();
+
+ if (canvasClip) {
+ ctx.restore();
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/series/AreaSeries.tsx b/packages/react-financial-charts/src/series/AreaSeries.tsx
new file mode 100644
index 000000000..a53da80cc
--- /dev/null
+++ b/packages/react-financial-charts/src/series/AreaSeries.tsx
@@ -0,0 +1,80 @@
+import * as React from "react";
+
+import { strokeDashTypes } from "../utils";
+import { AreaOnlySeries } from "./AreaOnlySeries";
+import { LineSeries } from "./LineSeries";
+
+interface AreaSeriesProps {
+ stroke?: string;
+ strokeWidth?: number;
+ canvasGradient?: any; // func
+ fill: string;
+ strokeOpacity: number;
+ opacity: number;
+ className?: string;
+ yAccessor: any; // func
+ baseAt?: any; // func
+ interpolation?: any; // func
+ canvasClip?: any; // func
+ style: React.CSSProperties;
+ strokeDasharray: strokeDashTypes;
+}
+
+export class AreaSeries extends React.Component {
+
+ public static defaultProps = {
+ stroke: "#4682B4",
+ strokeWidth: 1,
+ strokeOpacity: 1,
+ strokeDasharray: "Solid",
+ opacity: 0.5,
+ fill: "#4682B4",
+ className: "react-stockcharts-area",
+ };
+
+ public render() {
+ const {
+ baseAt,
+ className,
+ opacity,
+ stroke,
+ strokeWidth,
+ strokeOpacity,
+ strokeDasharray,
+ canvasGradient,
+ fill,
+ interpolation,
+ style,
+ canvasClip,
+ yAccessor,
+ } = this.props;
+
+ return (
+
+
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/series/BarSeries.tsx b/packages/react-financial-charts/src/series/BarSeries.tsx
new file mode 100644
index 000000000..c8a68075c
--- /dev/null
+++ b/packages/react-financial-charts/src/series/BarSeries.tsx
@@ -0,0 +1,124 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import {
+ drawOnCanvas2,
+ drawOnCanvasHelper,
+ getBarsSVG2,
+ identityStack,
+ StackedBarSeries,
+ svgHelper,
+} from "./StackedBarSeries";
+
+import { functor, isDefined } from "../utils";
+
+interface BarSeriesProps {
+ baseAt?: number | any; // func
+ stroke?: boolean;
+ width?: number | any; // func
+ yAccessor: any; // func
+ opacity?: number;
+ fill?: number | any; // func
+ className?: number | any; // func
+ clip?: boolean;
+ swapScales?: boolean;
+}
+
+export class BarSeries extends React.Component {
+
+ public static defaultProps = StackedBarSeries.defaultProps;
+
+ public render() {
+ const { clip } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ if (this.props.swapScales) {
+ const { xAccessor } = moreProps;
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, identityStack);
+ } else {
+ const bars = getBars(this.props, moreProps);
+ drawOnCanvas2(this.props, ctx, bars);
+ }
+
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ if (this.props.swapScales) {
+ const { xAccessor } = moreProps;
+ return {svgHelper(this.props, moreProps, xAccessor, identityStack)};
+ } else {
+ const bars = getBars(this.props, moreProps);
+ return {getBarsSVG2(this.props, bars)};
+ }
+ }
+}
+
+/*
+ Initially, this program was using StackedBarSeries.getBars
+ to benefit from code reuse and having a single place that
+ contains the logic for drawing all types of bar charts
+ simple, grouped, horizontal, but turnes out
+ making it highly cuztimizable also made it slow for the
+ most simple case, a regular bar chart.
+ This function contains just the necessary logic
+ to create bars
+*/
+function getBars(props, moreProps) {
+ const { baseAt, fill, stroke, yAccessor } = props;
+ const { xScale, xAccessor, plotData, chartConfig: { yScale } } = moreProps;
+
+ const getFill = functor(fill);
+ const getBase = functor(baseAt);
+
+ const widthFunctor = functor(props.width);
+
+ const width = widthFunctor(props, {
+ xScale,
+ xAccessor,
+ plotData,
+ });
+
+ const offset = Math.floor(0.5 * width);
+
+ const bars = plotData
+ .filter((d) => isDefined(yAccessor(d)))
+ .map((d) => {
+ const yValue = yAccessor(d);
+ let y = yScale(yValue);
+
+ const x = Math.round(xScale(xAccessor(d))) - offset;
+ let h = getBase(xScale, yScale, d) - yScale(yValue);
+
+ if (h < 0) {
+ y = y + h;
+ h = -h;
+ }
+
+ return {
+ // type: "line"
+ x,
+ y: Math.round(y),
+ height: Math.round(h),
+ width: offset * 2,
+ fill: getFill(d, 0),
+ stroke: stroke ? getFill(d, 0) : "none",
+ };
+ });
+
+ return bars;
+}
diff --git a/packages/react-financial-charts/src/series/BollingerSeries.tsx b/packages/react-financial-charts/src/series/BollingerSeries.tsx
new file mode 100644
index 000000000..df9ddb593
--- /dev/null
+++ b/packages/react-financial-charts/src/series/BollingerSeries.tsx
@@ -0,0 +1,75 @@
+import * as React from "react";
+
+import { AreaOnlySeries } from "./AreaOnlySeries";
+import { LineSeries } from "./LineSeries";
+
+interface BollingerSeriesProps {
+ yAccessor: any; // func
+ className?: string;
+ areaClassName?: string;
+ opacity?: number;
+ type?: string;
+ stroke: {
+ top: string,
+ middle: string,
+ bottom: string,
+ };
+ fill: string;
+}
+
+export class BollingerSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-bollinger-band-series",
+ areaClassName: "react-stockcharts-bollinger-band-series-area",
+ opacity: 0.2,
+ };
+
+ public render() {
+ const { areaClassName, className, opacity } = this.props;
+ const { stroke, fill } = this.props;
+
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ private readonly yAccessorForScalledBottom = (scale, d) => {
+ const { yAccessor } = this.props;
+ return scale(yAccessor(d) && yAccessor(d).bottom);
+ }
+
+ private readonly yAccessorForBottom = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).bottom;
+ }
+
+ private readonly yAccessorForMiddle = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).middle;
+ }
+
+ private readonly yAccessorForTop = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).top;
+ }
+}
diff --git a/packages/react-financial-charts/src/series/CandlestickSeries.tsx b/packages/react-financial-charts/src/series/CandlestickSeries.tsx
new file mode 100644
index 000000000..5a3d3de52
--- /dev/null
+++ b/packages/react-financial-charts/src/series/CandlestickSeries.tsx
@@ -0,0 +1,237 @@
+import { nest } from "d3-collection";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import {
+ functor, head, hexToRGBA, isDefined, plotDataLengthBarWidth,
+} from "../utils";
+
+interface CandlestickSeriesProps {
+ readonly className?: string;
+ readonly wickClassName?: string;
+ readonly candleClassName?: string;
+ readonly candleStrokeWidth?: number | string;
+ readonly widthRatio?: number;
+ readonly width?: number | any; // func
+ readonly classNames?: string | any; // func
+ readonly fill?: string | any; // func
+ readonly stroke?: string | any; // func
+ readonly wickStroke?: string | any; // func
+ readonly yAccessor?: any; // func
+ readonly clip?: boolean;
+ readonly opacity?: number;
+}
+
+export class CandlestickSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-candlestick",
+ wickClassName: "react-stockcharts-candlestick-wick",
+ candleClassName: "react-stockcharts-candlestick-candle",
+ yAccessor: (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close }),
+ classNames: (d) => d.close > d.open ? "up" : "down",
+ width: plotDataLengthBarWidth,
+ wickStroke: "#000000",
+ fill: (d) => d.close > d.open ? "#6BA583" : "#FF0000",
+ stroke: "#000000",
+ candleStrokeWidth: 0.5,
+ widthRatio: 0.8,
+ opacity: 0.5,
+ clip: true,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ drawOnCanvas(ctx, this.props, moreProps);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className, wickClassName, candleClassName } = this.props;
+ const { xScale, chartConfig: { yScale }, plotData, xAccessor } = moreProps;
+
+ const candleData = getCandleData(this.props, xAccessor, xScale, yScale, plotData);
+
+ return
+
+ {getWicksSVG(candleData)}
+
+
+ {getCandlesSVG(this.props, candleData)}
+
+ ;
+ }
+}
+
+function getWicksSVG(candleData) {
+
+ const wicks = candleData
+ .map((each, idx) => {
+ const d = each.wick;
+ return ;
+ });
+
+ return wicks;
+}
+
+function getCandlesSVG(props: CandlestickSeriesProps, candleData) {
+
+ const { opacity, candleStrokeWidth } = props;
+
+ const candles = candleData.map((d, idx) => {
+ if (d.width <= 1) {
+ return (
+
+ );
+ } else if (d.height === 0) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ });
+ return candles;
+}
+
+function drawOnCanvas(ctx, props: CandlestickSeriesProps, moreProps) {
+ const { opacity, candleStrokeWidth } = props;
+ const { xScale, chartConfig: { yScale }, plotData, xAccessor } = moreProps;
+
+ const candleData = getCandleData(props, xAccessor, xScale, yScale, plotData);
+
+ const wickNest = nest()
+ .key((d) => d.wick.stroke)
+ .entries(candleData);
+
+ wickNest.forEach((outer) => {
+ const { key, values } = outer;
+ ctx.strokeStyle = key;
+ ctx.fillStyle = key;
+ values.forEach((each) => {
+
+ const d = each.wick;
+
+ ctx.fillRect(d.x - 0.5, d.y1, 1, d.y2 - d.y1);
+ ctx.fillRect(d.x - 0.5, d.y3, 1, d.y4 - d.y3);
+ });
+ });
+
+ const candleNest = nest()
+ .key((d) => d.stroke)
+ .key((d) => d.fill)
+ .entries(candleData);
+
+ candleNest.forEach((outer) => {
+ const { key: strokeKey, values: strokeValues } = outer;
+ if (strokeKey !== "none") {
+ ctx.strokeStyle = strokeKey;
+ ctx.lineWidth = candleStrokeWidth;
+ }
+ strokeValues.forEach((inner) => {
+ const { key, values } = inner;
+ const fillStyle = head(values).width <= 1
+ ? key
+ : hexToRGBA(key, opacity);
+ ctx.fillStyle = fillStyle;
+
+ values.forEach((d) => {
+ if (d.width <= 1) {
+ ctx.fillRect(d.x - 0.5, d.y, 1, d.height);
+ } else if (d.height === 0) {
+ ctx.fillRect(d.x, d.y - 0.5, d.width, 1);
+ } else {
+ ctx.fillRect(d.x, d.y, d.width, d.height);
+ if (strokeKey !== "none") {
+ ctx.strokeRect(d.x, d.y, d.width, d.height);
+ }
+ }
+ });
+ });
+ });
+}
+
+function getCandleData(props: CandlestickSeriesProps, xAccessor, xScale, yScale, plotData) {
+
+ const { wickStroke: wickStrokeProp } = props;
+ const wickStroke = functor(wickStrokeProp);
+
+ const { classNames, fill: fillProp, stroke: strokeProp, yAccessor } = props;
+ const className = functor(classNames);
+
+ const fill = functor(fillProp);
+ const stroke = functor(strokeProp);
+
+ const widthFunctor = functor(props.width);
+ const width = widthFunctor(props, {
+ xScale,
+ xAccessor,
+ plotData,
+ });
+
+ const trueOffset = 0.5 * width;
+ const offset = trueOffset > 0.7
+ ? Math.round(trueOffset)
+ : Math.floor(trueOffset);
+
+ const candles: any[] = [];
+
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < plotData.length; i++) {
+ const d = plotData[i];
+ if (isDefined(yAccessor(d).close)) {
+ const x = Math.round(xScale(xAccessor(d)));
+
+ const ohlc = yAccessor(d);
+ const y = Math.round(yScale(Math.max(ohlc.open, ohlc.close)));
+ const height = Math.round(Math.abs(yScale(ohlc.open) - yScale(ohlc.close)));
+
+ candles.push({
+ // type: "line"
+ x: x - offset,
+ y,
+ wick: {
+ stroke: wickStroke(ohlc),
+ x,
+ y1: Math.round(yScale(ohlc.high)),
+ y2: y,
+ y3: y + height, // Math.round(yScale(Math.min(ohlc.open, ohlc.close))),
+ y4: Math.round(yScale(ohlc.low)),
+ },
+ height,
+ width: offset * 2,
+ className: className(ohlc),
+ fill: fill(ohlc),
+ stroke: stroke(ohlc),
+ direction: (ohlc.close - ohlc.open),
+ });
+ }
+ }
+
+ return candles;
+}
diff --git a/packages/react-financial-charts/src/series/CircleMarker.tsx b/packages/react-financial-charts/src/series/CircleMarker.tsx
new file mode 100644
index 000000000..586d3ef5e
--- /dev/null
+++ b/packages/react-financial-charts/src/series/CircleMarker.tsx
@@ -0,0 +1,70 @@
+import * as React from "react";
+
+import { functor, hexToRGBA } from "../utils";
+
+interface CircleProps {
+ stroke?: string;
+ fill: string;
+ opacity: number;
+ point: {
+ x: number,
+ y: number,
+ datum: any,
+ };
+ className?: string;
+ strokeWidth?: number;
+ r: number | any; // func
+}
+
+export class Circle extends React.Component {
+
+ public static defaultProps = {
+ stroke: "#4682B4",
+ strokeWidth: 1,
+ opacity: 0.5,
+ fill: "#4682B4",
+ className: "react-stockcharts-marker-circle",
+ };
+
+ public static drawOnCanvas = (props, point, ctx) => {
+
+ const { stroke, fill, opacity, strokeWidth } = props;
+
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = strokeWidth;
+
+ if (fill !== "none") {
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ }
+
+ Circle.drawOnCanvasWithNoStateChange(props, point, ctx);
+ }
+
+ public static drawOnCanvasWithNoStateChange = (props, point, ctx) => {
+
+ const { r } = props;
+ const radius = functor(r)(point.datum);
+
+ ctx.moveTo(point.x, point.y);
+ ctx.beginPath();
+ ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI, false);
+ ctx.stroke();
+ ctx.fill();
+ }
+
+ public render() {
+ const { className, stroke, strokeWidth, opacity, fill, point, r } = this.props;
+ const radius = functor(r)(point.datum);
+ return (
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/series/ElderRaySeries.tsx b/packages/react-financial-charts/src/series/ElderRaySeries.tsx
new file mode 100644
index 000000000..71bfec5f1
--- /dev/null
+++ b/packages/react-financial-charts/src/series/ElderRaySeries.tsx
@@ -0,0 +1,93 @@
+import * as React from "react";
+
+import OverlayBarSeries from "./OverlayBarSeries";
+import { StraightLine } from "./StraightLine";
+
+interface ElderRaySeriesProps {
+ className?: string;
+ yAccessor: any; // func
+ opacity?: number;
+ stroke?: boolean;
+ bullPowerFill?: string;
+ bearPowerFill?: string;
+ straightLineStroke?: string;
+ straightLineOpacity?: number;
+ widthRatio?: number;
+ clip: boolean;
+}
+
+export class ElderRaySeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-elderray-series",
+ straightLineStroke: "#000000",
+ straightLineOpacity: 0.3,
+ opacity: 0.5,
+ stroke: true,
+ bullPowerFill: "#6BA583",
+ bearPowerFill: "#FF0000",
+ widthRatio: 0.8,
+ clip: true,
+ };
+
+ public render() {
+ const { className, opacity, stroke,
+ straightLineStroke,
+ straightLineOpacity,
+ widthRatio,
+ } = this.props;
+ const { clip } = this.props;
+
+ return (
+
+
+
+
+ );
+ }
+
+ private readonly yAccessorBullTop = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && (yAccessor(d).bullPower > 0 ? yAccessor(d).bullPower : undefined);
+ }
+
+ private readonly yAccessorBearTop = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && (yAccessor(d).bearPower > 0 ? yAccessor(d).bearPower : undefined);
+ }
+
+ private readonly yAccessorBullBottom = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && (yAccessor(d).bullPower < 0 ? 0 : undefined);
+ }
+
+ private readonly yAccessorBearBottom = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && (yAccessor(d).bullPower < 0
+ || yAccessor(d).bullPower * yAccessor(d).bearPower < 0 // bullPower is +ve and bearPower is -ve
+ ? Math.min(0, yAccessor(d).bullPower) : undefined);
+ }
+
+ private readonly yAccessorForBarBase = (xScale, yScale, d) => {
+ const { yAccessor } = this.props;
+ const y = yAccessor(d) && Math.min(yAccessor(d).bearPower, 0);
+ return yScale(y);
+ }
+
+ private readonly fillForEachBar = (d, yAccessorNumber) => {
+ const { bullPowerFill, bearPowerFill } = this.props;
+ return yAccessorNumber % 2 === 0 ? bullPowerFill : bearPowerFill;
+ }
+}
diff --git a/packages/react-financial-charts/src/series/GroupedBarSeries.tsx b/packages/react-financial-charts/src/series/GroupedBarSeries.tsx
new file mode 100644
index 000000000..6e4d41cee
--- /dev/null
+++ b/packages/react-financial-charts/src/series/GroupedBarSeries.tsx
@@ -0,0 +1,62 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { drawOnCanvasHelper, identityStack, StackedBarSeries, svgHelper } from "./StackedBarSeries";
+
+interface GroupedBarSeriesProps {
+ baseAt: number | any; // func
+ direction: "up" | "down";
+ stroke: boolean;
+ widthRatio: number;
+ opacity: number;
+ fill: string | any; // func
+ className: string | any; // func
+ yAccessor: any[]; // func
+}
+
+export class GroupedBarSeries extends React.Component {
+
+ public static defaultProps = {
+ ...StackedBarSeries.defaultProps,
+ widthRatio: 0.8,
+ spaceBetweenBar: 5,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, identityStack, this.postProcessor);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { xAccessor } = moreProps;
+
+ return (
+
+ {svgHelper(this.props, moreProps, xAccessor, identityStack, this.postProcessor)}
+
+ );
+ }
+
+ private readonly postProcessor = (array) => {
+ return array.map((each) => {
+ return {
+ ...each,
+ x: each.x + each.offset - each.groupOffset,
+ width: each.groupWidth,
+ };
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/series/KagiSeries.tsx b/packages/react-financial-charts/src/series/KagiSeries.tsx
new file mode 100644
index 000000000..448bb5f79
--- /dev/null
+++ b/packages/react-financial-charts/src/series/KagiSeries.tsx
@@ -0,0 +1,178 @@
+import { curveStepBefore, line } from "d3-shape";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { isDefined, isNotDefined } from "../utils";
+
+interface KagiSeriesProps {
+ readonly className?: string;
+ readonly stroke?: {
+ yang: string;
+ yin: string;
+ };
+ readonly fill?: {
+ yang: string;
+ yin: string;
+ };
+ readonly strokeWidth: number;
+}
+
+export class KagiSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-kagi",
+ strokeWidth: 2,
+ stroke: {
+ yang: "#6BA583",
+ yin: "#E60000",
+ },
+ fill: {
+ yang: "none",
+ yin: "none",
+ },
+ currentValueStroke: "#000000",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { xAccessor, xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const {
+ className,
+ stroke = KagiSeries.defaultProps.stroke,
+ fill = KagiSeries.defaultProps.fill,
+ strokeWidth,
+ } = this.props;
+
+ const paths = helper(plotData, xAccessor)
+ .map((each, i) => {
+ const dataSeries = line()
+ .x((item) => xScale(item[0]))
+ .y((item) => yScale(item[1]))
+ .curve(curveStepBefore);
+
+ dataSeries(each.plot);
+
+ return (
+
+ );
+ });
+ return (
+
+ {paths}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+
+ drawOnCanvas(ctx, this.props, moreProps, xAccessor);
+ }
+}
+
+function drawOnCanvas(ctx, props, moreProps, xAccessor) {
+ const { stroke, strokeWidth, currentValueStroke } = props;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const paths = helper(plotData, xAccessor);
+
+ let begin = true;
+
+ paths.forEach((each) => {
+ ctx.strokeStyle = stroke[each.type];
+ ctx.lineWidth = strokeWidth;
+
+ ctx.beginPath();
+ let prevX;
+ each.plot.forEach((d) => {
+ const [x1, y] = [xScale(d[0]), yScale(d[1])];
+ if (begin) {
+ ctx.moveTo(x1, y);
+ begin = false;
+ } else {
+ if (isDefined(prevX)) {
+ ctx.lineTo(prevX, y);
+ }
+ ctx.lineTo(x1, y);
+ }
+ prevX = x1;
+ });
+ ctx.stroke();
+ });
+ const lastPlot = paths[paths.length - 1].plot;
+ const last = lastPlot[lastPlot.length - 1];
+ ctx.beginPath();
+ ctx.lineWidth = 1;
+
+ const [x, y1, y2] = [xScale(last[0]), yScale(last[2]), yScale(last[3])];
+ ctx.moveTo(x, y1);
+ ctx.lineTo(x + 10, y1);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.strokeStyle = currentValueStroke;
+ ctx.moveTo(x - 10, y2);
+ ctx.lineTo(x, y2);
+ ctx.stroke();
+}
+
+function helper(plotData, xAccessor) {
+ const kagiLine: any[] = [];
+ let kagi: {
+ added?: boolean;
+ plot?: any;
+ type?: any;
+ } = {};
+ let d = plotData[0];
+ let idx = xAccessor(d);
+
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < plotData.length; i++) {
+ d = plotData[i];
+
+ if (isNotDefined(d.close)) { continue; }
+ if (isNotDefined(kagi.type)) { kagi.type = d.startAs; }
+ if (isNotDefined(kagi.plot)) { kagi.plot = []; }
+
+ idx = xAccessor(d);
+ kagi.plot.push([idx, d.open]);
+
+ if (isDefined(d.changeTo)) {
+ kagi.plot.push([idx, d.changePoint]);
+ kagi.added = true;
+ kagiLine.push(kagi);
+
+ kagi = {
+ type: d.changeTo,
+ plot: [],
+ added: false,
+ };
+ kagi.plot.push([idx, d.changePoint]);
+ }
+ }
+
+ if (!kagi.added) {
+ kagi.plot.push([idx, d.close, d.current, d.reverseAt]);
+ kagiLine.push(kagi);
+ }
+
+ return kagiLine;
+}
diff --git a/packages/react-financial-charts/src/series/LineSeries.tsx b/packages/react-financial-charts/src/series/LineSeries.tsx
new file mode 100644
index 000000000..f70cca625
--- /dev/null
+++ b/packages/react-financial-charts/src/series/LineSeries.tsx
@@ -0,0 +1,208 @@
+
+import { line as d3Line } from "d3-shape";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas, getMouseCanvas } from "../GenericComponent";
+
+import {
+ getClosestItemIndexes,
+ getStrokeDasharray,
+ hexToRGBA,
+ isDefined,
+ strokeDashTypes,
+} from "../utils";
+
+interface LineSeriesProps {
+ className?: string;
+ strokeWidth?: number;
+ strokeOpacity?: number;
+ stroke?: string;
+ hoverStrokeWidth?: number;
+ fill?: string;
+ defined?: any; // func
+ hoverTolerance?: number;
+ strokeDasharray?: strokeDashTypes;
+ highlightOnHover?: boolean;
+ onClick?: any; // func
+ onDoubleClick?: any; // func
+ onHover?: any; // func
+ onUnHover?: any; // func
+ onContextMenu?: any; // func
+ yAccessor?: any; // func
+ connectNulls?: boolean;
+ interpolation?: any; // func
+ canvasClip?: any; // func
+ style?: React.CSSProperties;
+}
+
+export class LineSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "line ",
+ strokeWidth: 1,
+ strokeOpacity: 1,
+ hoverStrokeWidth: 4,
+ fill: "none",
+ stroke: "#4682B4",
+ strokeDasharray: "Solid",
+ defined: (d) => !isNaN(d),
+ hoverTolerance: 6,
+ highlightOnHover: false,
+ connectNulls: false,
+ };
+
+ public render() {
+ const { highlightOnHover, onHover, onUnHover } = this.props;
+ const hoverProps = (highlightOnHover || onHover || onUnHover)
+ ? {
+ isHover: this.isHover,
+ drawOn: ["mousemove", "pan"],
+ canvasToDraw: getMouseCanvas,
+ }
+ : {
+ drawOn: ["pan"],
+ canvasToDraw: getAxisCanvas,
+ };
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { yAccessor, stroke, strokeOpacity, strokeWidth, hoverStrokeWidth, defined, strokeDasharray } = this.props;
+ const { connectNulls } = this.props;
+ const { interpolation, style } = this.props;
+ const { xAccessor, chartConfig } = moreProps;
+
+ const { xScale, plotData, hovering } = moreProps;
+
+ const { yScale } = chartConfig;
+ const dataSeries = d3Line()
+ .x((d) => Math.round(xScale(xAccessor(d))))
+ .y((d) => Math.round(yScale(yAccessor(d))));
+
+ if (isDefined(interpolation)) {
+ dataSeries.curve(interpolation);
+ }
+ if (!connectNulls) {
+ dataSeries.defined((d) => defined(yAccessor(d)));
+ }
+
+ const data = dataSeries(plotData);
+
+ const { fill, className } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const {
+ yAccessor,
+ stroke,
+ strokeOpacity,
+ strokeWidth,
+ hoverStrokeWidth,
+ defined,
+ strokeDasharray,
+ interpolation,
+ canvasClip,
+ } = this.props;
+
+ const { connectNulls } = this.props;
+
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData, hovering } = moreProps;
+
+ if (canvasClip) {
+ ctx.save();
+ canvasClip(ctx, moreProps);
+ }
+
+ ctx.lineWidth = hovering ? hoverStrokeWidth : strokeWidth;
+
+ ctx.strokeStyle = hexToRGBA(stroke, strokeOpacity);
+ ctx.setLineDash(getStrokeDasharray(strokeDasharray).split(","));
+
+ const dataSeries = d3Line()
+ .x((d) => Math.round(xScale(xAccessor(d))))
+ .y((d) => Math.round(yScale(yAccessor(d))));
+
+ if (isDefined(interpolation)) {
+ dataSeries.curve(interpolation);
+ }
+ if (!connectNulls) {
+ dataSeries.defined((d) => defined(yAccessor(d)));
+ }
+
+ ctx.beginPath();
+ dataSeries.context(ctx)(plotData);
+ ctx.stroke();
+
+ if (canvasClip) {
+ ctx.restore();
+ }
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { highlightOnHover, yAccessor, hoverTolerance = LineSeries.defaultProps.hoverTolerance } = this.props;
+
+ if (!highlightOnHover) { return false; }
+
+ const { mouseXY, currentItem, xScale, plotData } = moreProps;
+ const { chartConfig: { yScale, origin } } = moreProps;
+
+ const { xAccessor } = moreProps;
+
+ const [x, y] = mouseXY;
+ const radius = hoverTolerance;
+
+ const { left, right } = getClosestItemIndexes(plotData, xScale.invert(x), xAccessor);
+ if (left === right) {
+ const cy = yScale(yAccessor(currentItem)) + origin[1];
+ const cx = xScale(xAccessor(currentItem)) + origin[0];
+
+ const hovering1 = Math.pow(x - cx, 2) + Math.pow(y - cy, 2) < Math.pow(radius, 2);
+
+ return hovering1;
+ } else {
+ const l = plotData[left];
+ const r = plotData[right];
+ const x1 = xScale(xAccessor(l)) + origin[0];
+ const y1 = yScale(yAccessor(l)) + origin[1];
+ const x2 = xScale(xAccessor(r)) + origin[0];
+ const y2 = yScale(yAccessor(r)) + origin[1];
+
+ // y = m * x + b
+ const m /* slope */ = (y2 - y1) / (x2 - x1);
+ const b /* y intercept */ = -1 * m * x1 + y1;
+
+ const desiredY = Math.round(m * x + b);
+
+ const hovering2 = y >= desiredY - radius && y <= desiredY + radius;
+
+ return hovering2;
+ }
+ }
+}
diff --git a/packages/react-financial-charts/src/series/MACDSeries.tsx b/packages/react-financial-charts/src/series/MACDSeries.tsx
new file mode 100644
index 000000000..50c418e2b
--- /dev/null
+++ b/packages/react-financial-charts/src/series/MACDSeries.tsx
@@ -0,0 +1,92 @@
+import * as React from "react";
+
+import { BarSeries } from "./BarSeries";
+import { LineSeries } from "./LineSeries";
+import { StraightLine } from "./StraightLine";
+
+interface MACDSeriesProps {
+ className?: string;
+ yAccessor?: any; // func
+ opacity?: number;
+ divergenceStroke?: boolean;
+ zeroLineStroke?: string;
+ zeroLineOpacity?: number;
+ clip: boolean;
+ stroke: {
+ macd: string;
+ signal: string;
+ };
+ fill: {
+ divergence: string | any; // func
+ };
+ widthRatio?: number;
+ width?: number | any; // func
+}
+
+export class MACDSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-macd-series",
+ zeroLineStroke: "#000000",
+ zeroLineOpacity: 0.3,
+ opacity: 0.6,
+ divergenceStroke: false,
+ clip: true,
+ widthRatio: 0.5,
+ width: BarSeries.defaultProps.width,
+ };
+
+ public render() {
+ const { className, opacity, divergenceStroke, widthRatio, width } = this.props;
+ const { stroke, fill } = this.props;
+
+ const { clip } = this.props;
+ const { zeroLineStroke, zeroLineOpacity } = this.props;
+
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ private readonly yAccessorForDivergenceBase = (xScale, yScale) => {
+ return yScale(0);
+ }
+
+ private readonly yAccessorForDivergence = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).divergence;
+ }
+
+ private readonly yAccessorForSignal = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).signal;
+ }
+
+ private readonly yAccessorForMACD = (d) => {
+ const { yAccessor } = this.props;
+ return yAccessor(d) && yAccessor(d).macd;
+ }
+}
diff --git a/packages/react-financial-charts/src/series/OHLCSeries.tsx b/packages/react-financial-charts/src/series/OHLCSeries.tsx
new file mode 100644
index 000000000..f0a7223d4
--- /dev/null
+++ b/packages/react-financial-charts/src/series/OHLCSeries.tsx
@@ -0,0 +1,124 @@
+import { nest } from "d3-collection";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { functor, isDefined } from "../utils";
+
+interface OHLCSeriesProps {
+ className?: string;
+ classNames: string | any; // func
+ stroke: string | any; // func
+ yAccessor: any; // func
+ clip: boolean;
+}
+
+export class OHLCSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-ohlc",
+ yAccessor: (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close }),
+ classNames: (d) => isDefined(d.absoluteChange) ? (d.absoluteChange > 0 ? "up" : "down") : "firstbar",
+ stroke: (d) => isDefined(d.absoluteChange) ? (d.absoluteChange > 0 ? "#6BA583" : "#FF0000") : "#000000",
+ clip: true,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return ;
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className, yAccessor } = this.props;
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const barData = getOHLCBars(this.props, xAccessor, yAccessor, xScale, yScale, plotData);
+
+ const { strokeWidth, bars } = barData;
+
+ return
+ {bars.map((d, idx) => )}
+ ;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { yAccessor } = this.props;
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const barData = getOHLCBars(this.props, xAccessor, yAccessor, xScale, yScale, plotData);
+ drawOnCanvas(ctx, barData);
+ }
+}
+
+function drawOnCanvas(ctx, barData) {
+
+ const { strokeWidth, bars } = barData;
+
+ const wickNest = nest()
+ .key((d) => d.stroke)
+ .entries(bars);
+
+ ctx.lineWidth = strokeWidth;
+
+ wickNest.forEach((outer) => {
+ const { key, values } = outer;
+ ctx.strokeStyle = key;
+ values.forEach((d) => {
+ ctx.beginPath();
+ ctx.moveTo(d.x, d.y1);
+ ctx.lineTo(d.x, d.y2);
+
+ ctx.moveTo(d.openX1, d.openY);
+ ctx.lineTo(d.openX2, d.openY);
+
+ ctx.moveTo(d.closeX1, d.closeY);
+ ctx.lineTo(d.closeX2, d.closeY);
+
+ ctx.stroke();
+ });
+ });
+}
+
+function getOHLCBars(props, xAccessor, yAccessor, xScale, yScale, plotData) {
+ const { classNames: classNamesProp, stroke: strokeProp } = props;
+
+ const strokeFunc = functor(strokeProp);
+ const classNameFunc = functor(classNamesProp);
+
+ const width = xScale(xAccessor(plotData[plotData.length - 1]))
+ - xScale(xAccessor(plotData[0]));
+
+ const barWidth = Math.max(1, Math.round(width / (plotData.length - 1) / 2) - 1.5);
+ const strokeWidth = Math.min(barWidth, 6);
+
+ const bars = plotData
+ .filter((d) => isDefined(yAccessor(d).close))
+ .map((d) => {
+ const ohlc = yAccessor(d);
+ const x = Math.round(xScale(xAccessor(d)));
+ const y1 = yScale(ohlc.high);
+ const y2 = yScale(ohlc.low);
+ const openX1 = x - barWidth;
+ const openX2 = x + strokeWidth / 2;
+ const openY = yScale(ohlc.open);
+ const closeX1 = x - strokeWidth / 2;
+ const closeX2 = x + barWidth;
+ const closeY = yScale(ohlc.close);
+ const className = classNameFunc(d);
+ const stroke = strokeFunc(d);
+
+ return { x, y1, y2, openX1, openX2, openY, closeX1, closeX2, closeY, stroke, className };
+ });
+ return { barWidth, strokeWidth, bars };
+}
diff --git a/packages/react-financial-charts/src/series/OverlayBarSeries.tsx b/packages/react-financial-charts/src/series/OverlayBarSeries.tsx
new file mode 100644
index 000000000..b426d5fd2
--- /dev/null
+++ b/packages/react-financial-charts/src/series/OverlayBarSeries.tsx
@@ -0,0 +1,123 @@
+import { merge } from "d3-array";
+
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { first, functor, isDefined, isNotDefined, plotDataLengthBarWidth } from "../utils";
+import { drawOnCanvas2, getBarsSVG2 } from "./StackedBarSeries";
+
+interface OverlayBarSeriesProps {
+ baseAt: number | any; // func
+ direction: "up" | "down";
+ stroke: boolean;
+ widthRatio: number;
+ opacity: number;
+ fill: string | any; // func
+ className: string | any; // func
+ xAccessor?: any; // func
+ yAccessor?: any[]; // func
+ xScale?: any; // func
+ yScale?: any; // func
+ plotData?: number[];
+ clip: boolean;
+}
+
+export class OverlayBarSeries extends React.Component {
+
+ public static defaultProps = {
+ baseAt: (xScale, yScale/* , d*/) => first(yScale.range()),
+ direction: "up",
+ className: "bar",
+ stroke: false,
+ fill: "#4682B4",
+ opacity: 1,
+ widthRatio: 0.5,
+ width: plotDataLengthBarWidth,
+ clip: true,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { yAccessor } = this.props;
+
+ const bars = getBars(this.props, moreProps, yAccessor);
+ return (
+
+ {getBarsSVG2(this.props, bars)}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { yAccessor } = this.props;
+ const bars = getBars(this.props, moreProps, yAccessor);
+
+ drawOnCanvas2(this.props, ctx, bars);
+ }
+}
+
+function getBars(props, moreProps, yAccessor) {
+ const { xScale, xAccessor, chartConfig: { yScale }, plotData } = moreProps;
+ const { baseAt, className, fill, stroke } = props;
+
+ const getClassName = functor(className);
+ const getFill = functor(fill);
+ const getBase = functor(baseAt);
+ const widthFunctor = functor(props.width);
+
+ const width = widthFunctor(props, moreProps);
+ const offset = Math.floor(0.5 * width);
+
+ const bars = plotData
+ .map((d) => {
+ const innerBars = yAccessor.map((eachYAccessor, i) => {
+ const yValue = eachYAccessor(d);
+ if (isNotDefined(yValue)) { return undefined; }
+
+ const xValue = xAccessor(d);
+ const x = Math.round(xScale(xValue)) - offset;
+ const y = yScale(yValue);
+ return {
+ width: offset * 2,
+ x,
+ y,
+ className: getClassName(d, i),
+ stroke: stroke ? getFill(d, i) : "none",
+ fill: getFill(d, i),
+ i,
+ };
+ }).filter((yValue) => isDefined(yValue));
+
+ let b = getBase(xScale, yScale, d);
+ let h;
+ for (let i = innerBars.length - 1; i >= 0; i--) {
+ h = b - innerBars[i].y;
+ if (h < 0) {
+ innerBars[i].y = b;
+ h = -1 * h;
+ }
+ innerBars[i].height = h;
+ b = innerBars[i].y;
+ }
+ return innerBars;
+ });
+
+ return merge(bars);
+}
+
+export default OverlayBarSeries;
diff --git a/packages/react-financial-charts/src/series/PointAndFigureSeries.tsx b/packages/react-financial-charts/src/series/PointAndFigureSeries.tsx
new file mode 100644
index 000000000..4fac1a28e
--- /dev/null
+++ b/packages/react-financial-charts/src/series/PointAndFigureSeries.tsx
@@ -0,0 +1,172 @@
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { isDefined, isNotDefined } from "../utils";
+
+interface PointAndFigureSeriesProps {
+ className?: string;
+ strokeWidth: number;
+ stroke: {
+ up: string,
+ down: string,
+ };
+ fill: {
+ up: string,
+ down: string,
+ };
+ clip: boolean;
+}
+
+export class PointAndFigureSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-point-and-figure",
+ strokeWidth: 1,
+ stroke: {
+ up: "#6BA583",
+ down: "#FF0000",
+ },
+ fill: {
+ up: "none",
+ down: "none",
+ },
+ clip: true,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const { stroke, fill, strokeWidth, className } = this.props;
+
+ const columns = getColumns(xScale, xAccessor, yScale, plotData);
+
+ return (
+
+ {columns.map((col, idx) => (
+
+ {col.boxes.map((box, i) => {
+ if (col.direction > 0) {
+ return (
+
+
+
+
+ );
+ }
+ return (
+
+ );
+ })}
+
+ ))}
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+ const columns = getColumns(xScale, xAccessor, yScale, plotData);
+
+ drawOnCanvas(ctx, this.props, columns);
+ }
+}
+
+function drawOnCanvas(ctx, props, columns) {
+ const { stroke, fill, strokeWidth } = props;
+
+ ctx.lineWidth = strokeWidth;
+
+ columns.forEach((col) => {
+ const [offsetX, offsetY] = col.offset;
+ col.boxes.forEach((box) => {
+ if (col.direction > 0) {
+ ctx.fillStyle = fill.up;
+ ctx.strokeStyle = stroke.up;
+
+ ctx.beginPath();
+
+ ctx.moveTo(offsetX, offsetY + box.open);
+ ctx.lineTo(offsetX + box.columnWidth, offsetY + box.close);
+ ctx.moveTo(offsetX, offsetY + box.close);
+ ctx.lineTo(offsetX + box.columnWidth, offsetY + box.open);
+
+ ctx.stroke();
+ } else {
+ ctx.fillStyle = fill.down;
+ ctx.strokeStyle = stroke.down;
+
+ ctx.beginPath();
+
+ const [x, y] = [offsetX + box.columnWidth / 2, offsetY + box.open + box.boxHeight / 2];
+ const [rx, ry] = [box.columnWidth / 2, box.boxHeight / 2];
+
+ ctx.ellipse(x, y, rx, ry, 0, 0, 2 * Math.PI);
+ ctx.stroke();
+ }
+ });
+ });
+
+ ctx.stroke();
+}
+
+function getColumns(xScale, xAccessor, yScale, plotData) {
+
+ const width = xScale(xAccessor(plotData[plotData.length - 1]))
+ - xScale(xAccessor(plotData[0]));
+
+ const columnWidth = (width / (plotData.length - 1));
+
+ let anyBox;
+ let j = 0;
+ while (isNotDefined(anyBox)) {
+ if (isDefined(plotData[j].close)) {
+ anyBox = plotData[j].boxes[0];
+ } else {
+ break;
+ }
+ j++;
+ }
+
+ const boxHeight = Math.abs(yScale(anyBox.open) - yScale(anyBox.close));
+
+ const columns = plotData
+ .filter((d) => isDefined(d.close))
+ .map((d) => {
+ const boxes = d.boxes.map((box) => ({
+ columnWidth,
+ boxHeight,
+ open: yScale(box.open),
+ close: yScale(box.close),
+ }));
+
+ const xOffset = (xScale(xAccessor(d)) - (columnWidth / 2));
+ return {
+ boxes,
+ direction: d.direction,
+ offset: [xOffset, 0],
+ };
+ });
+ return columns;
+}
diff --git a/packages/react-financial-charts/src/series/RSISeries.tsx b/packages/react-financial-charts/src/series/RSISeries.tsx
new file mode 100644
index 000000000..16be85f77
--- /dev/null
+++ b/packages/react-financial-charts/src/series/RSISeries.tsx
@@ -0,0 +1,215 @@
+import * as React from "react";
+import {
+ strokeDashTypes,
+} from "../utils";
+import { LineSeries } from "./LineSeries";
+import { StraightLine } from "./StraightLine";
+import { SVGComponent } from "./SVGComponent";
+
+interface RSISeriesProps {
+ className?: string;
+ yAccessor: any; // func
+ stroke: {
+ line: strokeDashTypes;
+ top: string;
+ middle: string;
+ bottom: string;
+ outsideThreshold: string;
+ insideThreshold: string;
+ };
+ opacity: {
+ top: number;
+ middle: number;
+ bottom: number;
+ };
+ strokeDasharray: {
+ line: strokeDashTypes;
+ top: strokeDashTypes;
+ middle: strokeDashTypes;
+ bottom: strokeDashTypes;
+ };
+ strokeWidth: {
+ outsideThreshold: number;
+ insideThreshold: number;
+ top: number;
+ middle: number;
+ bottom: number;
+ };
+ overSold: number;
+ middle: number;
+ overBought: number;
+}
+
+export class RSISeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-rsi-series",
+ stroke: {
+ line: "#000000",
+ top: "#B8C2CC",
+ middle: "#8795A1",
+ bottom: "#B8C2CC",
+ outsideThreshold: "#b300b3",
+ insideThreshold: "#ffccff",
+ },
+ opacity: {
+ top: 1,
+ middle: 1,
+ bottom: 1,
+ },
+ strokeDasharray: {
+ line: "Solid",
+ top: "ShortDash",
+ middle: "ShortDash",
+ bottom: "ShortDash",
+ },
+ strokeWidth: {
+ outsideThreshold: 1,
+ insideThreshold: 1,
+ top: 1,
+ middle: 1,
+ bottom: 1,
+ },
+ overSold: 70,
+ middle: 50,
+ overBought: 30,
+ };
+
+ private clipPathId1: string;
+ private clipPathId2: string;
+
+ constructor(props) {
+ super(props);
+
+ const id1 = String(Math.round(Math.random() * 10000 * 10000));
+ this.clipPathId1 = `rsi-clip-${id1}`;
+
+ const id2 = String(Math.round(Math.random() * 10000 * 10000));
+ this.clipPathId2 = `rsi-clip-${id2}`;
+ }
+
+ public render() {
+ const { className, stroke, opacity, strokeDasharray, strokeWidth } = this.props;
+ const { yAccessor } = this.props;
+ const { overSold, middle, overBought } = this.props;
+
+ const style1 = { clipPath: `url(#${this.clipPathId1})` };
+ const style2 = { clipPath: `url(#${this.clipPathId2})` };
+
+ return (
+
+
+ {this.renderClip}
+
+
+
+
+
+
+
+ );
+ }
+
+ private readonly renderClip = (moreProps) => {
+ const { chartConfig } = moreProps;
+ const { overSold, overBought } = this.props;
+ const { yScale, width, height } = chartConfig;
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ private readonly mainClip = (ctx, moreProps) => {
+ const { chartConfig } = moreProps;
+ const { overSold, overBought } = this.props;
+ const { yScale, width, height } = chartConfig;
+
+ ctx.beginPath();
+ ctx.rect(
+ 0,
+ 0,
+ width,
+ yScale(overSold),
+ );
+ ctx.rect(
+ 0,
+ yScale(overBought),
+ width,
+ height - yScale(overBought),
+ );
+ ctx.clip();
+ }
+
+ private readonly topAndBottomClip = (ctx, moreProps) => {
+ const { chartConfig } = moreProps;
+ const { overSold, overBought } = this.props;
+ const { yScale, width } = chartConfig;
+
+ ctx.beginPath();
+ ctx.rect(
+ 0,
+ yScale(overSold),
+ width,
+ yScale(overBought) - yScale(overSold),
+ );
+ ctx.clip();
+ }
+}
diff --git a/packages/react-financial-charts/src/series/RenkoSeries.tsx b/packages/react-financial-charts/src/series/RenkoSeries.tsx
new file mode 100644
index 000000000..60857d9ab
--- /dev/null
+++ b/packages/react-financial-charts/src/series/RenkoSeries.tsx
@@ -0,0 +1,134 @@
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { isDefined } from "../utils";
+
+interface RenkoSeriesProps {
+ classNames?: {
+ up: string,
+ down: string,
+ };
+ stroke: {
+ up: string,
+ down: string,
+ };
+ fill: {
+ up: string,
+ down: string,
+ partial: string,
+ };
+ yAccessor: any; // func
+ clip: boolean;
+}
+
+export class RenkoSeries extends React.Component {
+
+ public static defaultProps = {
+ classNames: {
+ up: "up",
+ down: "down",
+ },
+ stroke: {
+ up: "none",
+ down: "none",
+ },
+ fill: {
+ up: "#6BA583",
+ down: "#E60000",
+ partial: "#4682B4",
+ },
+ yAccessor: (d) => ({ open: d.open, high: d.high, low: d.low, close: d.close }),
+ clip: true,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return ;
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const { yAccessor } = this.props;
+
+ const candles = getRenko(this.props, plotData, xScale, xAccessor, yScale, yAccessor)
+ .map((each, idx) => ());
+
+ return (
+
+
+ {candles}
+
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const { yAccessor } = this.props;
+
+ const candles = getRenko(this.props, plotData, xScale, xAccessor, yScale, yAccessor);
+
+ drawOnCanvas(ctx, candles);
+ }
+}
+
+function drawOnCanvas(ctx, renko) {
+ renko.forEach((d) => {
+ ctx.beginPath();
+
+ ctx.strokeStyle = d.stroke;
+ ctx.fillStyle = d.fill;
+
+ ctx.rect(d.x, d.y, d.width, d.height);
+ ctx.closePath();
+ ctx.fill();
+ });
+}
+
+function getRenko(props, plotData, xScale, xAccessor, yScale, yAccessor) {
+ const { classNames, fill } = props;
+ const width = xScale(xAccessor(plotData[plotData.length - 1]))
+ - xScale(xAccessor(plotData[0]));
+
+ const candleWidth = (width / (plotData.length - 1));
+ const candles = plotData
+ .filter((d) => isDefined(yAccessor(d).close))
+ .map((d) => {
+ const ohlc = yAccessor(d);
+ const x = xScale(xAccessor(d)) - 0.5 * candleWidth;
+ const y = yScale(Math.max(ohlc.open, ohlc.close));
+ const height = Math.abs(yScale(ohlc.open) - yScale(ohlc.close));
+ const className = (ohlc.open <= ohlc.close) ? classNames.up : classNames.down;
+
+ const svgfill = d.fullyFormed
+ ? (ohlc.open <= ohlc.close ? fill.up : fill.down)
+ : fill.partial;
+
+ return {
+ className,
+ fill: svgfill,
+ x,
+ y,
+ height,
+ width: candleWidth,
+ };
+ });
+ return candles;
+}
diff --git a/packages/react-financial-charts/src/series/SARSeries.tsx b/packages/react-financial-charts/src/series/SARSeries.tsx
new file mode 100644
index 000000000..6c40ca27a
--- /dev/null
+++ b/packages/react-financial-charts/src/series/SARSeries.tsx
@@ -0,0 +1,114 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas, getMouseCanvas } from "../GenericComponent";
+
+import { first, hexToRGBA, isDefined, last } from "../utils";
+
+interface SARSeriesProps {
+ className?: string;
+ fill: {
+ falling: string;
+ rising: string;
+ };
+ yAccessor: any; // func
+ opacity: number;
+ onClick?: any; // func
+ onDoubleClick?: any; // func
+ onContextMenu?: any; // func
+ highlightOnHover?: boolean;
+}
+
+export class SARSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-sar",
+ fill: {
+ falling: "#4682B4",
+ rising: "#15EC2E",
+ },
+ highlightOnHover: true,
+ opacity: 0.2,
+ };
+
+ public render() {
+ const { highlightOnHover } = this.props;
+
+ const hoverProps = highlightOnHover
+ ? {
+ isHover: this.isHover,
+ drawOn: ["mousemove", "pan"],
+ canvasToDraw: getMouseCanvas,
+ }
+ : {
+ drawOn: ["pan"],
+ canvasToDraw: getAxisCanvas,
+ };
+
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className, yAccessor } = this.props;
+ const { xAccessor, plotData, xScale, chartConfig: { yScale } } = moreProps;
+
+ return
+ {plotData
+ .filter((each) => isDefined(yAccessor(each)))
+ .map((each, idx) => {
+ return (
+
+ );
+ })}
+ ;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { yAccessor, fill, opacity } = this.props;
+ const { xAccessor, plotData, xScale, chartConfig: { yScale }, hovering } = moreProps;
+
+ const width = xScale(xAccessor(last(plotData))) - xScale(xAccessor(first(plotData)));
+
+ const d = (width / plotData.length) * 0.5 / 2;
+ const radius = Math.min(2, Math.max(0.5, d)) + (hovering ? 2 : 0);
+
+ plotData.forEach((each) => {
+ const centerX = xScale(xAccessor(each));
+ const centerY = yScale(yAccessor(each));
+ const color = yAccessor(each) > each.close
+ ? fill.falling
+ : fill.rising;
+
+ ctx.fillStyle = hexToRGBA(color, opacity);
+ ctx.strokeStyle = color;
+
+ ctx.beginPath();
+ ctx.ellipse(centerX, centerY, radius, radius, 0, 0, 2 * Math.PI);
+ ctx.closePath();
+ ctx.fill();
+ ctx.stroke();
+ });
+ }
+
+ private readonly isHover = (moreProps) => {
+ const { mouseXY, currentItem, chartConfig: { yScale } } = moreProps;
+ const { yAccessor } = this.props;
+ const y = mouseXY[1];
+ const currentY = yScale(yAccessor(currentItem));
+ return y < currentY + 5 && y > currentY - 5;
+ }
+}
diff --git a/packages/react-financial-charts/src/series/SVGComponent.tsx b/packages/react-financial-charts/src/series/SVGComponent.tsx
new file mode 100644
index 000000000..afe36a0c0
--- /dev/null
+++ b/packages/react-financial-charts/src/series/SVGComponent.tsx
@@ -0,0 +1,15 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+
+export class SVGComponent extends React.Component {
+ public render() {
+ const { children } = this.props;
+ return (
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/series/ScatterSeries.tsx b/packages/react-financial-charts/src/series/ScatterSeries.tsx
new file mode 100644
index 000000000..7b440b804
--- /dev/null
+++ b/packages/react-financial-charts/src/series/ScatterSeries.tsx
@@ -0,0 +1,109 @@
+import { nest as d3Nest } from "d3-collection";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { functor, hexToRGBA } from "../utils";
+
+interface ScatterSeriesProps {
+ className?: string;
+ yAccessor: any; // func
+ marker?: any; // func
+ markerProvider?: any; // func
+ markerProps?: object;
+}
+
+export class ScatterSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-scatter",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className, markerProps } = this.props;
+ const { xAccessor } = moreProps;
+
+ const points = this.helper(this.props, moreProps, xAccessor);
+
+ return
+ {points.map((point, idx) => {
+ const { marker: Marker } = point;
+ return ;
+ })}
+ ;
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+
+ const points = this.helper(this.props, moreProps, xAccessor);
+
+ this.drawOnCanvasHelper(ctx, this.props, points);
+ }
+
+ private readonly helper = (props, moreProps, xAccessor) => {
+ const { yAccessor, markerProvider, markerProps } = props;
+ let { marker: Marker } = props;
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ if (!(markerProvider || Marker)) { throw new Error("required prop, either marker or markerProvider missing"); }
+
+ return plotData.map((d) => {
+
+ if (markerProvider) { Marker = markerProvider(d); }
+
+ const mProps = { ...Marker.defaultProps, ...markerProps };
+
+ const fill = functor(mProps.fill);
+ const stroke = functor(mProps.stroke);
+
+ return {
+ x: xScale(xAccessor(d)),
+ y: yScale(yAccessor(d)),
+ fill: hexToRGBA(fill(d), mProps.opacity),
+ stroke: stroke(d),
+ datum: d,
+ marker: Marker,
+ };
+ });
+ }
+
+ private readonly drawOnCanvasHelper = (ctx, props, points) => {
+
+ const { markerProps } = props;
+
+ const nest = d3Nest()
+ .key((d) => d.fill)
+ .key((d) => d.stroke)
+ .entries(points);
+
+ nest.forEach((fillGroup) => {
+ const { key: fillKey, values: fillValues } = fillGroup;
+
+ if (fillKey !== "none") {
+ ctx.fillStyle = fillKey;
+ }
+
+ fillValues.forEach((strokeGroup) => {
+ const { values: strokeValues } = strokeGroup;
+
+ strokeValues.forEach((point) => {
+ const { marker } = point;
+ marker.drawOnCanvas({ ...marker.defaultProps, ...markerProps, fill: fillKey }, point, ctx);
+ });
+ });
+ });
+ }
+}
diff --git a/packages/react-financial-charts/src/series/SquareMarker.tsx b/packages/react-financial-charts/src/series/SquareMarker.tsx
new file mode 100644
index 000000000..166b70d67
--- /dev/null
+++ b/packages/react-financial-charts/src/series/SquareMarker.tsx
@@ -0,0 +1,72 @@
+import * as React from "react";
+import { functor, hexToRGBA } from "../utils";
+
+interface SquareProps {
+ stroke?: string;
+ fill: string;
+ opacity: number;
+ point: {
+ x: number,
+ y: number,
+ datum: any,
+ };
+ className?: string;
+ strokeWidth?: number;
+ width: number | any; // func
+}
+
+export class Square extends React.Component {
+
+ public static defaultProps = {
+ stroke: "#4682B4",
+ strokeWidth: 1,
+ opacity: 0.5,
+ fill: "#4682B4",
+ className: "react-stockcharts-marker-rect",
+ };
+
+ public static drawOnCanvas = (props, point, ctx) => {
+ const { stroke, fill, opacity, strokeWidth } = props;
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = strokeWidth;
+ if (fill !== "none") {
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ }
+ Square.drawOnCanvasWithNoStateChange(props, point, ctx);
+ }
+
+ public static drawOnCanvasWithNoStateChange = (props, point, ctx) => {
+ const { width } = props;
+ const w = functor(width)(point.datum);
+ const x = point.x - (w / 2);
+ const y = point.y - (w / 2);
+ ctx.beginPath();
+ ctx.rect(x, y, w, w);
+ ctx.stroke();
+ ctx.fill();
+ }
+
+ public render() {
+ const {
+ className, stroke, strokeWidth,
+ opacity, fill, point, width,
+ } = this.props;
+ const w = functor(width)(point.datum);
+ const x = point.x - (w / 2);
+ const y = point.y - (w / 2);
+
+ return (
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/series/StackedBarSeries.tsx b/packages/react-financial-charts/src/series/StackedBarSeries.tsx
new file mode 100644
index 000000000..9789e8483
--- /dev/null
+++ b/packages/react-financial-charts/src/series/StackedBarSeries.tsx
@@ -0,0 +1,270 @@
+import { merge } from "d3-array";
+import { nest as d3Nest } from "d3-collection";
+import { stack as d3Stack } from "d3-shape";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { functor, head, hexToRGBA, identity, plotDataLengthBarWidth } from "../utils";
+
+interface StackedBarSeriesProps {
+ readonly baseAt: number | any; // func
+ readonly direction: "up" | "down";
+ readonly stroke: boolean;
+ readonly width: number | any; // func
+ readonly opacity: number;
+ readonly fill: string | any; // func
+ readonly className: string | any; // func
+ readonly clip: boolean;
+}
+
+export class StackedBarSeries extends React.Component {
+
+ public static defaultProps = {
+ baseAt: (xScale, yScale/* , d*/) => head(yScale.range()),
+ direction: "up",
+ className: "bar",
+ stroke: true,
+ fill: "#4682B4",
+ opacity: 0.5,
+ width: plotDataLengthBarWidth,
+ widthRatio: 0.8,
+ clip: true,
+ swapScales: false,
+ };
+
+ public render() {
+ const { clip } = this.props;
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor } = moreProps;
+
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, d3Stack);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { xAccessor } = moreProps;
+
+ return {svgHelper(this.props, moreProps, xAccessor, d3Stack)};
+ }
+}
+
+export function identityStack() {
+ let keys = [];
+ function stack(data) {
+ const response = keys.map((key, i) => {
+ const arrays = data.map((d) => {
+ const array = [0, d[key]];
+
+ // @ts-ignore
+ array.data = d;
+ return array;
+ });
+ arrays.key = key;
+ arrays.index = i;
+ return arrays;
+ });
+ return response;
+ }
+ stack.keys = function (x) {
+ if (!arguments.length) {
+ return keys;
+ }
+ keys = x;
+ return stack;
+ };
+ return stack;
+}
+
+export function drawOnCanvasHelper(ctx, props, moreProps, xAccessor, stackFn, defaultPostAction = identity, postRotateAction = rotateXY) {
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const bars = doStuff(props, xAccessor, plotData, xScale, yScale, stackFn, postRotateAction, defaultPostAction);
+
+ drawOnCanvas2(props, ctx, bars);
+}
+
+function convertToArray(item) {
+ return Array.isArray(item) ? item : [item];
+}
+
+export function svgHelper(props, moreProps, xAccessor, stackFn, defaultPostAction = identity, postRotateAction = rotateXY) {
+ const { xScale, chartConfig: { yScale }, plotData } = moreProps;
+ const bars = doStuff(props, xAccessor, plotData, xScale, yScale, stackFn, postRotateAction, defaultPostAction);
+ return getBarsSVG2(props, bars);
+}
+
+function doStuff(props, xAccessor, plotData, xScale, yScale, stackFn, postRotateAction, defaultPostAction) {
+ const { yAccessor, swapScales } = props;
+
+ const modifiedYAccessor = swapScales ? convertToArray(props.xAccessor) : convertToArray(yAccessor);
+ const modifiedXAccessor = swapScales ? yAccessor : xAccessor;
+
+ const modifiedXScale = swapScales ? yScale : xScale;
+ const modifiedYScale = swapScales ? xScale : yScale;
+
+ const postProcessor = swapScales ? postRotateAction : defaultPostAction;
+
+ const bars = getBars(props, modifiedXAccessor, modifiedYAccessor, modifiedXScale, modifiedYScale, plotData, stackFn, postProcessor);
+
+ return bars;
+}
+
+export const rotateXY = (array) => array.map((each) => {
+ return {
+ ...each,
+ x: each.y,
+ y: each.x,
+ height: each.width,
+ width: each.height,
+ };
+});
+
+export function getBarsSVG2(props, bars) {
+ /* eslint-disable react/prop-types */
+ const { opacity } = props;
+ /* eslint-enable react/prop-types */
+
+ return bars.map((d, idx) => {
+ if (d.width <= 1) {
+ return ;
+ }
+ return ;
+ });
+}
+
+export function drawOnCanvas2(props, ctx, bars) {
+ const { stroke } = props;
+
+ const nest = d3Nest()
+ .key((d) => d.fill)
+ .entries(bars);
+
+ nest.forEach((outer) => {
+ const { key, values } = outer;
+ if (head(values).width > 1) {
+ ctx.strokeStyle = key;
+ }
+ const fillStyle = head(values).width <= 1
+ ? key
+ : hexToRGBA(key, props.opacity);
+ ctx.fillStyle = fillStyle;
+
+ values.forEach((d) => {
+ if (d.width <= 1) {
+ ctx.fillRect(d.x - 0.5, d.y, 1, d.height);
+ } else {
+ ctx.fillRect(d.x, d.y, d.width, d.height);
+ if (stroke) { ctx.strokeRect(d.x, d.y, d.width, d.height); }
+ }
+
+ });
+ });
+}
+
+export function getBars(props, xAccessor, yAccessor, xScale, yScale, plotData, stack = identityStack, after = identity) {
+ const { baseAt, className, fill, stroke, spaceBetweenBar = 0 } = props;
+
+ const getClassName = functor(className);
+ const getFill = functor(fill);
+ const getBase = functor(baseAt);
+
+ const widthFunctor = functor(props.width);
+ const width = widthFunctor(props, {
+ xScale,
+ xAccessor,
+ plotData,
+ });
+
+ const barWidth = Math.round(width);
+
+ const eachBarWidth = (barWidth - spaceBetweenBar * (yAccessor.length - 1)) / yAccessor.length;
+
+ const offset = (barWidth === 1 ? 0 : 0.5 * width);
+
+ const ds = plotData
+ .map((each) => {
+ const d = {
+ appearance: {
+ },
+ x: xAccessor(each),
+ };
+ yAccessor.forEach((eachYAccessor, i) => {
+ const key = `y${i}`;
+ d[key] = eachYAccessor(each);
+ const appearance = {
+ className: getClassName(each, i),
+ stroke: stroke ? getFill(each, i) : "none",
+ fill: getFill(each, i),
+ };
+ d.appearance[key] = appearance;
+ });
+ return d;
+ });
+
+ const keys = yAccessor.map((_, i) => `y${i}`);
+
+ // @ts-ignore
+ const data = stack().keys(keys)(ds);
+
+ const newData = data.map((each, i) => {
+ const key = each.key;
+ return each.map((d) => {
+ const array = [d[0], d[1]];
+
+ // @ts-ignore
+ array.data = {
+ x: d.data.x,
+ i,
+ appearance: d.data.appearance[key],
+ };
+ return array;
+ });
+ });
+
+ const bars = merge(newData)
+ .map((d) => {
+ let y = yScale(d[1]);
+ let h = getBase(xScale, yScale, d.data) - yScale(d[1] - d[0]);
+ if (h < 0) {
+ y = y + h;
+ h = -h;
+ }
+
+ return {
+ ...d.data.appearance,
+ x: Math.round(xScale(d.data.x) - width / 2),
+ y,
+ groupOffset: Math.round(offset - (d.data.i > 0 ? (eachBarWidth + spaceBetweenBar) * d.data.i : 0)),
+ groupWidth: Math.round(eachBarWidth),
+ offset: Math.round(offset),
+ height: h,
+ width: barWidth,
+ };
+ })
+ .filter((bar) => !isNaN(bar.y));
+
+ return after(bars);
+}
diff --git a/packages/react-financial-charts/src/series/StochasticSeries.tsx b/packages/react-financial-charts/src/series/StochasticSeries.tsx
new file mode 100644
index 000000000..f1363d4e7
--- /dev/null
+++ b/packages/react-financial-charts/src/series/StochasticSeries.tsx
@@ -0,0 +1,79 @@
+import * as React from "react";
+
+import { LineSeries } from "./LineSeries";
+import { StraightLine } from "./StraightLine";
+
+interface StochasticSeriesProps {
+ className?: string;
+ yAccessor: any; // func
+ stroke: {
+ top: string;
+ middle: string;
+ bottom: string;
+ dLine: string;
+ kLine: string;
+ };
+ overSold: number;
+ middle: number;
+ overBought: number;
+ refLineOpacity: number;
+}
+
+export class StochasticSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-stochastic-series",
+ stroke: {
+ top: "#964B00",
+ middle: "#000000",
+ bottom: "#964B00",
+ dLine: "#EA2BFF",
+ kLine: "#74D400",
+ },
+ overSold: 80,
+ middle: 50,
+ overBought: 20,
+ refLineOpacity: 0.3,
+ };
+
+ public render() {
+ const { className, stroke, refLineOpacity } = this.props;
+ const { overSold, middle, overBought } = this.props;
+ return (
+
+
+
+
+
+
+
+ );
+ }
+
+ private readonly yAccessorForK = (d) => {
+ const { yAccessor } = this.props;
+
+ return yAccessor(d) && yAccessor(d).K;
+ }
+
+ private readonly yAccessorForD = (d) => {
+ const { yAccessor } = this.props;
+
+ return yAccessor(d) && yAccessor(d).D;
+ }
+}
diff --git a/packages/react-financial-charts/src/series/StraightLine.tsx b/packages/react-financial-charts/src/series/StraightLine.tsx
new file mode 100644
index 000000000..a6fc0258b
--- /dev/null
+++ b/packages/react-financial-charts/src/series/StraightLine.tsx
@@ -0,0 +1,86 @@
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+import { getStrokeDasharray, hexToRGBA, strokeDashTypes } from "../utils";
+
+interface StraightLineProps {
+ className?: string;
+ type?: "vertical" | "horizontal";
+ stroke?: string;
+ strokeWidth?: number;
+ strokeDasharray?: strokeDashTypes;
+ opacity: number;
+ yValue?: number;
+ xValue?: number;
+}
+
+export class StraightLine extends React.Component {
+
+ public static defaultProps = {
+ className: "line",
+ type: "horizontal",
+ stroke: "#000000",
+ opacity: 0.5,
+ strokeWidth: 1,
+ strokeDasharray: "Solid",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { width, height } = moreProps;
+ const { xScale, chartConfig: { yScale } } = moreProps;
+
+ const { className } = this.props;
+ const { type, stroke, strokeWidth, opacity, strokeDasharray } = this.props;
+ const { yValue, xValue } = this.props;
+
+ const lineCoordinates = this.getLineCoordinates(type, xScale, yScale, xValue, yValue, width, height);
+
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { type, stroke, strokeWidth, opacity, strokeDasharray } = this.props;
+ const { yValue, xValue } = this.props;
+ const { xScale } = moreProps;
+ const { chartConfig: { yScale, width, height } } = moreProps;
+
+ ctx.beginPath();
+
+ ctx.strokeStyle = hexToRGBA(stroke, opacity);
+ ctx.lineWidth = strokeWidth;
+
+ const { x1, y1, x2, y2 } = this.getLineCoordinates(type, xScale, yScale, xValue, yValue, width, height);
+
+ ctx.setLineDash(getStrokeDasharray(strokeDasharray).split(","));
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ }
+
+ private readonly getLineCoordinates = (type, xScale, yScale, xValue, yValue, width, height) => {
+ return type === "horizontal"
+ ? { x1: 0, y1: Math.round(yScale(yValue)), x2: width, y2: Math.round(yScale(yValue)) }
+ : { x1: Math.round(xScale(xValue)), y1: 0, x2: Math.round(xScale(xValue)), y2: height };
+ }
+}
diff --git a/packages/react-financial-charts/src/series/TriangleMarker.tsx b/packages/react-financial-charts/src/series/TriangleMarker.tsx
new file mode 100644
index 000000000..d62a735a8
--- /dev/null
+++ b/packages/react-financial-charts/src/series/TriangleMarker.tsx
@@ -0,0 +1,145 @@
+import * as React from "react";
+import { functor, hexToRGBA } from "../utils";
+
+interface TriangleProps {
+ direction: "top" | "bottom" | "left" | "right" | "hide";
+ stroke: string | any; // func
+ fill: string | any;
+ opacity: number;
+ point: {
+ x: number,
+ y: number,
+ datum: any,
+ };
+ className?: string;
+ strokeWidth?: number;
+ width: number | any; // func
+}
+
+export class Triangle extends React.Component {
+
+ public static defaultProps = {
+ direction: "top",
+ stroke: "#4682B4",
+ strokeWidth: 1,
+ opacity: 0.5,
+ fill: "#4682B4",
+ className: "react-stockcharts-marker-triangle",
+ };
+
+ public static drawOnCanvas = (props, point, ctx) => {
+ const { stroke, fill, opacity, strokeWidth } = props;
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = strokeWidth;
+ if (fill !== "none") {
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ }
+ Triangle.drawOnCanvasWithNoStateChange(props, point, ctx);
+ }
+
+ public static drawOnCanvasWithNoStateChange = (props, point, ctx) => {
+
+ const { width } = props;
+ const w = functor(width)(point.datum);
+ const { x, y } = point;
+ const { innerOpposite, innerHypotenuse } = getTrianglePoints(w);
+ const rotationDeg = getRotationInDegrees(props, point);
+
+ ctx.beginPath();
+ ctx.moveTo(x, y - innerHypotenuse);
+ ctx.lineTo(x + (w / 2), y + innerOpposite);
+ ctx.lineTo(x - (w / 2), y + innerOpposite);
+ ctx.stroke();
+
+ // TODO: rotation does not work
+ // example: https://gist.github.com/geoffb/6392450
+ if (rotationDeg !== null && rotationDeg !== 0) {
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(rotationDeg * Math.PI / 180); // 45 degrees
+ ctx.fill();
+ ctx.restore();
+ }
+ ctx.fill();
+ }
+
+ public render() {
+
+ const {
+ className, strokeWidth,
+ opacity, point, width,
+ } = this.props;
+
+ const rotation = getRotationInDegrees(this.props, point);
+ if (rotation == null) {
+ return null;
+ }
+
+ const fillColor = getFillColor(this.props);
+ const strokeColor = getStrokeColor(this.props);
+
+ const w = functor(width)(point.datum);
+ const { x, y } = point;
+ const { innerOpposite, innerHypotenuse } = getTrianglePoints(w);
+ const points = `
+ ${x} ${y - innerHypotenuse},
+ ${x + (w / 2)} ${y + innerOpposite},
+ ${x - (w / 2)} ${y + innerOpposite}
+ `;
+
+ return (
+
+ );
+ }
+}
+
+function getTrianglePoints(width) {
+ const innerHypotenuse = (width / 2) * (1 / Math.cos(30 * Math.PI / 180));
+ const innerOpposite = (width / 2) * (1 / Math.tan(60 * Math.PI / 180));
+ return {
+ innerOpposite,
+ innerHypotenuse,
+ };
+}
+
+function getFillColor(props) {
+ const { fill, point } = props;
+
+ return fill instanceof Function ? fill(point.datum) : fill;
+}
+
+function getStrokeColor(props) {
+ const { stroke, point } = props;
+
+ return stroke instanceof Function ? stroke(point.datum) : stroke;
+}
+
+function getRotationInDegrees(props, point) {
+ const { direction } = props;
+ const directionVal = direction instanceof Function ? direction(point.datum) : direction;
+ if (directionVal === "hide") {
+ return null;
+ }
+
+ let rotate = 0;
+ switch (directionVal) {
+ case "bottom":
+ rotate = 180;
+ break;
+ case "left":
+ rotate = -90;
+ break;
+ case "right":
+ rotate = 90;
+ break;
+ }
+ return rotate;
+}
diff --git a/packages/react-financial-charts/src/series/VolumeProfileSeries.tsx b/packages/react-financial-charts/src/series/VolumeProfileSeries.tsx
new file mode 100644
index 000000000..5fc3c29cb
--- /dev/null
+++ b/packages/react-financial-charts/src/series/VolumeProfileSeries.tsx
@@ -0,0 +1,237 @@
+import { ascending, descending, histogram as d3Histogram, max, merge, sum, zip } from "d3-array";
+import { nest } from "d3-collection";
+import { scaleLinear } from "d3-scale";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { getAxisCanvas } from "../GenericComponent";
+
+import { accumulatingWindow, functor, head, hexToRGBA, identity, last } from "../utils";
+
+interface VolumeProfileSeriesProps {
+ className?: string;
+ opacity?: number;
+ showSessionBackground?: boolean;
+ sessionBackGround?: string;
+ sessionBackGroundOpacity?: number;
+}
+
+export class VolumeProfileSeries extends React.Component {
+
+ public static defaultProps = {
+ className: "line ",
+ bins: 20,
+ opacity: 0.5,
+ maxProfileWidthPercent: 50,
+ fill: ({ type }) => type === "up" ? "#6BA583" : "#FF0000",
+ stroke: "#FFFFFF",
+ showSessionBackground: false,
+ sessionBackGround: "#4682B4",
+ sessionBackGroundOpacity: 0.3,
+ source: (d) => d.close,
+ volume: (d) => d.volume,
+ absoluteChange: (d) => d.absoluteChange,
+ bySession: false,
+ sessionStart: ({ d, i, plotData }) => i > 0 && plotData[i - 1].date.getMonth() !== d.date.getMonth(),
+ orient: "left",
+ partialStartOK: true,
+ partialEndOK: true,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const { xAccessor, width } = moreProps;
+ const { rects, sessionBg } = this.helper(this.props, moreProps, xAccessor, width);
+
+ this.drawOnCanvasContext(ctx, this.props, rects, sessionBg);
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { className, opacity } = this.props;
+ const { showSessionBackground, sessionBackGround, sessionBackGroundOpacity } = this.props;
+
+ const { xAccessor, width } = moreProps;
+ const { rects, sessionBg } = this.helper(this.props, moreProps, xAccessor, width);
+
+ const sessionBgSvg = showSessionBackground
+ ? sessionBg.map((d, idx) => )
+ : null;
+
+ return (
+
+ {sessionBgSvg}
+ {rects.map((d, i) =>
+
+
+ )}
+
+ );
+ }
+
+ private readonly drawOnCanvasContext = (ctx, props, rects, sessionBg) => {
+ const { opacity, sessionBackGround, sessionBackGroundOpacity, showSessionBackground } = props;
+
+ if (showSessionBackground) {
+ ctx.fillStyle = hexToRGBA(sessionBackGround, sessionBackGroundOpacity);
+
+ sessionBg.forEach((each) => {
+ const { x, y, height, width } = each;
+
+ ctx.beginPath();
+ ctx.rect(x, y, width, height);
+ ctx.closePath();
+ ctx.fill();
+ });
+ }
+
+ rects.forEach((each) => {
+ const { x, y, height, w1, w2, stroke1, stroke2, fill1, fill2 } = each;
+
+ if (w1 > 0) {
+ ctx.fillStyle = hexToRGBA(fill1, opacity);
+ if (stroke1 !== "none") { ctx.strokeStyle = stroke1; }
+
+ ctx.beginPath();
+ ctx.rect(x, y, w1, height);
+ ctx.closePath();
+ ctx.fill();
+
+ if (stroke1 !== "none") { ctx.stroke(); }
+ }
+
+ if (w2 > 0) {
+ ctx.fillStyle = hexToRGBA(fill2, opacity);
+ if (stroke2 !== "none") { ctx.strokeStyle = stroke2; }
+
+ ctx.beginPath();
+ ctx.rect(x + w1, y, w2, height);
+ ctx.closePath();
+ ctx.fill();
+
+ if (stroke2 !== "none") { ctx.stroke(); }
+ }
+ });
+ }
+
+ private readonly helper = (props, moreProps, xAccessor, width) => {
+ const { xScale: realXScale, chartConfig: { yScale }, plotData } = moreProps;
+
+ const { sessionStart, bySession, partialStartOK, partialEndOK } = props;
+
+ const { bins, maxProfileWidthPercent, source, volume, absoluteChange, orient, fill, stroke } = props;
+
+ const sessionBuilder = accumulatingWindow()
+ .discardTillStart(!partialStartOK)
+ // @ts-ignore
+ .discardTillEnd(!partialEndOK)
+ .accumulateTill((d, i) => {
+ return sessionStart({ d, i, ...moreProps });
+ })
+ .accumulator(identity);
+
+ const dx = plotData.length > 1 ? realXScale(xAccessor(plotData[1])) - realXScale(xAccessor(head(plotData))) : 0;
+
+ const sessions = bySession ? sessionBuilder(plotData) : [plotData];
+
+ const allRects = sessions.map((session) => {
+
+ const begin = bySession ? realXScale(xAccessor(head(session))) : 0;
+ const finish = bySession ? realXScale(xAccessor(last(session))) : width;
+ const sessionWidth = finish - begin + dx;
+
+ const histogram2 = d3Histogram()
+ .value(source)
+ .thresholds(bins);
+
+ const rollup = nest()
+ .key((d) => d.direction)
+ .sortKeys(orient === "right" ? descending : ascending)
+ .rollup((leaves) => sum(leaves, (d) => d.volume));
+
+ const values = histogram2(session);
+
+ const volumeInBins = values
+ .map((arr) => arr.map((d) => {
+ return absoluteChange(d) > 0 ? { direction: "up", volume: volume(d) } : { direction: "down", volume: volume(d) };
+ }))
+ .map((arr) => rollup.entries(arr));
+
+ const volumeValues = volumeInBins
+ .map((each) => sum(each.map((d) => d.value)));
+
+ const base = (xScaleD) => head(xScaleD.range());
+
+ const [start, end] = orient === "right"
+ ? [begin, begin + sessionWidth * maxProfileWidthPercent / 100]
+ : [finish, finish - sessionWidth * (100 - maxProfileWidthPercent) / 100];
+
+ const xScale = scaleLinear()
+ .domain([0, max(volumeValues)])
+ .range([start, end]);
+
+ const totalVolumes = volumeInBins.map((volumes) => {
+
+ const totalVolume = sum(volumes, (d) => d.value);
+ const totalVolumeX = xScale(totalVolume);
+ const widthLocal = base(xScale) - totalVolumeX;
+ const x = widthLocal < 0 ? totalVolumeX + widthLocal : totalVolumeX;
+
+ const ws = volumes.map((d) => {
+ return {
+ type: d.key,
+ width: d.value * Math.abs(widthLocal) / totalVolume,
+ };
+ });
+
+ return { x, ws, totalVolumeX };
+ });
+
+ const rects = zip(values, totalVolumes)
+ .map(([d, { x, ws }]) => {
+ const w1 = ws[0] || { type: "up", width: 0 };
+ const w2 = ws[1] || { type: "down", width: 0 };
+
+ return {
+ y: yScale(d.x1),
+ height: yScale(d.x1) - yScale(d.x0),
+ x,
+ width,
+ w1: w1.width,
+ w2: w2.width,
+ stroke1: functor(stroke)(w1),
+ stroke2: functor(stroke)(w2),
+ fill1: functor(fill)(w1),
+ fill2: functor(fill)(w2),
+ };
+ });
+
+ const sessionBg = {
+ x: begin,
+ y: last(rects).y,
+ height: head(rects).y - last(rects).y + head(rects).height,
+ width: sessionWidth,
+ };
+
+ return { rects, sessionBg };
+ });
+
+ return {
+ rects: merge(allRects.map((d) => d.rects)),
+ sessionBg: allRects.map((d) => d.sessionBg),
+ };
+ }
+}
diff --git a/packages/react-financial-charts/src/series/index.ts b/packages/react-financial-charts/src/series/index.ts
new file mode 100644
index 000000000..db18712ca
--- /dev/null
+++ b/packages/react-financial-charts/src/series/index.ts
@@ -0,0 +1,24 @@
+export * from "./AreaSeries";
+export * from "./AlternatingFillAreaSeries";
+export * from "./AreaOnlySeries";
+export * from "./CircleMarker";
+export * from "./TriangleMarker";
+export * from "./SquareMarker";
+export * from "./LineSeries";
+export * from "./CandlestickSeries";
+export * from "./OHLCSeries";
+export * from "./BarSeries";
+export { StackedBarSeries } from "./StackedBarSeries";
+export * from "./GroupedBarSeries";
+export * from "./KagiSeries";
+export * from "./PointAndFigureSeries";
+export * from "./RenkoSeries";
+export * from "./MACDSeries";
+export * from "./BollingerSeries";
+export * from "./RSISeries";
+export * from "./StochasticSeries";
+export * from "./ElderRaySeries";
+export * from "./VolumeProfileSeries";
+export * from "./ScatterSeries";
+export * from "./StraightLine";
+export * from "./SARSeries";
diff --git a/packages/react-financial-charts/src/tooltip/BollingerBandTooltip.tsx b/packages/react-financial-charts/src/tooltip/BollingerBandTooltip.tsx
new file mode 100644
index 000000000..2432f0072
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/BollingerBandTooltip.tsx
@@ -0,0 +1,87 @@
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor, isDefined } from "../utils";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+interface BollingerBandTooltipProps {
+ className?: string;
+ yAccessor: any; // func
+ displayValuesFor?: any; // func
+ displayFormat: any; // func
+ origin: number[];
+ onClick?: any; // func
+ options: {
+ sourcePath: string;
+ windowSize: number;
+ multiplier: number;
+ movingAverageType: string;
+ };
+ textFill?: string;
+ labelFill?: string;
+ fontFamily?: string;
+ fontSize?: number;
+}
+
+export class BollingerBandTooltip extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip react-stockcharts-bollingerband-tooltip",
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 10],
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { onClick, displayFormat, yAccessor, options, textFill, labelFill } = this.props;
+ const { displayValuesFor } = this.props;
+
+ const { chartConfig: { width, height } } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+
+ let top;
+ let middle;
+ let bottom;
+ top = middle = bottom = "n/a";
+
+ if (isDefined(currentItem)
+ && isDefined(yAccessor(currentItem))) {
+ const item = yAccessor(currentItem);
+ top = displayFormat(item.top);
+ middle = displayFormat(item.middle);
+ bottom = displayFormat(item.bottom);
+ }
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ const { sourcePath, windowSize, multiplier, movingAverageType } = options;
+ const tooltipLabel = `BB(${sourcePath}, ${windowSize}, ${multiplier}, ${movingAverageType}): `;
+ const tooltipValue = `${top}, ${middle}, ${bottom}`;
+ return (
+
+
+ {tooltipLabel}
+ {tooltipValue}
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/GroupTooltip.tsx b/packages/react-financial-charts/src/tooltip/GroupTooltip.tsx
new file mode 100644
index 000000000..e8489db27
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/GroupTooltip.tsx
@@ -0,0 +1,261 @@
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+type layouts =
+ "horizontal" |
+ "horizontalRows" |
+ "horizontalInline" |
+ "vertical" |
+ "verticalRows";
+
+interface SingleTooltipProps {
+ origin: number[];
+ yLabel: string;
+ yValue: string;
+ onClick?: ((details: any, event: React.MouseEvent) => void);
+ fontFamily?: string;
+ labelFill: string;
+ valueFill: string;
+ fontSize?: number;
+ withShape: boolean;
+ forChart: number | string;
+ options: any;
+ layout: layouts;
+}
+
+export class SingleTooltip extends React.Component {
+
+ public static defaultProps = {
+ labelFill: "#4682B4",
+ valueFill: "#000000",
+ withShape: false,
+ };
+
+ /*
+ * Renders the value next to the label.
+ */
+ public renderValueNextToLabel() {
+ const { origin, yLabel, yValue, labelFill, valueFill, withShape, fontSize, fontFamily } = this.props;
+
+ return (
+
+ {withShape ? : null}
+
+ {yLabel}:
+ {yValue}
+
+
+ );
+ }
+
+ /*
+ * Renders the value beneath the label.
+ */
+ public renderValueBeneathToLabel() {
+ const { origin, yLabel, yValue, labelFill, valueFill, withShape, fontSize, fontFamily } = this.props;
+
+ return (
+
+ {withShape ? : null}
+
+ {yLabel}
+ {yValue}
+
+
+ );
+ }
+
+ /*
+ * Renders the value next to the label.
+ * The parent component must have a "text"-element.
+ */
+ public renderInline() {
+ const { yLabel, yValue, labelFill, valueFill, fontSize, fontFamily } = this.props;
+
+ return (
+
+ {yLabel}:
+ {yValue}
+
+ );
+ }
+
+ public render() {
+
+ const { layout } = this.props;
+ let comp: JSX.Element | null = null;
+
+ switch (layout) {
+ case "horizontal":
+ comp = this.renderValueNextToLabel();
+ break;
+ case "horizontalRows":
+ comp = this.renderValueBeneathToLabel();
+ break;
+ case "horizontalInline":
+ comp = this.renderInline();
+ break;
+ case "vertical":
+ comp = this.renderValueNextToLabel();
+ break;
+ case "verticalRows":
+ comp = this.renderValueBeneathToLabel();
+ break;
+ default:
+ comp = this.renderValueNextToLabel();
+ }
+
+ return comp;
+ }
+
+ private readonly handleClick = (e: React.MouseEvent) => {
+ const { onClick, forChart, options } = this.props;
+
+ if (onClick !== undefined) {
+ onClick({ chartId: forChart, ...options }, e);
+ }
+ }
+}
+
+interface GroupTooltipProps {
+ className?: string;
+ layout: layouts;
+ position: "topRight" | "bottomLeft" | "bottomRight";
+ displayFormat: any; // func
+ origin: number[];
+ displayValuesFor: any; // func
+ onClick?: ((event: React.MouseEvent) => void);
+ fontFamily?: string;
+ fontSize?: number;
+ width?: number; // "width" only be used, if layout is "horizontal" or "horizontalRows".
+ verticalSize?: number; // "verticalSize" only be used, if layout is "vertical", "verticalRows".
+ options: Array<{
+ labelFill?: string;
+ yLabel: string | any; // func
+ yAccessor: any;
+ valueFill?: string;
+ withShape?: boolean;
+ }>;
+ yAccessor: any; // func
+ labelFill?: string;
+ valueFill?: string;
+ withShape: boolean; // "withShape" is ignored, if layout is "horizontalInline" or "vertical".
+}
+
+// tslint:disable-next-line: max-classes-per-file
+export class GroupTooltip extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip react-stockcharts-group-tooltip",
+ layout: "horizontal",
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 0],
+ width: 60,
+ verticalSize: 13,
+ };
+
+ public getPosition(moreProps) {
+ const { position } = this.props;
+ const { height, width } = moreProps.chartConfig;
+
+ const dx = 20;
+ const dy = 40;
+ let textAnchor: string | undefined;
+ let xyPos: Array | null = null;
+
+ if (position !== undefined) {
+ switch (position) {
+ case "topRight":
+ xyPos = [width - dx, null];
+ textAnchor = "end";
+ break;
+ case "bottomLeft":
+ xyPos = [null, height - dy];
+ break;
+ case "bottomRight":
+ xyPos = [width - dx, height - dy];
+ textAnchor = "end";
+ break;
+ default:
+ xyPos = [null, null];
+ }
+ } else {
+ xyPos = [null, null];
+ }
+
+ return { xyPos, textAnchor };
+ }
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+
+ const { displayValuesFor } = this.props;
+ const { chartId } = moreProps;
+
+ const { className, onClick, width = 60, verticalSize = 13, fontFamily, fontSize, layout } = this.props;
+ const { origin, displayFormat, options } = this.props;
+ const currentItem = displayValuesFor(this.props, moreProps);
+ const { xyPos, textAnchor } = this.getPosition(moreProps);
+
+ const xPos = xyPos != null && xyPos[0] != null ? xyPos[0] : origin[0];
+ const yPos = xyPos != null && xyPos[1] != null ? xyPos[1] : origin[1];
+
+ const singleTooltip = options.map((each, idx) => {
+
+ const yValue = currentItem && each.yAccessor(currentItem);
+ const yDisplayValue = yValue ? displayFormat(yValue) : "n/a";
+
+ const orig = () => {
+ if (layout === "horizontal" || layout === "horizontalRows") {
+ return [width * idx, 0];
+ }
+ if (layout === "vertical") {
+ return [0, verticalSize * idx];
+ }
+ if (layout === "verticalRows") {
+ return [0, verticalSize * 2.3 * idx];
+ }
+ return [0, 0];
+ };
+
+ return ;
+ });
+
+ return (
+
+ {layout === "horizontalInline"
+ ? {singleTooltip}
+ : singleTooltip
+ }
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/HoverTooltip.tsx b/packages/react-financial-charts/src/tooltip/HoverTooltip.tsx
new file mode 100644
index 000000000..560153b94
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/HoverTooltip.tsx
@@ -0,0 +1,283 @@
+import { sum } from "d3-array";
+import * as PropTypes from "prop-types";
+import * as React from "react";
+import GenericComponent from "../GenericComponent";
+
+import { first, hexToRGBA, isDefined, isNotDefined, last } from "../utils";
+
+interface HoverTooltipProps {
+ chartId?: number | string;
+ yAccessor?: any; // func
+ tooltipSVG?: any; // func
+ backgroundShapeSVG?: any; // func
+ bgwidth?: number;
+ bgheight?: number;
+ bgFill: string;
+ bgOpacity: number;
+ tooltipContent: any; // func
+ origin: number[] | any; // func
+ fontFamily?: string;
+ fontSize?: number;
+}
+
+class HoverTooltip extends React.Component {
+
+ public static defaultProps = {
+ tooltipSVG,
+ tooltipCanvas,
+ origin,
+ fill: "#D4E2FD",
+ bgFill: "#D4E2FD",
+ bgOpacity: 0.5,
+ stroke: "#9B9BFF",
+ fontFill: "#000000",
+ opacity: 0.8,
+ backgroundShapeSVG,
+ backgroundShapeCanvas,
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 12,
+ };
+
+ public static contextTypes = {
+ margin: PropTypes.object.isRequired,
+ ratio: PropTypes.number.isRequired,
+ };
+
+ public render() {
+ return ;
+ }
+
+ private readonly renderSVG = (moreProps) => {
+
+ const pointer = helper(this.props, moreProps);
+
+ if (pointer === undefined) {
+ return null;
+ }
+
+ const { bgFill, bgOpacity, backgroundShapeSVG, tooltipSVG } = this.props;
+ const { bgheight, bgwidth } = this.props;
+ const { height } = moreProps;
+
+ const { x, y, content, centerX, pointWidth, bgSize } = pointer;
+
+ const bgShape = isDefined(bgwidth) && isDefined(bgheight)
+ ? { width: bgwidth, height: bgheight }
+ : bgSize;
+
+ return (
+
+
+
+ {backgroundShapeSVG(this.props, bgShape)}
+ {tooltipSVG(this.props, content)}
+
+
+ );
+ }
+ private readonly drawOnCanvas = (ctx, moreProps) => {
+ const pointer = helper(this.props, moreProps, ctx);
+ const { height } = moreProps;
+
+ if (isNotDefined(pointer)) {
+ return null;
+ }
+
+ drawOnCanvas(ctx, this.props, this.context, pointer, height);
+ }
+}
+
+const PADDING = 5;
+const X = 10;
+const Y = 10;
+
+function backgroundShapeSVG({ fill, stroke, opacity }, { height, width }) {
+ return ;
+}
+
+function tooltipSVG({ fontFamily, fontSize, fontFill }, content) {
+ const tspans: any[] = [];
+ const startY = Y + fontSize * 0.9;
+
+ for (let i = 0; i < content.y.length; i++) {
+ const y = content.y[i];
+ const textY = startY + (fontSize * (i + 1));
+
+ tspans.push({y.label});
+ tspans.push(: );
+ tspans.push({y.value});
+ }
+ return
+ {content.x}
+ {tspans}
+ ;
+}
+
+function backgroundShapeCanvas(props, { width, height }, ctx) {
+ const { fill, stroke, opacity } = props;
+
+ ctx.fillStyle = hexToRGBA(fill, opacity);
+ ctx.strokeStyle = stroke;
+ ctx.beginPath();
+ ctx.rect(0, 0, width, height);
+ ctx.fill();
+ ctx.stroke();
+}
+
+function tooltipCanvas({ fontFamily, fontSize, fontFill }, content, ctx) {
+ const startY = Y + fontSize * 0.9;
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = fontFill;
+ ctx.textAlign = "left";
+ ctx.fillText(content.x, X, startY);
+
+ for (let i = 0; i < content.y.length; i++) {
+ const y = content.y[i];
+ const textY = startY + (fontSize * (i + 1));
+ ctx.fillStyle = y.stroke || fontFill;
+ ctx.fillText(y.label, X, textY);
+
+ ctx.fillStyle = fontFill;
+ ctx.fillText(": " + y.value, X + ctx.measureText(y.label).width, textY);
+ }
+}
+
+function drawOnCanvas(ctx, props, context, pointer, height) {
+
+ const { margin, ratio } = context;
+ const { bgFill, bgOpacity } = props;
+ const { backgroundShapeCanvas, tooltipCanvas } = props;
+
+ const originX = 0.5 * ratio + margin.left;
+ const originY = 0.5 * ratio + margin.top;
+
+ ctx.save();
+
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.scale(ratio, ratio);
+
+ ctx.translate(originX, originY);
+
+ const { x, y, content, centerX, pointWidth, bgSize } = pointer;
+
+ ctx.fillStyle = hexToRGBA(bgFill, bgOpacity);
+ ctx.beginPath();
+ ctx.rect(centerX - pointWidth / 2, 0, pointWidth, height);
+ ctx.fill();
+
+ ctx.translate(x, y);
+ backgroundShapeCanvas(props, bgSize, ctx);
+ tooltipCanvas(props, content, ctx);
+
+ ctx.restore();
+}
+
+function calculateTooltipSize({ fontFamily, fontSize, fontFill }, content, ctx) {
+ if (isNotDefined(ctx)) {
+ const canvas = document.createElement("canvas");
+ ctx = canvas.getContext("2d");
+ }
+
+ ctx.font = `${fontSize}px ${fontFamily}`;
+ ctx.fillStyle = fontFill;
+ ctx.textAlign = "left";
+
+ const measureText = (str) => ({
+ width: ctx.measureText(str).width,
+ height: fontSize,
+ });
+
+ const { width, height } = content.y
+ .map(({ label, value }) => measureText(`${label}: ${value}`))
+ // Sum all y and x sizes (begin with x label size)
+ .reduce((res, size) => sumSizes(res, size), measureText(String(content.x)))
+ ;
+
+ return {
+ width: width + 2 * X,
+ height: height + 2 * Y,
+ };
+}
+
+function sumSizes(...sizes) {
+ return {
+ width: Math.max(...sizes.map((size) => size.width)),
+ height: sum(sizes, (d) => d.height),
+ };
+}
+
+function normalizeX(x, bgSize, pointWidth, width) {
+ // return x - bgSize.width - pointWidth / 2 - PADDING * 2 < 0
+ return x < width / 2
+ ? x + pointWidth / 2 + PADDING
+ : x - bgSize.width - pointWidth / 2 - PADDING;
+}
+
+function normalizeY(y, bgSize) {
+ return y - bgSize.height <= 0
+ ? y + PADDING
+ : y - bgSize.height - PADDING;
+}
+
+function origin(props, moreProps, bgSize, pointWidth) {
+ const { chartId, yAccessor } = props;
+ const { mouseXY, xAccessor, currentItem, xScale, chartConfig, width } = moreProps;
+
+ // @ts-ignore
+ let y = last(mouseXY);
+
+ const xValue = xAccessor(currentItem);
+ let x = Math.round(xScale(xValue));
+
+ if (isDefined(chartId) && isDefined(yAccessor)
+ && isDefined(chartConfig) && isDefined(chartConfig.findIndex)) {
+ const yValue = yAccessor(currentItem);
+ const chartIndex = chartConfig.findIndex(x => x.id === chartId);
+
+ y = Math.round(chartConfig[chartIndex].yScale(yValue));
+ }
+
+ x = normalizeX(x, bgSize, pointWidth, width);
+ y = normalizeY(y, bgSize);
+
+ return [x, y];
+}
+
+function helper(props, moreProps, ctx?) {
+ const { show, xScale, currentItem, plotData } = moreProps;
+ const { origin, tooltipContent } = props;
+ const { xAccessor, displayXAccessor } = moreProps;
+
+ if (!show || isNotDefined(currentItem)) { return; }
+
+ const xValue = xAccessor(currentItem);
+
+ if (!show || isNotDefined(xValue)) { return; }
+
+ const content = tooltipContent({ currentItem, xAccessor: displayXAccessor });
+ const centerX = xScale(xValue);
+ // @ts-ignore
+ const pointWidth = Math.abs(xScale(xAccessor(last(plotData))) - xScale(xAccessor(first(plotData)))) / (plotData.length - 1);
+
+ const bgSize = calculateTooltipSize(props, content, ctx);
+
+ const [x, y] = origin(props, moreProps, bgSize, pointWidth);
+
+ return { x, y, content, centerX, pointWidth, bgSize };
+}
+
+export default HoverTooltip;
diff --git a/packages/react-financial-charts/src/tooltip/MACDTooltip.tsx b/packages/react-financial-charts/src/tooltip/MACDTooltip.tsx
new file mode 100644
index 000000000..ed49013b3
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/MACDTooltip.tsx
@@ -0,0 +1,94 @@
+import { format } from "d3-format";
+import * as React from "react";
+
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor } from "../utils";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+interface MACDTooltipProps {
+ origin: number[] | any; // func
+ className?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ labelFill?: string;
+ yAccessor: any; // func
+ options: {
+ slow: number;
+ fast: number;
+ signal: number;
+ };
+ appearance: {
+ stroke: {
+ macd: string,
+ signal: string,
+ },
+ fill: {
+ divergence: string,
+ },
+ };
+ displayFormat: any; // func
+ displayValuesFor: any; // func
+ onClick?: any; // func
+}
+
+export class MACDTooltip extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip",
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 0],
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { onClick, fontFamily, fontSize, displayFormat, className } = this.props;
+ const { yAccessor, options, appearance, labelFill } = this.props;
+ const { displayValuesFor } = this.props;
+
+ const { chartConfig: { width, height } } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+ const macdValue = currentItem && yAccessor(currentItem);
+
+ const macd = (macdValue && macdValue.macd && displayFormat(macdValue.macd)) || "n/a";
+ const signal = (macdValue && macdValue.signal && displayFormat(macdValue.signal)) || "n/a";
+ const divergence = (macdValue && macdValue.divergence && displayFormat(macdValue.divergence)) || "n/a";
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ return (
+
+
+ MACD (
+ {options.slow}
+ ,
+ {options.fast}
+ ):
+ {macd}
+ Signal (
+ {options.signal}
+ ):
+ {signal}
+ Divergence:
+ {divergence}
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/MovingAverageTooltip.tsx b/packages/react-financial-charts/src/tooltip/MovingAverageTooltip.tsx
new file mode 100644
index 000000000..cdd7b3f7f
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/MovingAverageTooltip.tsx
@@ -0,0 +1,146 @@
+
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+import { functor } from "../utils";
+
+interface SingleMAToolTipProps {
+ origin: number[];
+ color: string;
+ displayName: string;
+ value: string;
+ onClick?: ((details: any, event: React.MouseEvent) => void);
+ fontFamily?: string;
+ textFill?: string;
+ labelFill?: string;
+ fontSize?: number;
+ forChart: number | string;
+ options: any;
+}
+
+export class SingleMAToolTip extends React.Component {
+
+ public render() {
+ const { textFill, labelFill } = this.props;
+ const translate = "translate(" + this.props.origin[0] + ", " + this.props.origin[1] + ")";
+ return (
+
+
+
+ {this.props.displayName}
+ {this.props.value}
+
+
+
+ );
+ }
+
+ private readonly onClick = (event: React.MouseEvent) => {
+ const { onClick, forChart, options } = this.props;
+
+ if (onClick !== undefined) {
+ onClick({ chartId: forChart, ...options }, event);
+ }
+ }
+}
+
+interface MovingAverageTooltipProps {
+ className?: string;
+ displayFormat: any; // func
+ origin: number[];
+ displayValuesFor?: any; // func
+ onClick?: ((event: React.MouseEvent) => void);
+ textFill?: string;
+ labelFill?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ width?: number;
+ options: Array<{
+ yAccessor: any; // func
+ type: string;
+ stroke: string;
+ windowSize: number;
+ echo: any;
+ }>;
+}
+
+// tslint:disable-next-line: max-classes-per-file
+export class MovingAverageTooltip extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip react-stockcharts-moving-average-tooltip",
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 10],
+ width: 65,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { displayValuesFor } = this.props;
+
+ const { chartId } = moreProps;
+ const { chartConfig } = moreProps;
+
+ const { className, onClick, width = 65, fontFamily, fontSize, textFill, labelFill } = this.props;
+ const { origin: originProp, displayFormat, options } = this.props;
+ const { chartConfig: { height } } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+ const config = chartConfig;
+
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+ const [ox, oy] = config.origin;
+
+ return (
+
+ {options
+ .map((each, idx) => {
+ const yValue = currentItem && each.yAccessor(currentItem);
+
+ const tooltipLabel = `${each.type} (${each.windowSize})`;
+ const yDisplayValue = yValue ? displayFormat(yValue) : "n/a";
+ return (
+
+ );
+ })}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/OHLCTooltip.tsx b/packages/react-financial-charts/src/tooltip/OHLCTooltip.tsx
new file mode 100644
index 000000000..a6c54057f
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/OHLCTooltip.tsx
@@ -0,0 +1,183 @@
+
+import { format } from "d3-format";
+import { timeFormat } from "d3-time-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor, isDefined } from "../utils";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+const displayTextsDefault = {
+ d: "Date: ",
+ o: " O: ",
+ h: " H: ",
+ l: " L: ",
+ c: " C: ",
+ v: " Vol: ",
+ na: "n/a",
+};
+
+const defaultDisplay = (props, _, itemsToDisplay) => {
+
+ const {
+ className,
+ textFill,
+ labelFill,
+ onClick,
+ fontFamily,
+ fontSize,
+ displayTexts,
+ } = props;
+
+ const {
+ displayDate,
+ open,
+ high,
+ low,
+ close,
+ volume,
+ x,
+ y,
+ } = itemsToDisplay;
+
+ return (
+
+
+
+ {displayTexts.d}
+
+ {displayDate}
+ {displayTexts.o}
+ {open}
+ {displayTexts.h}
+ {high}
+ {displayTexts.l}
+ {low}
+ {displayTexts.c}
+ {close}
+ {displayTexts.v}
+ {volume}
+
+
+ );
+};
+
+interface OHLCTooltipProps {
+ className?: string;
+ accessor?: any; // func
+ xDisplayFormat?: any; // func
+ children?: any; // func
+ volumeFormat?: any; // func
+ percentFormat?: any; // func
+ ohlcFormat?: any; // func
+ origin?: number[] | any; // func
+ fontFamily?: string;
+ fontSize?: number;
+ onClick?: ((event: React.MouseEvent) => void);
+ displayValuesFor?: any; // func
+ textFill?: string;
+ labelFill?: string;
+ displayTexts?: any;
+}
+
+export class OHLCTooltip extends React.Component {
+
+ public static defaultProps = {
+ accessor: (d) => {
+ return {
+ date: d.date,
+ open: d.open,
+ high: d.high,
+ low: d.low,
+ close: d.close,
+ volume: d.volume,
+ };
+ },
+ xDisplayFormat: timeFormat("%Y-%m-%d"),
+ volumeFormat: format(".4s"),
+ percentFormat: format(".2%"),
+ ohlcFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 0],
+ children: defaultDisplay,
+ displayTexts: displayTextsDefault,
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { displayValuesFor } = this.props;
+ const {
+ xDisplayFormat,
+ accessor,
+ volumeFormat,
+ ohlcFormat,
+ percentFormat,
+ displayTexts,
+ } = this.props;
+
+ const { chartConfig: { width, height } } = moreProps;
+ const { displayXAccessor } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+
+ let displayDate;
+ let open;
+ let high;
+ let low;
+ let close;
+ let volume;
+ let percent;
+ displayDate = open = high = low = close = volume = percent = displayTexts.na;
+
+ if (isDefined(currentItem) && isDefined(accessor(currentItem))) {
+ const item = accessor(currentItem);
+ volume = isDefined(item.volume) ? volumeFormat(item.volume) : displayTexts.na;
+
+ displayDate = xDisplayFormat(displayXAccessor(item));
+ open = ohlcFormat(item.open);
+ high = ohlcFormat(item.high);
+ low = ohlcFormat(item.low);
+ close = ohlcFormat(item.close);
+ percent = percentFormat((item.close - item.open) / item.open);
+ }
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ const itemsToDisplay = {
+ displayDate,
+ open,
+ high,
+ low,
+ close,
+ percent,
+ volume,
+ x,
+ y,
+ };
+ return this.props.children(this.props, moreProps, itemsToDisplay);
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/RSITooltip.tsx b/packages/react-financial-charts/src/tooltip/RSITooltip.tsx
new file mode 100644
index 000000000..884e86e93
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/RSITooltip.tsx
@@ -0,0 +1,74 @@
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor, isDefined } from "../utils";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+interface RSITooltipProps {
+ origin: number[] | any; // func
+ options: {
+ windowSize: number;
+ };
+ className?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ onClick?: ((event: React.MouseEvent) => void);
+ yAccessor: any; // func
+ displayFormat: any; // func
+ displayValuesFor?: any; // func
+ textFill?: string;
+ labelFill?: string;
+}
+
+export class RSITooltip extends React.Component {
+
+ public static defaultProps = {
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 0],
+ className: "react-stockcharts-tooltip",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { onClick, fontFamily, fontSize, yAccessor, displayFormat, className } = this.props;
+ const { options, labelFill, textFill } = this.props;
+ const { displayValuesFor } = this.props;
+
+ const { chartConfig: { width, height } } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+ const rsi = isDefined(currentItem) && yAccessor(currentItem);
+ const value = (rsi && displayFormat(rsi)) || "n/a";
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ const tooltipLabel = `RSI (${options.windowSize}): `;
+ return (
+
+
+ {tooltipLabel}
+ {value}
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/SingleValueTooltip.tsx b/packages/react-financial-charts/src/tooltip/SingleValueTooltip.tsx
new file mode 100644
index 000000000..6c668a874
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/SingleValueTooltip.tsx
@@ -0,0 +1,86 @@
+
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor, identity, isDefined, noop } from "../utils";
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+interface SingleValueTooltipProps {
+ xDisplayFormat?: any; // func
+ yDisplayFormat: any; // func
+ xLabel?: string;
+ yLabel: string;
+ labelFill?: string;
+ valueFill?: string;
+ origin?: number[] | any; // func
+ className?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ onClick?: ((event: React.MouseEvent) => void);
+ displayValuesFor?: any; // func
+ xAccessor?: any; // func
+ yAccessor?: any; // func
+}
+
+export class SingleValueTooltip extends React.Component {
+
+ public static defaultProps = {
+ origin: [0, 0],
+ labelFill: "#4682B4",
+ valueFill: "#000000",
+ yDisplayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ xAccessor: noop,
+ yAccessor: identity,
+ className: "react-stockcharts-tooltip",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+
+ const { onClick, fontFamily, fontSize, labelFill, valueFill, className } = this.props;
+ const { xDisplayFormat, yDisplayFormat, xLabel, yLabel, xAccessor, yAccessor } = this.props;
+ const { displayValuesFor } = this.props;
+
+ const { chartConfig: { width, height } } = moreProps;
+ const currentItem = displayValuesFor(this.props, moreProps);
+
+ const xDisplayValue = isDefined(currentItem) && isDefined(xAccessor(currentItem)) ? xDisplayFormat(xAccessor(currentItem)) : "n/a";
+ const yDisplayValue = isDefined(currentItem) && isDefined(yAccessor(currentItem)) ? yDisplayFormat(yAccessor(currentItem)) : "n/a";
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ return (
+
+
+ {xLabel ? {`${xLabel}: `} : null}
+ {xLabel ? {`${xDisplayValue} `} : null}
+
+ {`${yLabel}: `}
+
+
+ {yDisplayValue}
+
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/StochasticTooltip.tsx b/packages/react-financial-charts/src/tooltip/StochasticTooltip.tsx
new file mode 100644
index 000000000..763b040ec
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/StochasticTooltip.tsx
@@ -0,0 +1,87 @@
+import { format } from "d3-format";
+import * as React from "react";
+import GenericChartComponent from "../GenericChartComponent";
+import { default as defaultDisplayValuesFor } from "./displayValuesFor";
+
+import { functor } from "../utils";
+
+import { ToolTipText } from "./ToolTipText";
+import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
+
+interface StochasticTooltipProps {
+ origin: number[] | any; // func
+ className?: string;
+ fontFamily?: string;
+ fontSize?: number;
+ labelFill?: string;
+ onClick?: any; // func
+ yAccessor: any; // func
+ options: {
+ windowSize: number;
+ kWindowSize: number;
+ dWindowSize: number;
+ };
+ appearance: {
+ stroke: {
+ dLine: string;
+ kLine: string;
+ },
+ };
+ displayFormat: any; // func
+ displayValuesFor?: any; // func
+ label: string;
+}
+
+export class StochasticTooltip extends React.Component {
+
+ public static defaultProps = {
+ displayFormat: format(".2f"),
+ displayValuesFor: defaultDisplayValuesFor,
+ origin: [0, 0],
+ className: "react-stockcharts-tooltip",
+ label: "STO",
+ };
+
+ public render() {
+ return (
+
+ );
+ }
+
+ private readonly renderSVG = (moreProps) => {
+ const { onClick, fontFamily, fontSize, yAccessor, displayFormat, label } = this.props;
+ const { className, options, appearance, labelFill } = this.props;
+ const { displayValuesFor } = this.props;
+ const { chartConfig: { width, height } } = moreProps;
+
+ const currentItem = displayValuesFor(this.props, moreProps);
+ const { stroke } = appearance;
+ const stochastic = currentItem && yAccessor(currentItem);
+
+ const K = (stochastic && stochastic.K && displayFormat(stochastic.K)) || "n/a";
+ const D = (stochastic && stochastic.D && displayFormat(stochastic.D)) || "n/a";
+
+ const { origin: originProp } = this.props;
+ const origin = functor(originProp);
+ const [x, y] = origin(width, height);
+
+ return (
+
+
+ {`${label} %K(`}
+ {`${options.windowSize}, ${options.kWindowSize}`}
+ ):
+ {K}
+ %D (
+ {options.dWindowSize}
+ ):
+ {D}
+
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/ToolTipTSpanLabel.tsx b/packages/react-financial-charts/src/tooltip/ToolTipTSpanLabel.tsx
new file mode 100644
index 000000000..a31227b2e
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/ToolTipTSpanLabel.tsx
@@ -0,0 +1,24 @@
+import * as React from "react";
+
+interface ToolTipTSpanLabelProps extends React.SVGProps {
+ readonly fill: string | undefined;
+}
+
+export class ToolTipTSpanLabel extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip-label",
+ fill: "#4682B4",
+ };
+
+ public render() {
+
+ const { children, ...rest } = this.props;
+
+ return (
+
+ {children}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/ToolTipText.tsx b/packages/react-financial-charts/src/tooltip/ToolTipText.tsx
new file mode 100644
index 000000000..5699ce942
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/ToolTipText.tsx
@@ -0,0 +1,27 @@
+import * as React from "react";
+
+interface ToolTipTextProps extends React.SVGProps {
+}
+
+export class ToolTipText extends React.Component {
+
+ public static defaultProps = {
+ className: "react-stockcharts-tooltip",
+ fontFamily: "Helvetica Neue, Helvetica, Arial, sans-serif",
+ fontSize: 11,
+ };
+
+ public render() {
+
+ const { children, fontFamily, fontSize, ...rest } = this.props;
+
+ return (
+
+ {children}
+
+ );
+ }
+}
diff --git a/packages/react-financial-charts/src/tooltip/displayValuesFor.ts b/packages/react-financial-charts/src/tooltip/displayValuesFor.ts
new file mode 100644
index 000000000..c06b73689
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/displayValuesFor.ts
@@ -0,0 +1,4 @@
+export default function displayValuesFor(props, moreProps) {
+ const { currentItem } = moreProps;
+ return currentItem;
+}
diff --git a/packages/react-financial-charts/src/tooltip/index.ts b/packages/react-financial-charts/src/tooltip/index.ts
new file mode 100644
index 000000000..43291452b
--- /dev/null
+++ b/packages/react-financial-charts/src/tooltip/index.ts
@@ -0,0 +1,11 @@
+export * from "./MACDTooltip";
+export * from "./OHLCTooltip";
+export * from "./SingleValueTooltip";
+export * from "./MovingAverageTooltip";
+export * from "./BollingerBandTooltip";
+export * from "./RSITooltip";
+export * from "./StochasticTooltip";
+export { default as HoverTooltip } from "./HoverTooltip";
+export * from "./ToolTipText";
+export * from "./ToolTipTSpanLabel";
+export * from "./GroupTooltip";
diff --git a/packages/react-financial-charts/src/utils/ChartDataUtil.ts b/packages/react-financial-charts/src/utils/ChartDataUtil.ts
new file mode 100644
index 000000000..1ca4f692a
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/ChartDataUtil.ts
@@ -0,0 +1,266 @@
+
+import { extent } from "d3-array";
+import { set } from "d3-collection";
+import flattenDeep from "lodash.flattendeep";
+import * as React from "react";
+
+import { Chart } from "../Chart";
+
+import {
+ find,
+ functor,
+ getClosestItem,
+ isDefined,
+ isNotDefined,
+ isObject,
+ last,
+ mapObject,
+ shallowEqual,
+ zipper,
+} from "./index";
+
+export function getChartOrigin(origin, contextWidth, contextHeight) {
+ const originCoordinates = typeof origin === "function"
+ ? origin(contextWidth, contextHeight)
+ : origin;
+ return originCoordinates;
+}
+
+export function getDimensions({ width, height }, chartProps) {
+
+ const chartHeight = (chartProps.height || height);
+
+ return {
+ availableHeight: height,
+ width,
+ height: chartHeight,
+ };
+}
+
+function values(func) {
+ return (d) => {
+ const obj = func(d);
+ if (isObject(obj)) {
+ return mapObject(obj);
+ }
+ return obj;
+ };
+}
+
+function isArraySize2AndNumber(yExtentsProp) {
+ if (Array.isArray(yExtentsProp) && yExtentsProp.length === 2) {
+ const [a, b] = yExtentsProp;
+ return (typeof a === "number" && typeof b === "number");
+ }
+ return false;
+}
+
+export function getNewChartConfig(innerDimension, children, existingChartConfig = []) {
+ return React.Children.map(children, (each) => {
+ if (each && each.type.toString() === Chart.toString()) {
+ const chartProps = {
+ ...Chart.defaultProps,
+ ...each.props,
+ };
+ const {
+ id,
+ origin,
+ padding,
+ yExtents: yExtentsProp,
+ yScale: yScaleProp,
+ flipYScale,
+ yExtentsCalculator,
+ } = chartProps;
+
+ const yScale = yScaleProp.copy();
+ const {
+ width, height, availableHeight,
+ } = getDimensions(innerDimension, chartProps);
+
+ const { yPan } = chartProps;
+ let { yPanEnabled } = chartProps;
+ const yExtents = isDefined(yExtentsProp)
+ ? (Array.isArray(yExtentsProp) ? yExtentsProp : [yExtentsProp]).map(functor)
+ : undefined;
+
+ const prevChartConfig = find(existingChartConfig, (d) => d.id === id);
+
+ if (isArraySize2AndNumber(yExtentsProp)) {
+ if (
+ isDefined(prevChartConfig)
+ && prevChartConfig.yPan
+ && prevChartConfig.yPanEnabled
+ && yPan
+ && yPanEnabled
+ && shallowEqual(prevChartConfig.originalYExtentsProp, yExtentsProp)
+ ) {
+ // console.log(prevChartConfig.originalYExtentsProp, yExtentsProp)
+ // console.log(prevChartConfig.yScale.domain())
+ yScale.domain(prevChartConfig.yScale.domain());
+ } else {
+ const [a, b] = yExtentsProp;
+ yScale.domain([a, b]);
+ }
+ } else if (isDefined(prevChartConfig) && prevChartConfig.yPanEnabled) {
+ if (isArraySize2AndNumber(prevChartConfig.originalYExtentsProp)) {
+ // do nothing
+ } else {
+ yScale.domain(prevChartConfig.yScale.domain());
+ yPanEnabled = true;
+ }
+ }
+
+ return {
+ id,
+ origin: functor(origin)(width, availableHeight),
+ padding,
+ originalYExtentsProp: yExtentsProp,
+ yExtents,
+ yExtentsCalculator,
+ flipYScale,
+ // yScale: setRange(yScale.copy(), height, padding, flipYScale),
+ yScale,
+ yPan,
+ yPanEnabled,
+ // mouseCoordinates,
+ width,
+ height,
+ };
+ }
+ return undefined;
+ }).filter((each) => isDefined(each));
+}
+export function getCurrentCharts(chartConfig, mouseXY) {
+ const currentCharts = chartConfig.filter((eachConfig) => {
+ const top = eachConfig.origin[1];
+ const bottom = top + eachConfig.height;
+ return (mouseXY[1] > top && mouseXY[1] < bottom);
+ }).map((config) => config.id);
+
+ return currentCharts;
+}
+
+function setRange(scale, height, padding, flipYScale) {
+ if (scale.rangeRoundPoints || isNotDefined(scale.invert)) {
+ if (isNaN(padding)) { throw new Error("padding has to be a number for ordinal scale"); }
+ if (scale.rangeRoundPoints) { scale.rangeRoundPoints(flipYScale ? [0, height] : [height, 0], padding); }
+ if (scale.rangeRound) { scale.range(flipYScale ? [0, height] : [height, 0]).padding(padding); }
+ } else {
+ const { top, bottom } = isNaN(padding)
+ ? padding
+ : { top: padding, bottom: padding };
+
+ scale.range(flipYScale ? [top, height - bottom] : [height - bottom, top]);
+ }
+ return scale;
+}
+
+function yDomainFromYExtents(yExtents, yScale, plotData) {
+ const yValues = yExtents.map((eachExtent) =>
+ plotData.map(values(eachExtent)));
+
+ const allYValues = flattenDeep(yValues);
+ // console.log(allYValues)
+ const realYDomain = (yScale.invert)
+ ? extent(allYValues)
+ : set(allYValues).values();
+
+ return realYDomain;
+}
+
+export function getChartConfigWithUpdatedYScales(
+ chartConfig,
+ { plotData, xAccessor, displayXAccessor, fullData },
+ xDomain,
+ dy,
+ chartsToPan,
+) {
+ const yDomains = chartConfig
+ .map(({ yExtentsCalculator, yExtents, yScale }) => {
+
+ const realYDomain = isDefined(yExtentsCalculator)
+ ? yExtentsCalculator({ plotData, xDomain, xAccessor, displayXAccessor, fullData })
+ : yDomainFromYExtents(yExtents, yScale, plotData);
+
+ // console.log("yScale.domain() ->", yScale.domain())
+
+ const yDomainDY = isDefined(dy)
+ ? yScale.range().map((each) => each - dy).map(yScale.invert)
+ : yScale.domain();
+ return {
+ realYDomain,
+ yDomainDY,
+ prevYDomain: yScale.domain(),
+ };
+ });
+
+ const combine = zipper()
+ .combine((config, { realYDomain, yDomainDY, prevYDomain }) => {
+ const { id, padding, height, yScale, yPan, flipYScale, yPanEnabled = false } = config;
+
+ const another = isDefined(chartsToPan)
+ ? chartsToPan.indexOf(id) > -1
+ : true;
+ const domain = yPan && yPanEnabled
+ ? another ? yDomainDY : prevYDomain
+ : realYDomain;
+
+ // console.log(id, yPan, yPanEnabled, another);
+ // console.log(domain, realYDomain, prevYDomain);
+ const newYScale = setRange(
+ yScale.copy().domain(domain), height, padding, flipYScale,
+ );
+ return {
+ ...config,
+ yScale: newYScale,
+ realYDomain,
+ };
+ // return { ...config, yScale: yScale.copy().domain(domain).range([height - padding, padding]) };
+ });
+
+ // @ts-ignore
+ const updatedChartConfig = combine(chartConfig, yDomains);
+ // console.error(yDomains, dy, chartsToPan, updatedChartConfig.map(d => d.yScale.domain()));
+ // console.log(updatedChartConfig.map(d => ({ id: d.id, domain: d.yScale.domain() })))
+
+ return updatedChartConfig;
+}
+
+export function getCurrentItem(xScale, xAccessor, mouseXY, plotData) {
+ let xValue;
+ let item;
+ if (xScale.invert) {
+ xValue = xScale.invert(mouseXY[0]);
+ item = getClosestItem(plotData, xValue, xAccessor);
+ } else {
+ const dr = xScale
+ .range()
+ .map((d, idx) => ({ x: Math.abs(d - mouseXY[0]), idx }))
+ .reduce((a, b) => a.x < b.x ? a : b);
+
+ item = isDefined(dr) ? plotData[dr.idx] : plotData[0];
+ }
+ return item;
+}
+
+export function getXValue(xScale, xAccessor, mouseXY, plotData) {
+
+ let xValue;
+ let item;
+ if (xScale.invert) {
+ xValue = xScale.invert(mouseXY[0]);
+ if (xValue > xAccessor(last(plotData)) && xScale.value) {
+ return Math.round(xValue);
+ } else {
+ item = getClosestItem(plotData, xValue, xAccessor);
+ }
+ } else {
+ const dr = xScale
+ .range()
+ .map((d, idx) => ({ x: Math.abs(d - mouseXY[0]), idx }))
+ .reduce((a, b) => a.x < b.x ? a : b);
+
+ item = isDefined(dr) ? plotData[dr.idx] : plotData[0];
+ }
+ return xAccessor(item);
+}
diff --git a/packages/react-financial-charts/src/utils/PureComponent.tsx b/packages/react-financial-charts/src/utils/PureComponent.tsx
new file mode 100644
index 000000000..65546f1de
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/PureComponent.tsx
@@ -0,0 +1,10 @@
+import * as React from "react";
+import shallowEqual from "./shallowEqual";
+
+export class PureComponent extends React.Component {
+ public shouldComponentUpdate(nextProps, nextState, nextContext) {
+ return !shallowEqual(this.props, nextProps)
+ || !shallowEqual(this.state, nextState)
+ || !shallowEqual(this.context, nextContext);
+ }
+}
diff --git a/packages/react-financial-charts/src/utils/accumulatingWindow.ts b/packages/react-financial-charts/src/utils/accumulatingWindow.ts
new file mode 100644
index 000000000..a618f66ad
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/accumulatingWindow.ts
@@ -0,0 +1,104 @@
+/*
+
+Taken from https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/slidingWindow.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+import identity from "./identity";
+import { functor } from "./index";
+import noop from "./noop";
+
+export default function () {
+
+ let accumulateTill = functor(false);
+ let accumulator = noop;
+ let value = identity;
+ let discardTillStart = false;
+ let discardTillEnd = false;
+
+ const accumulatingWindow = function (data) {
+ let accumulatedWindow: any[] | undefined = discardTillStart ? undefined : [];
+ const response: any[] = [];
+ let accumulatorIdx = 0;
+ let i = 0;
+ for (i = 0; i < data.length; i++) {
+ const d = data[i];
+ if (accumulateTill(d, i, (accumulatedWindow || []))) {
+ if (accumulatedWindow && accumulatedWindow.length > 0) {
+ // @ts-ignore
+ response.push(accumulator(accumulatedWindow, i, accumulatorIdx++));
+ }
+
+ accumulatedWindow = [value(d)];
+ } else if (accumulatedWindow) {
+ accumulatedWindow.push(value(d));
+ }
+ }
+
+ if (!discardTillEnd) {
+ // @ts-ignore
+ response.push(accumulator(accumulatedWindow, i, accumulatorIdx));
+ }
+
+ return response;
+ };
+
+ accumulatingWindow.accumulateTill = function (x) {
+ if (!arguments.length) {
+ return accumulateTill;
+ }
+ accumulateTill = functor(x);
+ return accumulatingWindow;
+ };
+ accumulatingWindow.accumulator = function (x) {
+ if (!arguments.length) {
+ return accumulator;
+ }
+ accumulator = x;
+ return accumulatingWindow;
+ };
+ accumulatingWindow.value = function (x) {
+ if (!arguments.length) {
+ return value;
+ }
+ value = x;
+ return accumulatingWindow;
+ };
+ accumulatingWindow.discardTillStart = function (x) {
+ if (!arguments.length) {
+ return discardTillStart;
+ }
+ discardTillStart = x;
+ return accumulatingWindow;
+ };
+ accumulatingWindow.discardTillEnd = function (x) {
+ if (!arguments.length) {
+ return discardTillEnd;
+ }
+ discardTillEnd = x;
+ return accumulatingWindow;
+ };
+ return accumulatingWindow;
+}
diff --git a/packages/react-financial-charts/src/utils/barWidth.ts b/packages/react-financial-charts/src/utils/barWidth.ts
new file mode 100644
index 000000000..d6879bd40
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/barWidth.ts
@@ -0,0 +1,40 @@
+import { head } from ".";
+
+/**
+ * Bar width is based on the amount of items in the plot data and the distance between the first and last of those
+ * items.
+ * @param props the props passed to the series.
+ * @param moreProps an object holding the xScale, xAccessor and plotData.
+ * @return {number} the bar width.
+ */
+export const plotDataLengthBarWidth = (props: { widthRatio: number }, moreProps: { xScale: any; }): number => {
+ const { widthRatio } = props;
+ const { xScale } = moreProps;
+
+ const [l, r] = xScale.range();
+
+ const totalWidth = Math.abs(r - l);
+ if (xScale.invert != null) {
+ const [dl, dr] = xScale.domain();
+ const width = totalWidth / Math.abs(dl - dr);
+ return width * widthRatio;
+ } else {
+ const width = totalWidth / xScale.domain().length;
+ return width * widthRatio;
+ }
+};
+
+/**
+ * Generates a width function that calculates the bar width based on the given time interval.
+ * @param interval a d3-time time interval.
+ * @return {Function} the width function.
+ */
+export const timeIntervalBarWidth = (interval) => {
+ return function (props: { widthRatio: number }, moreProps: { xScale: any; xAccessor: any; plotData: any }) {
+ const { widthRatio } = props;
+ const { xScale, xAccessor, plotData } = moreProps;
+
+ const first = xAccessor(head(plotData));
+ return Math.abs(xScale(interval.offset(first, 1)) - xScale(first)) * widthRatio;
+ };
+};
diff --git a/packages/react-financial-charts/src/utils/identity.ts b/packages/react-financial-charts/src/utils/identity.ts
new file mode 100644
index 000000000..d9aabe12a
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/identity.ts
@@ -0,0 +1 @@
+export default (d) => d;
diff --git a/packages/react-financial-charts/src/utils/index.ts b/packages/react-financial-charts/src/utils/index.ts
new file mode 100644
index 000000000..0e8db023f
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/index.ts
@@ -0,0 +1,311 @@
+import { bisector } from "d3-array";
+import { scaleOrdinal, schemeCategory10 } from "d3-scale";
+import identity from "./identity";
+import noop from "./noop";
+
+export { default as rebind } from "./rebind";
+export { default as zipper } from "./zipper";
+export { default as merge } from "./merge";
+export { default as slidingWindow } from "./slidingWindow";
+export { default as identity } from "./identity";
+export { default as noop } from "./noop";
+export { default as shallowEqual } from "./shallowEqual";
+export { default as mappedSlidingWindow } from "./mappedSlidingWindow";
+export { default as accumulatingWindow } from "./accumulatingWindow";
+
+export * from "./barWidth";
+export * from "./strokeDasharray";
+
+export function getLogger(prefix) {
+ let logger = noop;
+ if (process.env.NODE_ENV !== "production") {
+ logger = require("debug")("react-financial-charts:" + prefix);
+ }
+ return logger;
+}
+
+export function sign(x) {
+ // @ts-ignore
+ return (x > 0) - (x < 0);
+}
+
+export const yes = () => true;
+
+export function path(loc = []) {
+ const key = Array.isArray(loc) ? loc : [loc];
+ const length = key.length;
+
+ return function (obj, defaultValue?) {
+ if (length === 0) { return isDefined(obj) ? obj : defaultValue; }
+
+ let index = 0;
+ while (obj != null && index < length) {
+ obj = obj[key[index++]];
+ }
+ return (index === length) ? obj : defaultValue;
+ };
+}
+
+export function functor(v) {
+ return typeof v === "function" ? v : () => v;
+}
+
+export function createVerticalLinearGradient(stops) {
+ return function (moreProps, ctx) {
+ const { chartConfig: { height } } = moreProps;
+
+ const grd = ctx.createLinearGradient(0, height, 0, 0);
+ stops.forEach((each) => {
+ grd.addColorStop(each.stop, each.color);
+ });
+
+ return grd;
+ };
+}
+
+export function getClosestItemIndexes2(array, value, accessor) {
+ let left = bisector(accessor).left(array, value);
+ left = Math.max(left - 1, 0);
+ let right = Math.min(left + 1, array.length - 1);
+
+ const item = accessor(array[left]);
+ if (item >= value && item <= value) { right = left; }
+
+ return { left, right };
+}
+
+export function getClosestValue(inputValue, currentValue) {
+ const values = isArray(inputValue) ? inputValue : [inputValue];
+
+ const diff = values
+ .map((each) => each - currentValue)
+ .reduce((diff1, diff2) => Math.abs(diff1) < Math.abs(diff2) ? diff1 : diff2);
+ return currentValue + diff;
+}
+
+// @ts-ignore
+export function find(list, predicate, context = this) {
+ for (let i = 0; i < list.length; ++i) {
+ if (predicate.call(context, list[i], i, list)) {
+ return list[i];
+ }
+ }
+ return undefined;
+}
+
+export function d3Window(node) {
+ const d3win = node
+ && (node.ownerDocument && node.ownerDocument.defaultView
+ || node.document && node
+ || node.defaultView);
+ return d3win;
+}
+
+export const MOUSEENTER = "mouseenter.interaction";
+export const MOUSELEAVE = "mouseleave.interaction";
+export const MOUSEMOVE = "mousemove.pan";
+export const MOUSEUP = "mouseup.pan";
+export const TOUCHMOVE = "touchmove.pan";
+export const TOUCHEND = "touchend.pan touchcancel.pan";
+
+export function getTouchProps(touch) {
+ if (!touch) { return {}; }
+ return {
+ pageX: touch.pageX,
+ pageY: touch.pageY,
+ clientX: touch.clientX,
+ clientY: touch.clientY,
+ };
+}
+
+export function getClosestItemIndexes(array, value, accessor) {
+ let lo = 0;
+ let hi = array.length - 1;
+ while (hi - lo > 1) {
+ const mid = Math.round((lo + hi) / 2);
+ if (accessor(array[mid]) <= value) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ // for Date object === does not work, so using the <= in combination with >=
+ // the same code works for both dates and numbers
+ if (accessor(array[lo]).valueOf() === value.valueOf()) { hi = lo; }
+ if (accessor(array[hi]).valueOf() === value.valueOf()) { lo = hi; }
+
+ if (accessor(array[lo]) < value && accessor(array[hi]) < value) { lo = hi; }
+ if (accessor(array[lo]) > value && accessor(array[hi]) > value) { hi = lo; }
+
+ return { left: lo, right: hi };
+}
+
+export function getClosestItem(array, value, accessor) {
+ const { left, right } = getClosestItemIndexes(array, value, accessor);
+
+ if (left === right) {
+ return array[left];
+ }
+
+ const closest = (Math.abs(accessor(array[left]) - value) < Math.abs(accessor(array[right]) - value))
+ ? array[left]
+ : array[right];
+
+ return closest;
+}
+
+export const overlayColors = scaleOrdinal(schemeCategory10);
+
+export function head(array, accessor?) {
+ if (accessor && array) {
+ let value;
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < array.length; i++) {
+ value = array[i];
+ if (isDefined(accessor(value))) {
+ return value;
+ }
+ }
+ return undefined;
+ }
+ return array ? array[0] : undefined;
+}
+
+export function tail(array, accessor) {
+ if (accessor && array) {
+ return array.map(accessor).slice(1);
+ }
+ return array ? array.slice(1) : undefined;
+}
+
+export const first = head;
+
+export function last(array, accessor?) {
+ if (accessor && array) {
+ let value;
+ for (let i = array.length - 1; i >= 0; i--) {
+ value = array[i];
+ if (isDefined(accessor(value))) { return value; }
+ }
+ return undefined;
+ }
+ const length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+}
+
+export const isDefined = (d: T) => {
+ return d !== null && d !== undefined;
+};
+
+export function isNotDefined(d) {
+ return !isDefined(d);
+}
+
+export function isObject(d) {
+ return isDefined(d) && typeof d === "object" && !Array.isArray(d);
+}
+
+export const isArray = Array.isArray;
+
+export function touchPosition(touch, e) {
+ const container = e.target;
+ const rect = container.getBoundingClientRect();
+ const x = touch.clientX - rect.left - container.clientLeft;
+ const y = touch.clientY - rect.top - container.clientTop;
+ const xy = [Math.round(x), Math.round(y)];
+ return xy;
+}
+
+export function mousePosition(e: React.MouseEvent, defaultRect?) {
+ const container = e.currentTarget;
+ const rect = defaultRect || container.getBoundingClientRect();
+ const x = e.clientX - rect.left - container.clientLeft;
+ const y = e.clientY - rect.top - container.clientTop;
+ const xy = [Math.round(x), Math.round(y)];
+ return xy;
+}
+
+export function clearCanvas(canvasList, ratio) {
+ canvasList.forEach((each) => {
+ each.setTransform(1, 0, 0, 1, 0, 0);
+ each.clearRect(-1, -1, each.canvas.width + 2, each.canvas.height + 2);
+ each.scale(ratio, ratio);
+ });
+}
+
+export function capitalizeFirst(str) {
+ return str.charAt(0).toUpperCase() + str.substring(1);
+}
+
+export function hexToRGBA(inputHex, opacity) {
+ const hex = inputHex.replace("#", "");
+ if (inputHex.indexOf("#") > -1 && (hex.length === 3 || hex.length === 6)) {
+
+ const multiplier = (hex.length === 3) ? 1 : 2;
+
+ const r = parseInt(hex.substring(0, 1 * multiplier), 16);
+ const g = parseInt(hex.substring(1 * multiplier, 2 * multiplier), 16);
+ const b = parseInt(hex.substring(2 * multiplier, 3 * multiplier), 16);
+
+ const result = `rgba(${r}, ${g}, ${b}, ${opacity})`;
+
+ return result;
+ }
+ return inputHex;
+}
+
+export function toObject(array, iteratee = identity) {
+ return array.reduce((returnObj, a) => {
+ const [key, value] = iteratee(a);
+ return {
+ ...returnObj,
+ [key]: value,
+ };
+ }, {});
+}
+
+// copied from https://github.com/lodash/lodash/blob/master/mapValue.js
+export function mapValue(object, iteratee) {
+ object = Object(object);
+ // eslint-disable-next-line prefer-const
+ const result = {};
+
+ Object.keys(object).forEach((key) => {
+ const mappedValue = iteratee(object[key], key, object);
+
+ if (isDefined(mappedValue)) {
+ result[key] = mappedValue;
+ }
+ });
+ return result;
+}
+
+// copied from https://github.com/lodash/lodash/blob/master/mapObject.js
+export function mapObject(object = {}, iteratee = identity) {
+ const props = Object.keys(object);
+
+ // eslint-disable-next-line prefer-const
+ const result = new Array(props.length);
+
+ props.forEach((key, index) => {
+ // @ts-ignore
+ result[index] = iteratee(object[key], key, object);
+ });
+ return result;
+}
+
+export function replaceAtIndex(array, index, value) {
+ if (isDefined(array) && array.length > index) {
+ return array.slice(0, index)
+ .concat(value)
+ .concat(array.slice(index + 1));
+ }
+ return array;
+}
+
+// copied from https://github.com/lodash/lodash/blob/master/forOwn.js
+export function forOwn(obj, iteratee) {
+ const object = Object(obj);
+ Object.keys(object)
+ .forEach((key) => iteratee(object[key], key, object));
+}
diff --git a/packages/react-financial-charts/src/utils/mappedSlidingWindow.ts b/packages/react-financial-charts/src/utils/mappedSlidingWindow.ts
new file mode 100644
index 000000000..2438baf9e
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/mappedSlidingWindow.ts
@@ -0,0 +1,82 @@
+
+import identity from "./identity";
+import { functor } from "./index";
+import noop from "./noop";
+
+export default function () {
+
+ let undefinedValue;
+ let windowSize = 10;
+ let accumulator = noop;
+ let source = identity;
+ let skipInitial = 0;
+
+ const mappedSlidingWindow = function (data) {
+ // @ts-ignore
+ const size = functor(windowSize).apply(this, arguments);
+ const windowData: any[] = [];
+ let accumulatorIdx = 0;
+ const undef = functor(undefinedValue);
+ const result: any[] = [];
+ data.forEach(function (d, i) {
+ let mapped;
+ if (i < (skipInitial + size - 1)) {
+ mapped = undef(d, i);
+ result.push(mapped);
+ windowData.push(mapped);
+ return;
+ }
+ if (i >= (skipInitial + size)) {
+ windowData.shift();
+ }
+ // @ts-ignore
+ windowData.push(source(d, i));
+
+ // @ts-ignore
+ mapped = accumulator(windowData, i, accumulatorIdx++);
+ result.push(mapped);
+ windowData.pop();
+ windowData.push(mapped);
+ return;
+ });
+ return result;
+ };
+
+ mappedSlidingWindow.undefinedValue = function (x) {
+ if (!arguments.length) {
+ return undefinedValue;
+ }
+ undefinedValue = x;
+ return mappedSlidingWindow;
+ };
+ mappedSlidingWindow.windowSize = function (x) {
+ if (!arguments.length) {
+ return windowSize;
+ }
+ windowSize = x;
+ return mappedSlidingWindow;
+ };
+ mappedSlidingWindow.accumulator = function (x) {
+ if (!arguments.length) {
+ return accumulator;
+ }
+ accumulator = x;
+ return mappedSlidingWindow;
+ };
+ mappedSlidingWindow.skipInitial = function (x) {
+ if (!arguments.length) {
+ return skipInitial;
+ }
+ skipInitial = x;
+ return mappedSlidingWindow;
+ };
+ mappedSlidingWindow.source = function (x) {
+ if (!arguments.length) {
+ return source;
+ }
+ source = x;
+ return mappedSlidingWindow;
+ };
+
+ return mappedSlidingWindow;
+}
diff --git a/packages/react-financial-charts/src/utils/merge.ts b/packages/react-financial-charts/src/utils/merge.ts
new file mode 100644
index 000000000..ceea13a84
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/merge.ts
@@ -0,0 +1,79 @@
+/*
+https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/merge.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+import identity from "./identity";
+import noop from "./noop";
+import zipper from "./zipper";
+
+import { isNotDefined } from "./index";
+
+// applies an algorithm to an array, merging the result back into
+// the source array using the given merge function.
+export default function () {
+
+ let algorithm = identity;
+ let skipUndefined = true;
+ let merge = noop;
+
+ function mergeCompute(data) {
+ const zip = zipper()
+ .combine((datum, indicator) => {
+ const result = (skipUndefined && isNotDefined(indicator))
+ ? datum
+ // @ts-ignore
+ : merge(datum, indicator);
+ return isNotDefined(result) ? datum : result;
+ });
+
+ // @ts-ignore
+ return zip(data, algorithm(data));
+ }
+
+ mergeCompute.algorithm = function (x) {
+ if (!arguments.length) {
+ return algorithm;
+ }
+ algorithm = x;
+ return mergeCompute;
+ };
+
+ mergeCompute.merge = function (x) {
+ if (!arguments.length) {
+ return merge;
+ }
+ merge = x;
+ return mergeCompute;
+ };
+ mergeCompute.skipUndefined = function (x) {
+ if (!arguments.length) {
+ return skipUndefined;
+ }
+ skipUndefined = x;
+ return mergeCompute;
+ };
+
+ return mergeCompute;
+}
diff --git a/packages/react-financial-charts/src/utils/noop.ts b/packages/react-financial-charts/src/utils/noop.ts
new file mode 100644
index 000000000..c39d398e9
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/noop.ts
@@ -0,0 +1,2 @@
+// tslint:disable-next-line: no-empty
+export default () => { };
diff --git a/packages/react-financial-charts/src/utils/rebind.ts b/packages/react-financial-charts/src/utils/rebind.ts
new file mode 100644
index 000000000..8f9cacbb3
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/rebind.ts
@@ -0,0 +1,19 @@
+// copied from https://github.com/d3fc/d3fc-rebind/blob/master/src/rebind.js
+
+function createReboundMethod(target, source, name) {
+ const method = source[name];
+ if (typeof method !== "function") {
+ throw new Error(`Attempt to rebind ${name} which isn't a function on the source object`);
+ }
+ return (...args) => {
+ const value = method.apply(source, args);
+ return value === source ? target : value;
+ };
+}
+
+export default function rebind(target, source, ...names) {
+ for (const name of names) {
+ target[name] = createReboundMethod(target, source, name);
+ }
+ return target;
+}
diff --git a/packages/react-financial-charts/src/utils/shallowEqual.ts b/packages/react-financial-charts/src/utils/shallowEqual.ts
new file mode 100644
index 000000000..871490324
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/shallowEqual.ts
@@ -0,0 +1,58 @@
+// https://github.com/jonschlinkert/is-equal-shallow/
+
+/*
+The MIT License (MIT)
+
+Copyright (c) 2015, Jon Schlinkert.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+function isDate(date) {
+ return Object.prototype.toString.call(date) === "[object Date]";
+}
+
+function isEqual(val1, val2) {
+ return (isDate(val1) && isDate(val2))
+ ? val1.getTime() === val2.getTime()
+ : val1 === val2;
+}
+
+export default function shallowEqual(a, b) {
+ if (!a && !b) { return true; }
+ if (!a && b || a && !b) { return false; }
+
+ let numKeysA = 0;
+ let numKeysB = 0;
+ let key;
+
+ // tslint:disable: forin
+ for (key in b) {
+ numKeysB++;
+ if ((b.hasOwnProperty(key) && !a.hasOwnProperty(key)) || !isEqual(a[key], b[key])) {
+ return false;
+ }
+ }
+
+ for (key in a) {
+ numKeysA++;
+ }
+
+ return numKeysA === numKeysB;
+}
diff --git a/packages/react-financial-charts/src/utils/slidingWindow.ts b/packages/react-financial-charts/src/utils/slidingWindow.ts
new file mode 100644
index 000000000..17d323336
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/slidingWindow.ts
@@ -0,0 +1,117 @@
+/*
+
+Taken from https://github.com/ScottLogic/d3fc/blob/master/src/indicator/algorithm/calculator/slidingWindow.js
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Scott Logic Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+import { functor, path } from "./index";
+import noop from "./noop";
+
+export default function () {
+
+ let undefinedValue;
+ let windowSize = 10;
+ let accumulator = noop;
+ let sourcePath;
+ let source;
+ let skipInitial = 0;
+ let misc;
+
+ const slidingWindow = function (data) {
+ const sourceFunction = source || path(sourcePath);
+
+ // @ts-ignore
+ const size = functor(windowSize).apply(this, arguments);
+ const windowData = data.slice(skipInitial, size + skipInitial).map(sourceFunction);
+ let accumulatorIdx = 0;
+ const undef = functor(undefinedValue);
+ return data.map(function (d, i) {
+ // console.log(d, i);
+ if (i < (skipInitial + size - 1)) {
+ return undef(sourceFunction(d), i, misc);
+ }
+ if (i >= (skipInitial + size)) {
+ // Treat windowData as FIFO rolling buffer
+ windowData.shift();
+ windowData.push(sourceFunction(d, i));
+ }
+
+ // @ts-ignore
+ return accumulator(windowData, i, accumulatorIdx++, misc);
+ });
+ };
+
+ slidingWindow.undefinedValue = function (...args) {
+ if (!args.length) {
+ return undefinedValue;
+ }
+ undefinedValue = args;
+ return slidingWindow;
+ };
+ slidingWindow.windowSize = function (x) {
+ if (!arguments.length) {
+ return windowSize;
+ }
+ windowSize = x;
+ return slidingWindow;
+ };
+ slidingWindow.misc = function (x) {
+ if (!arguments.length) {
+ return misc;
+ }
+ misc = x;
+ return slidingWindow;
+ };
+ slidingWindow.accumulator = function (x) {
+ if (!arguments.length) {
+ return accumulator;
+ }
+ accumulator = x;
+ return slidingWindow;
+ };
+ slidingWindow.skipInitial = function (x) {
+ if (!arguments.length) {
+ return skipInitial;
+ }
+ skipInitial = x;
+ return slidingWindow;
+ };
+ slidingWindow.sourcePath = function (x) {
+ if (!arguments.length) {
+ return sourcePath;
+ }
+ sourcePath = x;
+ return slidingWindow;
+ };
+ slidingWindow.source = function (x) {
+ if (!arguments.length) {
+ return source;
+ }
+ source = x;
+ return slidingWindow;
+ };
+
+ return slidingWindow;
+}
diff --git a/packages/react-financial-charts/src/utils/strokeDasharray.ts b/packages/react-financial-charts/src/utils/strokeDasharray.ts
new file mode 100644
index 000000000..e770a6d7f
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/strokeDasharray.ts
@@ -0,0 +1,51 @@
+export type strokeDashTypes =
+ "Solid" |
+ "ShortDash" |
+ "ShortDash2" |
+ "ShortDot" |
+ "ShortDashDot" |
+ "ShortDashDotDot" |
+ "Dot" |
+ "Dash" |
+ "LongDash" |
+ "DashDot" |
+ "LongDashDot" |
+ "LongDashDotDot";
+
+export function getStrokeDasharrayCanvas(type) {
+ const a = getStrokeDasharray(type).split(",");
+
+ if (a.length === 1) { return []; }
+
+ return a.map((d) => Number(d));
+
+}
+export const getStrokeDasharray = (type) => {
+ switch (type) {
+ default:
+ case "Solid":
+ return "none";
+ case "ShortDash":
+ return "6, 2";
+ case "ShortDash2":
+ return "6, 3";
+ case "ShortDot":
+ return "2, 2";
+ case "ShortDashDot":
+ return "6, 2, 2, 2";
+ case "ShortDashDotDot":
+ return "6, 2, 2, 2, 2, 2";
+ case "Dot":
+ return "2, 6";
+ case "Dash":
+ return "8, 6";
+ case "LongDash":
+ return "16, 6";
+ case "DashDot":
+ return "8, 6, 2, 6";
+ case "LongDashDot":
+ return "16, 6, 2, 6";
+ case "LongDashDotDot":
+ return "16, 6, 2, 6, 2, 6";
+ }
+};
diff --git a/packages/react-financial-charts/src/utils/zipper.ts b/packages/react-financial-charts/src/utils/zipper.ts
new file mode 100644
index 000000000..8d1d7e569
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/zipper.ts
@@ -0,0 +1,39 @@
+/* an extension to d3.zip so we call a function instead of an array */
+
+import { min } from "d3-array";
+
+import identity from "./identity";
+
+export default function zipper() {
+ let combine = identity;
+
+ function zip() {
+ const n = arguments.length;
+ if (!n) { return []; }
+ const m = min(arguments, d3_zipLength);
+
+ let i;
+ const zips = new Array(m);
+ for (i = -1; ++i < m;) {
+ // tslint:disable-next-line: no-shadowed-variable
+ for (let j = -1, zip = zips[i] = new Array(n); ++j < n;) {
+ zip[j] = arguments[j][i];
+ }
+
+ // @ts-ignore
+ zips[i] = combine.apply(this, zips[i]);
+ }
+ return zips;
+ }
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ zip.combine = function (x) {
+ if (!arguments.length) {
+ return combine;
+ }
+ combine = x;
+ return zip;
+ };
+ return zip;
+}
diff --git a/packages/react-financial-charts/src/utils/zoomBehavior.ts b/packages/react-financial-charts/src/utils/zoomBehavior.ts
new file mode 100644
index 000000000..6ec77a5f1
--- /dev/null
+++ b/packages/react-financial-charts/src/utils/zoomBehavior.ts
@@ -0,0 +1,40 @@
+import {
+ getCurrentItem,
+} from "./ChartDataUtil";
+
+import {
+ last,
+} from "./index";
+
+export function mouseBasedZoomAnchor({
+ xScale,
+ xAccessor,
+ mouseXY,
+ plotData,
+ fullData,
+}) {
+ const currentItem = getCurrentItem(xScale, xAccessor, mouseXY, plotData);
+ return xAccessor(currentItem);
+}
+
+export function lastVisibleItemBasedZoomAnchor({
+ xScale,
+ xAccessor,
+ mouseXY,
+ plotData,
+ fullData,
+}) {
+ const lastItem = last(plotData);
+ return xAccessor(lastItem);
+}
+
+export function rightDomainBasedZoomAnchor({
+ xScale,
+ xAccessor,
+ mouseXY,
+ plotData,
+ fullData,
+}) {
+ const [, end] = xScale.domain();
+ return end;
+}
diff --git a/packages/react-financial-charts/tsconfig.json b/packages/react-financial-charts/tsconfig.json
new file mode 100644
index 000000000..ba5a25607
--- /dev/null
+++ b/packages/react-financial-charts/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "declaration": true,
+ "experimentalDecorators": true,
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "noImplicitAny": false,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "outDir": "lib",
+ "removeComments": true,
+ "sourceMap": true,
+ "strict": true,
+ "target": "es2017"
+ },
+ "include": [
+ "src"
+ ],
+ "exclude": [
+ "lib",
+ "**/__tests__/**"
+ ]
+}
diff --git a/packages/react-financial-charts/tslint.yaml b/packages/react-financial-charts/tslint.yaml
new file mode 100644
index 000000000..7325d2a01
--- /dev/null
+++ b/packages/react-financial-charts/tslint.yaml
@@ -0,0 +1,10 @@
+---
+extends: "tslint:recommended"
+rules:
+ completed-docs: false
+ interface-name: false
+ object-literal-sort-keys: false
+ only-arrow-functions: false
+ space-before-function-paren: false
+ max-line-length:
+ options: [140]