[
  {
    "path": ".dockerignore",
    "content": "node_modules\n.travis.yml\nvolumes\nconfig.js\nsample-config.js\n.git\n.gitignore"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "**Note: this is the technical bug tracker, please use other platforms for getting support and starting a (non technical) discussion. See the [getting help page](https://gekko.wizb.it/docs/introduction/getting-help.html) for details.**\n\n**I'm submitting a ...**\n[ ] bug report\n[ ] question about the decisions made in the repository\n\n**Action taken** (what you did)\n\n\n**Expected result** (what you hoped would happen)\n\n\n**Actual result** (unexpected outcome)\n\n\n**Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, etc)\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)\n\n\n\n* **What is the current behavior?** (You can also link to an open issue here)\n\n\n\n* **What is the new behavior (if this is a feature change)?**\n\n\n\n* **Other information**:\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 60\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 7\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - pinned\n  - security\n  - important\n# Label to use when marking an issue as stale\nstaleLabel: wontfix\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions. If you feel this is very a important issue please\n  reach out the maintainer of this project directly via e-mail: gekko at mvr dot me.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false"
  },
  {
    "path": ".gitignore",
    "content": "# Numerous always-ignore extensions\n*.diff\n*.err\n*.orig\n*.log\n*.rej\n*.swo\n*.swp\n*.vi\n*~\n*.sass-cache\n\n# OS or Editor folders\n.DS_Store\nThumbs.db\nconfig.js\napi-keys.js\n.cache\n.project\n.settings\n.tmproj\nnbproject\n*.sublime-project\n*.sublime-workspace\n\n# Dreamweaver added files\n_notes\ndwsync.xml\n\n# Komodo\n*.komodoproject\n.komodotools\n\n# Espresso\n*.esproj\n*.espressostorage\n\n# Folders & files to ignore\n\nnode_modules\ncandles.csv\ncexio.db\nhistory\nTMP_*\n.idea\nvolumes\nconfig.js\nconfig-*.js\nprivate-*.js\nprivate-*.toml\nSECRET-api-keys.json\nexchange/nusadua"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"trailingComma\": \"es5\",\n  \"singleQuote\": true\n}"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"8.11.2\""
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for (thinking about) contributing to Gekko, all help is wanted!\n\n## Before Submitting an Issue\n\nFirst, please do a search in [open issues](https://github.com/askmike/gekko/issues/) to see if the issue or feature request has already been filed.\n\nIf you find your issue already exists, make relevant comments and add your reaction:\n\n👍 - upvote\n\n👎 - downvote\n\nIf you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.\n\n### Submitting an issue (bug)\n\n* Be as clear and concise as possible.\n* Do not submit more than one bug in a single issue.\n* Clearly explain the following:\n\n1. Action taken (what you did)\n2. Expected result (what you hoped would happen)\n3. Actual result (unexpected outcome)\n4. Your setup (any and all relevant technical facts, error messages, logs, etc)\n\n### Feature requests\n\n* First consider if **you** yourself might be able to work on the feature?  If so, check out info on contributing code below.\n* If you do not have the skills, then please take the time to clearly think through the request. Is is appropriate for all users of Gekko?  If so, create a new issue containing the following:\n\n1. Write `[request]` as the first item in the title, followed by a short, concise description, eg: `[request] Export data to CSV`.\n2. Fill in details explaining your request.  Be as clear and concise as possible and only 1 request at a time.\n3. Add mock-ups, etc as needed to clearly demonstrate the idea.\n\n## New Feature and code contributions\n\n- If you want to add an exchange to Gekko, see [this doc](https://gekko.wizb.it/docs/extending/add_an_exchange.html) for all the information you need.\n- If you want to Gekko react to anything from the market, you can most likely put this functionality into a plugin. See [this document](https://gekko.wizb.it/docs/internals/plugins.html) for details.\n- If you want to create a strategy, please see [this page](https://gekko.wizb.it/docs/strategies/creating_a_strategy.html).\n- If you just want to work on Gekko, you can use the open issues with the tag `open-for-pulls` for inspiration.\n- If you want to work on the web interface (Gekko UI), please see [this frontend doc](https://gekko.wizb.it/docs/internals/gekko_ui.html) on the Vue.js frontend.\n\nThings to take into consideration when submitting a pull request:\n\n - Please submit all pull requests (except for hotfixes) to the [develop branch](https://github.com/askmike/gekko/tree/develop).\n - Please keep current code styling in mind.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:8\n\nENV HOST localhost\nENV PORT 3000\n\n# Create app directory\nRUN mkdir -p /usr/src/app\nWORKDIR /usr/src/app\n\n# Install GYP dependencies globally, will be used to code build other dependencies\nRUN npm install -g --production node-gyp && \\\n    npm cache clean --force\n\n# Install Gekko dependencies\nCOPY package.json .\nRUN npm install --production && \\\n    npm install --production redis@0.10.0 talib@1.0.2 tulind@0.8.7 pg && \\\n    npm cache clean --force\n\n# Install Gekko Broker dependencies\nWORKDIR exchange\nCOPY exchange/package.json .\nRUN npm install --production && \\\n    npm cache clean --force\nWORKDIR ../\n\n# Bundle app source\nCOPY . /usr/src/app\n\nEXPOSE 3000\nRUN chmod +x /usr/src/app/docker-entrypoint.sh\nENTRYPOINT [\"/usr/src/app/docker-entrypoint.sh\"]\n\nCMD [\"--config\", \"config.js\", \"--ui\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014-2017 Mike van Rossum mike@mvr.me\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "README.md",
    "content": "# This repo is not maintained anymore\n\nI am officially not maintaining this project anymore. It was an amazing journey and I want to thank everyone for\nplaying the role in this amazing story!\n\nMore details can be found here: [https://medium.com/@gekkoplus/archiving-open-source-gekko-dba02e6efc7](https://medium.com/@gekkoplus/archiving-open-source-gekko-dba02e6efc7)\n\nThis only impacts my Gekko repo (askmike/gekko). There might be other forks of Gekko out there that are being maintained!\n\n------\n\nOld content:\n\n------\n\n\n# Gekko [![npm](https://img.shields.io/npm/dm/gekko.svg)]() [![Build Status](https://travis-ci.org/askmike/gekko.png)](https://travis-ci.org/askmike/gekko) [![Build status](https://ci.appveyor.com/api/projects/status/github/askmike/gekko?branch=stable&svg=true)](https://ci.appveyor.com/project/askmike/gekko)\n\n![Gordon Gekko](http://mikevanrossum.nl/static/gekko.jpg)\n\n*The most valuable commodity I know of is information.*\n\n-Gordon Gekko\n\nGekko is a Bitcoin TA trading and backtesting platform that connects to popular Bitcoin exchanges. It is written in JavaScript and runs on [Node.js](http://nodejs.org).\n\n*Use Gekko at your own risk.*\n\n## Documentation\n\nSee [the documentation website](https://gekko.wizb.it/docs/introduction/about_gekko.html).\n\n## Installation & Usage\n\nSee [the installing Gekko doc](https://gekko.wizb.it/docs/installation/installing_gekko.html).\n\n## Community & Support\n\nGekko has [a forum](https://forum.gekko.wizb.it/) that is the place for discussions on using Gekko, automated trading and exchanges. In case you rather want to chat in realtime about Gekko feel free to join the [Gekko Support Discord](https://discord.gg/26wMygt).\n\n## Final\n\nIf Gekko helped you in any way, you can always leave me a tip at (BTC) 13r1jyivitShUiv9FJvjLH7Nh1ZZptumwW\n"
  },
  {
    "path": "appveyor.yml",
    "content": "init:\n  - git config --global core.autocrlf input\n\nenvironment:\n  nodejs_version: \"9\"\n\ninstall:\n  - ps: Install-Product node $env:nodejs_version\n  - npm install\ntest_script:\n  - node --version\n  - npm --version\n  - cmd: npm test\n\nbuild: off"
  },
  {
    "path": "config/adapters/mongodb.toml",
    "content": "connectionString = \"mongodb://mongodb/gekko\"\npath = \"plugins/mongodb\"\nversion = 0.1\n\n[[dependencies]]\nmodule = \"mongojs\"\nversion = \"2.4.0\""
  },
  {
    "path": "config/adapters/postgresql.toml",
    "content": "connectionString = \"postgres://user:pass@localhost:5432\"\npath = \"plugins/postgresql\"\nversion = 0.1\n\n[[dependencies]]\nmodule = \"pg\"\nversion = \"6.1.0\""
  },
  {
    "path": "config/adapters/sqlite.toml",
    "content": "dataDirectory = \"history\"\npath = \"plugins/sqlite\"\nversion = 0.1\n\n[[dependencies]]\nmodule = \"sqlite3\"\nversion = \"3.1.4\""
  },
  {
    "path": "config/backtest.toml",
    "content": "batchSize = 50\n\n# scan for available dateranges\ndaterange = \"scan\"\n# or specify it like so:\n# [daterange]\n# from = \"2015-01-01\"\n# to = \"2016-01-01\""
  },
  {
    "path": "config/general.toml",
    "content": "debug = true\n\n# what database should Gekko use?\nadapter = 'sqlite'\n\n[watch]\nexchange = 'Poloniex'\ncurrency = 'USDT'\nasset = 'BTC'\n\n"
  },
  {
    "path": "config/plugins/candleWriter.toml",
    "content": "enabled = true\nadapter = \"sqlite\""
  },
  {
    "path": "config/plugins/paperTrader.toml",
    "content": "feeMaker = 0.25\nfeeTaker = 0.25\nfeeUsing = 'maker'\nslippage = 0.05\n\n[simulationBalance]\nasset = 1\ncurrency = 100\n"
  },
  {
    "path": "config/plugins/performanceAnalyzer.toml",
    "content": "# Used to calculate sharpe ratio\n# yearly % of riskfree return for example\n# treasury bonds or bank interest.\n\nriskFreeReturn = 2"
  },
  {
    "path": "config/plugins/pushbullet.toml",
    "content": "enabled = false\n\n# Send 'Gekko starting' message if true\nsendMessageOnStart = true\n\n# disable advice printout if it's soft\nmuteSoft = true\n\n# your email, change it unless you are Azor Ahai\nemail = \"jon_snow@westeros.org\"\n\n# your pushbullet API key\nkey = \"xxx\"\n\n# will make Gekko messages start with [GEKKO]\ntag = \"[GEKKO]\""
  },
  {
    "path": "config/plugins/trader.toml",
    "content": "enabled = false\n\n## NOTE: once you filled in the following\n## never share this file with anyone!\n\nkey = \"\"\nsecret = \"\"\n# this is only required at specific exchanges\nusername = \"\""
  },
  {
    "path": "config/plugins/tradingAdvisor.toml",
    "content": "enabled = true\n\ncandleSize = 60\nhistorySize = 25\nmethod = \"MACD\"\n\n[talib]\nenabled = false\nversion = \"1.0.2\""
  },
  {
    "path": "config/strategies/CCI.toml",
    "content": "# constant multiplier. 0.015 gets to around 70% fit\nconstant = 0.015\n\n# history size, make same or smaller than history\nhistory = 90\n\n[thresholds]\nup = 100\ndown = -100\npersistence = 0"
  },
  {
    "path": "config/strategies/DEMA.toml",
    "content": "weight = 21\n\n[thresholds]\ndown = -0.025\nup = 0.025\n"
  },
  {
    "path": "config/strategies/MACD.toml",
    "content": "short = 10\nlong = 21\nsignal = 9\n\n[thresholds]\ndown = -0.025\nup = 0.025\npersistence = 1"
  },
  {
    "path": "config/strategies/PPO.toml",
    "content": "short = 12\nlong = 26\nsignal = 9\n\n[thresholds]\ndown = -0.025\nup = 0.025\npersistence = 2"
  },
  {
    "path": "config/strategies/RSI.toml",
    "content": "interval = 14\n\n[thresholds]\nlow = 30\nhigh = 70\npersistence = 1"
  },
  {
    "path": "config/strategies/StochRSI.toml",
    "content": "interval = 3\n\n[thresholds]\nlow = 20\nhigh = 80\npersistence = 3"
  },
  {
    "path": "config/strategies/TMA.toml",
    "content": "short = 7\nmedium = 25\nlong = 99\n"
  },
  {
    "path": "config/strategies/TSI.toml",
    "content": "short = 13\nlong = 25\n\n[thresholds]\nlow = -25\nhigh = 25\npersistence = 1"
  },
  {
    "path": "config/strategies/UO.toml",
    "content": "[first]\nweight = 4\nperiod = 7\n\n[second]\nweight = 2\nperiod = 14\n\n[third]\nweight = 1\nperiod = 28\n\n[thresholds]\nlow = 30\nhigh = 70\npersistence = 1\n"
  },
  {
    "path": "config/strategies/custom.toml",
    "content": "my_custom_setting = 10"
  },
  {
    "path": "config/strategies/talib-macd.toml",
    "content": "[parameters]\noptInFastPeriod = 10\noptInSlowPeriod = 21\noptInSignalPeriod = 9\n\n[thresholds]\ndown = -0.025\nup = 0.025"
  },
  {
    "path": "config/strategies/tulip-adx.toml",
    "content": "historySize = 80\noptInTimePeriod = 15\ncandleSize = 10\n\n[thresholds]\nup = 30\ndown = 20"
  },
  {
    "path": "config/strategies/tulip-macd.toml",
    "content": "[parameters]\noptInFastPeriod = 10\noptInSlowPeriod = 21\noptInSignalPeriod = 9\n\n[thresholds]\ndown = -0.025\nup = 0.025"
  },
  {
    "path": "config/strategies/tulip-multi-strat.toml",
    "content": "optInTimePeriod = 2\noptInFastPeriod = 4\noptInSlowPeriod = 7\noptInSignalPeriod = 23.707189677282354\n\ncandleSize = 1\nhistorySize = 4\n\nup = 24.52\ndown = 55.74\nmacd_up = 14.498233170768081\nmacd_down = -9.65220944122072\n"
  },
  {
    "path": "config/strategies/varPPO.toml",
    "content": "momentum = \"TSI\" # RSI, TSI or UO\n\n[thresholds]\nweightLow = 120\nweightHigh = -120\n\n# How many candle intervals should a trend persist\n# before we consider it real?\npersistence = 0"
  },
  {
    "path": "core/budfox/budfox.js",
    "content": "// Budfox is the realtime market for Gekko!\n//\n// Read more here:\n// @link https://github.com/askmike/gekko/blob/stable/docs/internals/budfox.md\n//\n// > [getting up] I don't know. I guess I realized that I'm just Bud Fox.\n// > As much as I wanted to be Gordon Gekko, I'll *always* be Bud Fox.\n// > [tosses back the handkerchief and walks away]\n\nvar _ = require('lodash');\nvar async = require('async');\n\nvar util = require(__dirname + '/../util');\nvar dirs = util.dirs();\n\nvar Heart = require(dirs.budfox + 'heart');\nvar MarketDataProvider =  require(dirs.budfox + 'marketDataProvider');\nvar CandleManager = require(dirs.budfox + 'candleManager');\n\nvar BudFox = function(config) {\n  _.bindAll(this);\n\n  Readable.call(this, {objectMode: true});\n\n  // BudFox internal modules:\n  \n  this.heart = new Heart;\n  this.marketDataProvider = new MarketDataProvider(config);\n  this.candleManager = new CandleManager;\n\n  //    BudFox data flow:\n\n  // relay a marketUpdate event\n  this.marketDataProvider.on(\n    'marketUpdate',\n    e => this.emit('marketUpdate', e)\n  );\n\n  // relay a marketStart event\n  this.marketDataProvider.on(\n    'marketStart',\n    e => this.emit('marketStart', e)\n  );\n\n  // Output the candles\n  this.candleManager.on(\n    'candles',\n    this.pushCandles\n  );\n\n  // on every `tick` retrieve trade data\n  this.heart.on(\n    'tick',\n    this.marketDataProvider.retrieve\n  );\n\n  // on new trade data create candles\n  this.marketDataProvider.on(\n    'trades',\n    this.candleManager.processTrades\n  );\n\n  this.heart.pump();\n}\n\nvar Readable = require('stream').Readable;\n\nBudFox.prototype = Object.create(Readable.prototype, {\n  constructor: { value: BudFox }\n});\n\nBudFox.prototype._read = function noop() {}\n\nBudFox.prototype.pushCandles = function(candles) {\n  _.each(candles, this.push);\n}\n\nmodule.exports = BudFox;\n"
  },
  {
    "path": "core/budfox/candleCreator.js",
    "content": "// The CandleCreator creates one minute candles based on trade batches. Note\n// that it also adds empty candles to fill gaps with no volume.\n//\n// Expects trade batches to be written like:\n//\n// {\n//   amount: x,\n//   start: (moment),\n//   end: (moment),\n//   first: (trade),\n//   last: (trade),\n//   timespan: x,\n//   all: [\n//      // batch of new trades with\n//      // moments instead of timestamps\n//   ]\n// }\n//\n// Emits 'new candles' event with:\n//\n// [\n//     {\n//       start: (moment),\n//       end: (moment),\n//       high: (float),\n//       open: (float),\n//       low: (float),\n//       close: (float)\n//       volume: (float)\n//       vwp: (float) // volume weighted price\n//    },\n//    {\n//       start: (moment), // + 1\n//       end: (moment),\n//       high: (float),\n//       open: (float),\n//      low: (float),\n//      close: (float)\n//       volume: (float)\n//       vwp: (float) // volume weighted price\n//    }\n//    // etc.\n// ]\n//\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nvar util = require(__dirname + '/../util');\n\nvar CandleCreator = function() {\n  _.bindAll(this);\n\n  // TODO: remove fixed date\n  this.threshold = moment(\"1970-01-01\", \"YYYY-MM-DD\");\n\n  // This also holds the leftover between fetches\n  this.buckets = {};\n}\n\nutil.makeEventEmitter(CandleCreator);\n\nCandleCreator.prototype.write = function(batch) {\n  var trades = batch.data;\n\n  if(_.isEmpty(trades))\n    return;\n\n  trades = this.filter(trades);\n  this.fillBuckets(trades);\n  var candles = this.calculateCandles();\n\n  candles = this.addEmptyCandles(candles);\n\n  if(_.isEmpty(candles))\n    return;  \n\n  // the last candle is not complete\n  this.threshold = candles.pop().start;\n\n  this.emit('candles', candles);\n}\n\nCandleCreator.prototype.filter = function(trades) {\n  // make sure we only include trades more recent\n  // than the previous emitted candle\n  return _.filter(trades, function(trade) {\n    return trade.date > this.threshold;\n  }, this);\n}\n\n// put each trade in a per minute bucket\nCandleCreator.prototype.fillBuckets = function(trades) {\n  _.each(trades, function(trade) {\n    var minute = trade.date.format('YYYY-MM-DD HH:mm');\n\n    if(!(minute in this.buckets))\n      this.buckets[minute] = [];\n\n    this.buckets[minute].push(trade);\n  }, this);\n\n  this.lastTrade = _.last(trades);\n}\n\n// convert each bucket into a candle\nCandleCreator.prototype.calculateCandles = function() {\n  var minutes = _.size(this.buckets);\n\n  // catch error from high volume getTrades\n  if (this.lastTrade !== undefined)\n    // create a string referencing the minute this trade happened in\n    var lastMinute = this.lastTrade.date.format('YYYY-MM-DD HH:mm');\n\n  var candles = _.map(this.buckets, function(bucket, name) {\n    var candle = this.calculateCandle(bucket);\n\n    // clean all buckets, except the last one:\n    // this candle is not complete\n    if(name !== lastMinute)\n      delete this.buckets[name];\n\n    return candle;\n  }, this);\n\n  return candles;\n}\n\nCandleCreator.prototype.calculateCandle = function(trades) {\n  var first = _.first(trades);\n\n  var f = parseFloat;\n\n  var candle = {\n    start: first.date.clone().startOf('minute'),\n    open: f(first.price),\n    high: f(first.price),\n    low: f(first.price),\n    close: f(_.last(trades).price),\n    vwp: 0,\n    volume: 0,\n    trades: _.size(trades)\n  };\n\n  _.each(trades, function(trade) {\n    candle.high = _.max([candle.high, f(trade.price)]);\n    candle.low = _.min([candle.low, f(trade.price)]);\n    candle.volume += f(trade.amount);\n    candle.vwp += f(trade.price) * f(trade.amount);\n  });\n\n  candle.vwp /= candle.volume;\n\n  return candle;\n}\n\n// Gekko expects a candle every minute, if nothing happened\n// during a particilar minute Gekko will add empty candles with:\n//\n// - open, high, close, low, vwp are the same as the close of the previous candle.\n// - trades, volume are 0\nCandleCreator.prototype.addEmptyCandles = function(candles) {\n  var amount = _.size(candles);\n  if(!amount)\n    return candles;\n\n  // iterator\n  var start = _.first(candles).start.clone();\n  var end = _.last(candles).start;\n  var i, j = -1;\n\n  var minutes = _.map(candles, function(candle) {\n    return +candle.start;\n  });\n\n  while(start < end) {\n    start.add(1, 'm');\n    i = +start;\n    j++;\n\n    if(_.contains(minutes, i))\n      continue; // we have a candle for this minute\n\n    var lastPrice = candles[j].close;\n\n    candles.splice(j + 1, 0, {\n      start: start.clone(),\n      open: lastPrice,\n      high: lastPrice,\n      low: lastPrice,\n      close: lastPrice,\n      vwp: lastPrice,\n      volume: 0,\n      trades: 0\n    });\n  }\n  return candles;\n}\n\nmodule.exports = CandleCreator;\n"
  },
  {
    "path": "core/budfox/candleManager.js",
    "content": "// The candleManager consumes trades and emits:\n// - `candles`: array of minutly candles.\n// - `candle`: the most recent candle after a fetch Gekko.\n\nvar _ = require('lodash');\nvar moment = require('moment');\nvar fs = require('fs');\n\nvar util = require(__dirname + '/../util');\nvar dirs = util.dirs();\nvar config = util.getConfig();\nvar log = require(dirs.core + 'log');\n\nvar CandleCreator = require(dirs.budfox + 'candleCreator');\n\nvar Manager = function() {\n  _.bindAll(this);\n\n  this.candleCreator = new CandleCreator;\n\n  this.candleCreator\n    .on('candles', this.relayCandles);\n};\n\nutil.makeEventEmitter(Manager);\nManager.prototype.processTrades = function(tradeBatch) {\n  this.candleCreator.write(tradeBatch);\n}\n\nManager.prototype.relayCandles = function(candles) {\n  this.emit('candles', candles);\n}\n\nmodule.exports = Manager;\n"
  },
  {
    "path": "core/budfox/heart.js",
    "content": "// The heart schedules and emit ticks every 20 seconds.\n\nvar util = require(__dirname + '/../util');\nvar log = require(util.dirs().core + 'log');\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nif (util.getConfig().watch.tickrate)\n  var TICKRATE = util.getConfig().watch.tickrate;\nelse if(util.getConfig().watch.exchange === 'okcoin')\n  var TICKRATE = 2;\nelse\n  var TICKRATE = 20;\n\nvar Heart = function() {\n  this.lastTick = false;\n\n  _.bindAll(this);\n}\n\nutil.makeEventEmitter(Heart);\n\nHeart.prototype.pump = function() {\n  log.debug('scheduling ticks');\n  this.scheduleTicks();\n}\n\nHeart.prototype.tick = function() {\n  if(this.lastTick) {\n    // make sure the last tick happened not to lang ago\n    // @link https://github.com/askmike/gekko/issues/514\n    if(this.lastTick < moment().unix() - TICKRATE * 3)\n      util.die('Failed to tick in time, see https://github.com/askmike/gekko/issues/514 for details', true);\n  }\n\n  this.lastTick = moment().unix();\n  this.emit('tick');\n}\n\nHeart.prototype.scheduleTicks = function() {\n  setInterval(\n    this.tick,\n    +moment.duration(TICKRATE, 's')\n  );\n\n  // start!\n  _.defer(this.tick);\n}\n\nmodule.exports = Heart;\n"
  },
  {
    "path": "core/budfox/marketDataProvider.js",
    "content": "// \n// The market data provider will fetch data from a datasource on tick. It emits:\n// \n// - `trades`: batch of newly detected trades\n// - `trade`: after Gekko fetched new trades, this\n//   will be the most recent one.\n\nconst _ = require('lodash');\nconst util = require(__dirname + '/../util');\n\nconst MarketFetcher = require('./marketFetcher');\nconst dirs = util.dirs();\n\nconst Manager = function(config) {\n\n  _.bindAll(this);\n\n  // fetch trades\n  this.source = new MarketFetcher(config);\n\n  // relay newly fetched trades\n  this.source\n    .on('trades batch', this.relayTrades);\n}\n\nutil.makeEventEmitter(Manager);\n\n// HANDLERS\nManager.prototype.retrieve = function() {\n  this.source.fetch();\n}\n\n\nManager.prototype.relayTrades = function(batch) {\n  this.sendMarketStart(batch);\n  this.emit('marketUpdate', batch.last.date);\n\n  this.emit('trades', batch);\n}\n\nManager.prototype.sendMarketStart = _.once(function(batch) {\n  this.emit('marketStart', batch.first.date);\n});\n\nmodule.exports = Manager;"
  },
  {
    "path": "core/budfox/marketFetcher.js",
    "content": "//\n// The fetcher is responsible for fetching new\n// market data at the exchange on interval. It will emit\n// the following events:\n//\n// - `trades batch` - all new trades.\n// - `trade` - the most recent trade after every fetch\n\nconst _ = require('lodash');\nconst moment = require('moment');\nconst utc = moment.utc;\nconst util = require(__dirname + '/../util');\nconst dirs = util.dirs();\n\nconst config = util.getConfig();\nconst log = require(dirs.core + 'log');\nconst exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');\n\nconst TradeBatcher = require(util.dirs().budfox + 'tradeBatcher');\n\nconst Fetcher = function(config) {\n  if(!_.isObject(config))\n    throw new Error('TradeFetcher expects a config');\n\n  const exchangeName = config.watch.exchange.toLowerCase();\n  const DataProvider = require(util.dirs().gekko + 'exchange/wrappers/' + exchangeName);\n  _.bindAll(this);\n\n  // Create a public dataProvider object which can retrieve live\n  // trade information from an exchange.\n  this.exchangeTrader = new DataProvider(config.watch);\n\n  this.exchange = exchangeChecker.settings(config.watch);\n\n  var requiredHistory = config.tradingAdvisor.candleSize * config.tradingAdvisor.historySize;\n\n  // If the trading adviser is enabled we might need a very specific fetch since\n  // to line up [local db, trading method, and fetching]\n  if(config.tradingAdvisor.enabled && config.tradingAdvisor.firstFetchSince) {\n    this.firstSince = config.tradingAdvisor.firstFetchSince;\n\n    if(this.exchange.providesHistory === 'date') {\n      this.firstSince = moment.unix(this.firstSince).utc();\n    }\n  }\n\n  this.batcher = new TradeBatcher(this.exchange.tid);\n\n  this.pair = [\n    config.watch.asset,\n    config.watch.currency\n  ].join('/');\n\n  log.info('Starting to watch the market:',\n    this.exchange.name,\n    this.pair\n  );\n\n  // if the exchange returns an error\n  // we will keep on retrying until next\n  // scheduled fetch.\n  this.tries = 0;\n  this.limit = 20; // [TODO]\n\n  this.firstFetch = true;\n\n  this.batcher.on('new batch', this.relayTrades);\n}\n\nutil.makeEventEmitter(Fetcher);\n\nFetcher.prototype._fetch = function(since) {\n  if(++this.tries >= this.limit)\n    return;\n\n  this.exchangeTrader.getTrades(since, this.processTrades, false);\n}\n\nFetcher.prototype.fetch = function() {\n  var since = false;\n  if(this.firstFetch) {\n    since = this.firstSince;\n    this.firstFetch = false;\n  } else\n    since = false;\n\n  this.tries = 0;\n  log.debug('Requested', this.pair, 'trade data from', this.exchange.name, '...');\n  this._fetch(since);\n}\n\nFetcher.prototype.processTrades = function(err, trades) {\n  if(err || _.isEmpty(trades)) {\n    if(err) {\n      log.warn(this.exchange.name, 'returned an error while fetching trades:', err);\n      log.debug('refetching...');\n    } else\n      log.debug('Trade fetch came back empty, refetching...');\n    setTimeout(this._fetch, +moment.duration('s', 1));\n    return;\n  }\n  this.batcher.write(trades);\n}\n\nFetcher.prototype.relayTrades = function(batch) {\n  this.emit('trades batch', batch);\n}\n\nmodule.exports = Fetcher;\n"
  },
  {
    "path": "core/budfox/tradeBatcher.js",
    "content": "// \n// Small wrapper that only propagates new trades.\n// \n// Expects trade batches to be written like:\n// [\n//  {\n//    tid: x, // tid is preferred, but if none available date will also work\n//    price: x,\n//    date: (timestamp),\n//    amount: x\n//  },\n//  {\n//    tid: x + 1,\n//    price: x,\n//    date: (timestamp),\n//    amount: x\n//  }\n// ]\n// \n// Emits 'new trades' event with:\n// {\n//   amount: x,\n//   start: (moment),\n//   end: (moment),\n//   first: (trade),\n//   last: (trade)\n//   data: [\n//      // batch of new trades with \n//      // moments instead of timestamps\n//   ]\n// }\n\nvar _ = require('lodash');\nvar moment = require('moment');\nvar util = require('../util');\nvar log = require('../log');\n\nvar TradeBatcher = function(tid) {\n  if(!_.isString(tid))\n    throw new Error('tid is not a string');\n\n  _.bindAll(this);\n  this.tid = tid;\n  this.last = -1;\n}\n\nutil.makeEventEmitter(TradeBatcher);\n\nTradeBatcher.prototype.write = function(batch) {\n\n  if(!_.isArray(batch))\n    throw new Error('batch is not an array');\n\n  if(_.isEmpty(batch))\n    return log.debug('Trade fetch came back empty.');\n\n  var filterBatch = this.filter(batch);\n\n  var amount = _.size(filterBatch);\n  if(!amount)\n    return log.debug('No new trades.');\n\n  var momentBatch = this.convertDates(filterBatch);\n\n  var last = _.last(momentBatch);\n  var first = _.first(momentBatch);\n\n  log.debug(\n    'Processing', amount, 'new trades.',\n    'From',\n    first.date.format('YYYY-MM-DD HH:mm:ss'),\n    'UTC to',\n    last.date.format('YYYY-MM-DD HH:mm:ss'),\n    'UTC.',\n    '(' + first.date.from(last.date, true) + ')'\n  );\n\n  this.emit('new batch', {\n    amount: amount,\n    start: first.date,\n    end: last.date,\n    last: last,\n    first: first,\n    data: momentBatch\n  });\n\n  this.last = last[this.tid];\n\n  // we overwrote those, get unix ts back\n  if(this.tid === 'date')\n    this.last = this.last.unix();\n\n}\n\nTradeBatcher.prototype.filter = function(batch) {\n  // make sure we're not trying to count\n  // beyond infinity\n  var lastTid = _.last(batch)[this.tid];\n  if(lastTid === lastTid + 1)\n    util.die('trade tid is max int, Gekko can\\'t process..');\n\n  // remove trades that have zero amount\n  // see @link\n  // https://github.com/askmike/gekko/issues/486\n  batch = _.filter(batch, function(trade) {\n    return trade.amount > 0;\n  });\n\n  // weed out known trades\n  // TODO: optimize by stopping as soon as the\n  // first trade is too old (reverse first)\n  return _.filter(batch, function(trade) {\n    return this.last < trade[this.tid];\n  }, this);\n}\n\nTradeBatcher.prototype.convertDates = function(batch) {\n  return _.map(_.cloneDeep(batch), function(trade) {\n    trade.date = moment.unix(trade.date).utc();\n    return trade;\n  });\n}\n\nmodule.exports = TradeBatcher;\n"
  },
  {
    "path": "core/candleBatcher.js",
    "content": "// internally we only use 1m\n// candles, this can easily\n// convert them to any desired\n// size.\n\n// Acts as ~fake~ stream: takes\n// 1m candles as input and emits\n// bigger candles.\n// \n// input are transported candles.\n\nvar _ = require('lodash');\nvar util = require(__dirname + '/util');\n\nvar CandleBatcher = function(candleSize) {\n  if(!_.isNumber(candleSize))\n    throw new Error('candleSize is not a number');\n\n  this.candleSize = candleSize;\n  this.smallCandles = [];\n  this.calculatedCandles = [];\n\n  _.bindAll(this);\n}\n\nutil.makeEventEmitter(CandleBatcher);\n\nCandleBatcher.prototype.write = function(candles) {\n  if(!_.isArray(candles)) {\n    throw new Error('candles is not an array');\n  }\n\n  this.emitted = 0;\n\n  _.each(candles, function(candle) {\n    this.smallCandles.push(candle);\n    this.check();\n  }, this);\n\n  return this.emitted;\n}\n\nCandleBatcher.prototype.check = function() {\n  if(_.size(this.smallCandles) % this.candleSize !== 0)\n    return;\n\n  this.emitted++;\n  this.calculatedCandles.push(this.calculate());\n  this.smallCandles = [];\n}\n\nCandleBatcher.prototype.flush = function() {\n  _.each(\n    this.calculatedCandles,\n    candle => this.emit('candle', candle)\n  );\n\n  this.calculatedCandles = [];\n}\n\nCandleBatcher.prototype.calculate = function() {\n  // remove the id property of the small candle\n  var { id, ...first } = this.smallCandles.shift();\n\n  first.vwp = first.vwp * first.volume;\n\n  var candle = _.reduce(\n    this.smallCandles,\n    function(candle, m) {\n      candle.high = _.max([candle.high, m.high]);\n      candle.low = _.min([candle.low, m.low]);\n      candle.close = m.close;\n      candle.volume += m.volume;\n      candle.vwp += m.vwp * m.volume;\n      candle.trades += m.trades;\n      return candle;\n    },\n    first\n  );\n\n  if(candle.volume)\n    // we have added up all prices (relative to volume)\n    // now divide by volume to get the Volume Weighted Price\n    candle.vwp /= candle.volume;\n  else\n    // empty candle\n    candle.vwp = candle.open;\n\n  candle.start = first.start;\n  return candle;\n}\n\nmodule.exports = CandleBatcher;\n"
  },
  {
    "path": "core/emitter.js",
    "content": "// Gekko uses a custom event emitter within the GekkoStream (the plugins) to guarantee\n// the correct order of events that are triggered by eachother. Turns sync events from\n// LIFO into a FIFO stack based model.\n//\n// More details here: https://forum.gekko.wizb.it/thread-56579.html\n\nconst util = require('util');\nconst events = require('events');\nconst NativeEventEmitter = events.EventEmitter;\n\nconst GekkoEventEmitter = function() {\n  NativeEventEmitter.call(this);\n  this.defferedEvents = [];\n}\n\nutil.inherits(GekkoEventEmitter, NativeEventEmitter);\n\n// push to stack\nGekkoEventEmitter.prototype.deferredEmit = function(name, payload) {\n  this.defferedEvents.push({name, payload});\n}\n\n// resolve FIFO\nGekkoEventEmitter.prototype.broadcastDeferredEmit = function() {\n  if(this.defferedEvents.length === 0)\n    return false;\n\n  const event = this.defferedEvents.shift();\n\n  this.emit(event.name, event.payload);\n  return true;\n}\n\nmodule.exports = GekkoEventEmitter;"
  },
  {
    "path": "core/gekkoStream.js",
    "content": "// Small writable stream wrapper that\n// passes data to all `candleConsumers`.\n\nconst Writable = require('stream').Writable;\nconst _ = require('lodash');\nconst async = require('async');\nconst moment = require('moment');\n\nconst util = require('./util');\nconst env = util.gekkoEnv();\nconst mode = util.gekkoMode();\nconst config = util.getConfig();\nconst log = require(util.dirs().core + 'log');\n\nvar Gekko = function(plugins) {\n  this.plugins = plugins;\n  this.candleConsumers = plugins\n    .filter(plugin => plugin.processCandle);\n  Writable.call(this, {objectMode: true});\n\n  this.producers = this.plugins\n    .filter(p => p.meta.emits);\n\n  this.finalize = _.bind(this.finalize, this);\n}\n\nGekko.prototype = Object.create(Writable.prototype, {\n  constructor: { value: Gekko }\n});\n\nif(config.debug && mode !== 'importer') {\n  // decorate with more debug information\n  Gekko.prototype._write = function(chunk, encoding, _done) {\n\n    if(chunk.isFinished) {\n      return this.finalize();\n    }\n\n    const start = moment();\n    var relayed = false;\n    var at = null;\n\n    const timer = setTimeout(() => {\n      if(!relayed)\n        log.error([\n          `The plugin \"${at}\" has not processed a candle for 1 second.`,\n          `This will cause Gekko to slow down or stop working completely.`\n        ].join(' '));\n    }, 1000);\n\n    const flushEvents = _.after(this.candleConsumers.length, () => {\n      relayed = true;\n      clearInterval(timer);\n      this.flushDefferedEvents();\n      _done();\n    });\n    _.each(this.candleConsumers, function(c) {\n      at = c.meta.name;\n      c.processCandle(chunk, flushEvents);\n    }, this);\n  }\n} else {\n  // skip decoration\n  Gekko.prototype._write = function(chunk, encoding, _done) {\n    if(chunk.isFinished) {\n      return this.finalize();\n    }\n\n    const flushEvents = _.after(this.candleConsumers.length, () => {\n      this.flushDefferedEvents();\n      _done();\n    });\n    _.each(this.candleConsumers, function(c) {\n      c.processCandle(chunk, flushEvents);\n    }, this);\n  }\n}\n\nGekko.prototype.flushDefferedEvents = function() {\n  const broadcasted = _.find(\n    this.producers,\n    producer => producer.broadcastDeferredEmit()\n  );\n\n  // If we braodcasted anything we might have\n  // triggered more events, recurse until we\n  // have fully broadcasted everything.\n  if(broadcasted)\n    this.flushDefferedEvents();\n}\n\nGekko.prototype.finalize = function() {\n  var tradingMethod = _.find(\n    this.candleConsumers,\n    c => c.meta.name === 'Trading Advisor'\n  );\n\n  if(!tradingMethod)\n    return this.shutdown();\n\n  tradingMethod.finish(this.shutdown.bind(this));\n}\n\nGekko.prototype.shutdown = function() {\n  this.end();\n  async.eachSeries(\n    this.plugins,\n    function(c, callback) {\n      if (c.finalize) c.finalize(callback);\n      else callback();\n    },\n    () => {\n      // If we are a child process, we signal to the parent to kill the child once it is done\n      // so that is has time to process all remaining events (and send report data)\n      if (env === 'child-process') process.send('done');\n      else process.exit(0);\n    }\n  );\n};\n\nmodule.exports = Gekko;"
  },
  {
    "path": "core/log.js",
    "content": "/*\n\n  Lightweight logger, print everything that is send to error, warn\n  and messages to stdout (the terminal). If config.debug is set in config\n  also print out everything send to debug.\n\n*/\n\nvar moment = require('moment');\nvar fmt = require('util').format;\nvar _ = require('lodash');\nvar util = require('./util');\nvar config = util.getConfig();\nvar debug = config.debug;\nvar silent = config.silent;\n\nvar sendToParent = function() {\n  var send = method => (...args) => {\n    process.send({log: method, message: args.join(' ')});\n  }\n\n  return {\n    error: send('error'),\n    warn: send('warn'),\n    info: send('info'),\n    write: send('write')\n  }\n}\n\nvar Log = function() {\n  _.bindAll(this);\n  this.env = util.gekkoEnv();\n\n  if(this.env === 'standalone')\n    this.output = console;\n  else if(this.env === 'child-process')\n    this.output = sendToParent();\n};\n\nLog.prototype = {\n  _write: function(method, args, name) {\n    if(!name)\n      name = method.toUpperCase();\n\n    var message = moment().format('YYYY-MM-DD HH:mm:ss');\n    message += ' (' + name + '):\\t';\n    message += fmt.apply(null, args);\n\n    this.output[method](message);\n  },\n  error: function() {\n    this._write('error', arguments);\n  },\n  warn: function() {\n    this._write('warn', arguments);\n  },\n  info: function() {\n    this._write('info', arguments);\n  },\n  write: function() {\n    var args = _.toArray(arguments);\n    var message = fmt.apply(null, args);\n    this.output.info(message);\n  }\n}\n\nif(debug)\n  Log.prototype.debug = function() {\n    this._write('info', arguments, 'DEBUG');  \n  }\nelse\n  Log.prototype.debug = _.noop;\n\nif(silent) {\n  Log.prototype.debug = _.noop;\n  Log.prototype.info = _.noop;\n  Log.prototype.warn = _.noop;\n  Log.prototype.write = _.noop;\n}\n\nmodule.exports = new Log;"
  },
  {
    "path": "core/markets/backtest.js",
    "content": "var _ = require('lodash');\nvar util = require('../util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + 'log');\nvar moment = require('moment');\n\nvar adapter = config[config.adapter];\nvar Reader = require(dirs.gekko + adapter.path + '/reader');\nvar daterange = config.backtest.daterange;\n\nvar to = moment.utc(daterange.to);\nvar from = moment.utc(daterange.from);\n\nif(to <= from)\n  util.die('This daterange does not make sense.')\n\nif(!from.isValid())\n  util.die('invalid `from`');\n\nif(!to.isValid())\n  util.die('invalid `to`');\n\nvar Market = function() {\n\n  _.bindAll(this);\n  this.pushing = false;\n  this.ended = false;\n  this.closed = false;\n\n  Readable.call(this, {objectMode: true});\n\n  log.write('');\n  log.info('\\tWARNING: BACKTESTING FEATURE NEEDS PROPER TESTING');\n  log.info('\\tWARNING: ACT ON THESE NUMBERS AT YOUR OWN RISK!');\n  log.write('');\n\n  this.reader = new Reader();\n  this.batchSize = config.backtest.batchSize;\n  this.iterator = {\n    from: from.clone(),\n    to: from.clone().add(this.batchSize, 'm').subtract(1, 's')\n  }\n}\n\nvar Readable = require('stream').Readable;\nMarket.prototype = Object.create(Readable.prototype, {\n  constructor: { value: Market }\n});\n\nMarket.prototype._read = _.once(function() {\n  this.get();\n});\n\nMarket.prototype.get = function() {\n  if(this.iterator.to >= to) {\n    this.iterator.to = to;\n    this.ended = true;\n  }\n\n  this.reader.get(\n    this.iterator.from.unix(),\n    this.iterator.to.unix(),\n    'full',\n    this.processCandles\n  )\n}\n\nMarket.prototype.processCandles = function(err, candles) {\n  this.pushing = true;\n  var amount = _.size(candles);\n\n  if(amount === 0) {\n    if(this.ended) {\n      this.closed = true;\n      this.reader.close();\n      this.push({isFinished: true});\n    } else {\n      util.die('Query returned no candles (do you have local data for the specified range?)');\n    }\n  }\n\n  if(!this.ended && amount < this.batchSize) {\n    var d = function(ts) {\n      return moment.unix(ts).utc().format('YYYY-MM-DD HH:mm:ss');\n    }\n    var from = d(_.first(candles).start);\n    var to = d(_.last(candles).start);\n    log.warn(`Simulation based on incomplete market data (${this.batchSize - amount} missing between ${from} and ${to}).`);\n  }\n\n  _.each(candles, function(c, i) {\n    c.start = moment.unix(c.start);\n    this.push(c);\n  }, this);\n\n  this.pushing = false;\n\n  this.iterator = {\n    from: this.iterator.from.clone().add(this.batchSize, 'm'),\n    to: this.iterator.from.clone().add(this.batchSize * 2, 'm').subtract(1, 's')\n  }\n\n  if(!this.closed)\n    this.get();\n}\n\nmodule.exports = Market;\n"
  },
  {
    "path": "core/markets/importer.js",
    "content": "var _ = require('lodash');\nvar util = require('../util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + 'log');\nvar moment = require('moment');\nvar gekkoEnv = util.gekkoEnv();\n\nvar adapter = config[config.adapter];\nvar daterange = config.importer.daterange;\n\nvar from = moment.utc(daterange.from);\n\nif(daterange.to) {\n  var to = moment.utc(daterange.to);\n} else {\n  var to = moment().utc();\n  log.debug(\n    'No end date specified for importing, setting to',\n    to.format()\n  );\n}\nlog.debug(to.format());\n\nif(!from.isValid())\n  util.die('invalid `from`');\n\nif(!to.isValid())\n  util.die('invalid `to`');\n\nvar TradeBatcher = require(dirs.budfox + 'tradeBatcher');\nvar CandleManager = require(dirs.budfox + 'candleManager');\nvar exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');\n\nvar error = exchangeChecker.cantFetchFullHistory(config.watch);\nif(error)\n  util.die(error, true);\n\nvar fetcher = require(dirs.importers + config.watch.exchange);\n\nif(to <= from)\n  util.die('This daterange does not make sense.')\n\nvar Market = function() {\n  _.bindAll(this);\n  this.exchangeSettings = exchangeChecker.settings(config.watch);\n\n  this.tradeBatcher = new TradeBatcher(this.exchangeSettings.tid);\n  this.candleManager = new CandleManager;\n  this.fetcher = fetcher({\n    to: to,\n    from: from\n  });\n\n  this.done = false;\n\n  this.fetcher.bus.on(\n    'trades',\n    this.processTrades\n  );\n\n  this.fetcher.bus.on(\n    'done',\n    function() {\n      this.done = true;\n    }.bind(this)\n  )\n\n  this.tradeBatcher.on(\n    'new batch',\n    this.candleManager.processTrades\n  );\n\n  this.candleManager.on(\n    'candles',\n    this.pushCandles\n  );\n\n  Readable.call(this, {objectMode: true});\n\n  this.get();\n}\n\nvar Readable = require('stream').Readable;\nMarket.prototype = Object.create(Readable.prototype, {\n  constructor: { value: Market }\n});\n\nMarket.prototype._read = _.noop;\n\nMarket.prototype.pushCandles = function(candles) {\n  _.each(candles, this.push);\n}\n\nMarket.prototype.get = function() {\n  this.fetcher.fetch();\n}\n\nMarket.prototype.processTrades = function(trades) {\n  this.tradeBatcher.write(trades);\n\n  if(this.done) {\n    log.info('Done importing!');\n    this.emit('end');\n    return;\n  }\n\n  if(_.size(trades) && gekkoEnv === 'child-process') {\n    let lastAtTS = _.last(trades).date;\n    let lastAt = moment.unix(lastAtTS).utc().format();\n    process.send({event: 'marketUpdate', payload: lastAt});\n  }\n\n  setTimeout(this.get, 1000);\n}\n\nmodule.exports = Market;\n"
  },
  {
    "path": "core/markets/leech.js",
    "content": "// a leech market is \"semi-realtime\" and pulls out candles of a\n// database (which is expected to be updated regularly, like with a\n// realtime market running in parallel).\n\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst util = require('../util');\nconst dirs = util.dirs();\nconst config = util.getConfig();\n\nconst exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');\n\nconst adapter = config[config.adapter];\nconst Reader = require(dirs.gekko + adapter.path + '/reader');\n\nconst TICKINTERVAL = 20 * 1000; // 20 seconds\n\nconst slug = config.watch.exchange.toLowerCase();\nconst exchange = exchangeChecker.getExchangeCapabilities(slug);\n\nif(!exchange)\n  util.die(`Unsupported exchange: ${slug}`)\n\nconst error = exchangeChecker.cantMonitor(config.watch);\nif(error)\n  util.die(error, true);\n\nif(config.market.from)\n  var fromTs = moment.utc(config.market.from).unix();\nelse\n  var fromTs = moment().startOf('minute').unix();\n\n\nvar Market = function() {\n\n  _.bindAll(this);\n\n  Readable.call(this, {objectMode: true});\n\n  this.reader = new Reader();\n  this.latestTs = fromTs;\n\n  setInterval(\n    this.get,\n    TICKINTERVAL\n  );\n}\n\nvar Readable = require('stream').Readable;\nMarket.prototype = Object.create(Readable.prototype, {\n  constructor: { value: Market }\n});\n\nMarket.prototype._read = _.once(function() {\n  this.get();\n});\n\nMarket.prototype.get = function() {\n  var future = moment().add(1, 'minute').unix();\n\n  this.reader.get(\n    this.latestTs,\n    future,\n    'full',\n    this.processCandles\n  )\n}\n\nMarket.prototype.processCandles = function(err, candles) {\n  var amount = _.size(candles);\n  if(amount === 0) {\n    // no new candles!\n    return;\n  }\n\n  // TODO:\n  // verify that the correct amount of candles was passed:\n  //\n  // if `this.latestTs` was at 10:00 and we receive 3 candles with the latest at 11:00\n  // we know we are missing 57 candles...\n\n  _.each(candles, function(c, i) {\n    c.start = moment.unix(c.start).utc();\n    this.push(c);\n  }, this);\n\n  this.latestTs = _.last(candles).start.unix() + 1;\n}\n\nmodule.exports = Market;\n"
  },
  {
    "path": "core/markets/realtime.js",
    "content": "const _ = require('lodash');\n\nconst util = require('../util');\nconst dirs = util.dirs();\n\nconst exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');\nconst config = util.getConfig();\n\nconst slug = config.watch.exchange.toLowerCase();\nconst exchange = exchangeChecker.getExchangeCapabilities(slug);\n\nif(!exchange)\n  util.die(`Unsupported exchange: ${slug}`)\n\nconst error = exchangeChecker.cantMonitor(config.watch);\nif(error)\n  util.die(error, true);\n\nmodule.exports = require(dirs.budfox + 'budfox');"
  },
  {
    "path": "core/pipeline.js",
    "content": "/*\n\n  A pipeline implements a full Gekko Flow based on a config and \n  a mode. The mode is an abstraction that tells Gekko what market\n  to load (realtime, backtesting or importing) while making sure\n  all enabled plugins are actually supported by that market.\n\n  Read more here:\n  https://gekko.wizb.it/docs/internals/architecture.html\n\n*/\n\n\nvar util = require('./util');\nvar dirs = util.dirs();\n\nvar _ = require('lodash');\nvar async = require('async');\n\nvar log = require(dirs.core + 'log');\n\nvar pipeline = (settings) => {\n\n  var mode = settings.mode;\n  var config = settings.config;\n\n  // prepare a GekkoStream\n  var GekkoStream = require(dirs.core + 'gekkoStream');\n\n  // all plugins\n  var plugins = [];\n  // all emitting plugins\n  var emitters = {};\n  // all plugins interested in candles\n  var candleConsumers = [];\n\n  // utility to check and load plugins.\n  var pluginHelper = require(dirs.core + 'pluginUtil');\n\n  // meta information about every plugin that tells Gekko\n  // something about every available plugin\n  var pluginParameters = require(dirs.gekko + 'plugins');\n  // meta information about the events plugins can broadcast\n  // and how they should hooked up to consumers.\n  var subscriptions = require(dirs.gekko + 'subscriptions');\n\n  var market;\n\n  // Instantiate each enabled plugin\n  var loadPlugins = function(next) {\n    // load all plugins\n    async.mapSeries(\n      pluginParameters,\n      pluginHelper.load,\n      function(error, _plugins) {\n        if(error)\n          return util.die(error, true);\n\n        plugins = _.compact(_plugins);\n        next();\n      }\n    );\n  };\n\n  // Some plugins emit their own events, store\n  // a reference to those plugins.\n  var referenceEmitters = function(next) {\n\n    _.each(plugins, function(plugin) {\n      if(plugin.meta.emits)\n        emitters[plugin.meta.slug] = plugin;\n    });\n\n    next();\n  }\n\n  // Subscribe all plugins to other emitting plugins\n  var subscribePlugins = function(next) {\n    // events broadcasted by plugins\n    var pluginSubscriptions = _.filter(\n      subscriptions,\n      sub => sub.emitter !== 'market'\n    );\n\n    // some events can be broadcasted by different\n    // plugins, however the pipeline only allows a single\n    // emitting plugin for each event to be enabled.\n    _.each(\n      pluginSubscriptions.filter(s => _.isArray(s.emitter)),\n      subscription => {\n        // cache full list\n        subscription.emitters = subscription.emitter;\n        var singleEventEmitters = subscription.emitter\n          .filter(\n            s => _.size(plugins.filter(p => p.meta.slug === s))\n          );\n\n        if(_.size(singleEventEmitters) > 1) {\n          var error = `Multiple plugins are broadcasting`;\n          error += ` the event \"${subscription.event}\" (${singleEventEmitters.join(',')}).`;\n          error += 'This is unsupported.'\n          util.die(error);\n        } else {\n          subscription.emitter = _.first(singleEventEmitters);\n        }\n      }\n    );\n\n    // subscribe interested plugins to\n    // emitting plugins\n    _.each(plugins, function(plugin) {\n      _.each(pluginSubscriptions, function(sub) {\n\n        if(plugin[sub.handler]) {\n          // if a plugin wants to listen\n          // to something disabled\n          if(!emitters[sub.emitter]) {\n            if(!plugin.meta.greedy) {\n\n              let emitterMessage;\n              if(sub.emitters) {\n                emitterMessage = 'all of the emitting plugins [ ';\n                emitterMessage += sub.emitters.join(', ');\n                emitterMessage += ' ] are disabled.';\n              } else {\n                emitterMessage += 'the emitting plugin (' + sub.emitter;\n                emitterMessage += ')is disabled.'\n              }\n\n              log.error([\n                plugin.meta.name,\n                'wanted to listen to event',\n                sub.event + ',',\n                'however',\n                emitterMessage,\n                plugin.meta.name + ' might malfunction because of it.'\n              ].join(' '));\n            }\n            return;\n          }\n\n          // attach handler\n          emitters[sub.emitter]\n            .on(sub.event,\n              plugin[\n                sub.handler\n              ])\n        }\n\n      });\n    });\n\n    // events broadcasted by the market\n    var marketSubscriptions = _.filter(\n      subscriptions,\n      {emitter: 'market'}\n    );\n\n    // subscribe plugins to the market\n    _.each(plugins, function(plugin) {\n      _.each(marketSubscriptions, function(sub) {\n\n        if(plugin[sub.handler]) {\n          if(sub.event === 'candle')\n            candleConsumers.push(plugin);\n        }\n\n      });\n    });\n\n    next();\n  }\n\n  var prepareMarket = function(next) {\n    if(mode === 'backtest' && config.backtest.daterange === 'scan')\n      require(dirs.core + 'prepareDateRange')(next);\n    else\n      next();\n  }\n\n  var setupMarket = function(next) {\n    // load a market based on the config (or fallback to mode)\n    let marketType;\n    if(config.market)\n      marketType = config.market.type;\n    else\n      marketType = mode;\n\n    var Market = require(dirs.markets + marketType);\n\n    market = new Market(config);\n\n    next();\n  }\n\n  var subscribePluginsToMarket = function(next) {\n\n    // events broadcasted by the market\n    var marketSubscriptions = _.filter(\n      subscriptions,\n      {emitter: 'market'}\n    );\n\n    _.each(plugins, function(plugin) {\n      _.each(marketSubscriptions, function(sub) {\n\n        if(sub.event === 'candle')\n          // these are handled via the market stream\n          return;\n\n        if(plugin[sub.handler]) {\n          market.on(sub.event, plugin[sub.handler]);\n        }\n\n      });\n    });\n\n    next();\n\n  }\n\n  log.info('Setting up Gekko in', mode, 'mode');\n  log.info('');\n\n  async.series(\n    [\n      loadPlugins,\n      referenceEmitters,\n      subscribePlugins,\n      prepareMarket,\n      setupMarket,\n      subscribePluginsToMarket\n    ],\n    function() {\n\n      var gekkoStream = new GekkoStream(plugins);\n\n      market\n        .pipe(gekkoStream)\n\n        // convert JS objects to JSON string\n        // .pipe(new require('stringify-stream')())\n        // output to standard out\n        // .pipe(process.stdout);\n\n      market.on('end', gekkoStream.finalize);\n    }\n  );\n\n}\n\nmodule.exports = pipeline;"
  },
  {
    "path": "core/pluginUtil.js",
    "content": "var _ = require('lodash');\nvar async = require('async');\nvar Emitter = require('./emitter');\n\nvar util = require(__dirname + '/util');\n\nvar log = require(util.dirs().core + 'log');\n\nvar config = util.getConfig();\nvar pluginDir = util.dirs().plugins;\nvar gekkoMode = util.gekkoMode();\nvar inherits = require('util').inherits;\n\nvar pluginHelper = {\n  // Checks whether we can load a module\n\n  // @param Object plugin\n  //    plugin config object\n  // @return String\n  //    error message if we can't\n  //    use the module.\n  cannotLoad: function(plugin) {\n\n    // verify plugin dependencies are installed\n    if(_.has(plugin, 'dependencies'))\n      var error = false;\n\n      _.each(plugin.dependencies, function(dep) {\n        try {\n          var a = require(dep.module);\n        }\n        catch(e) {\n          log.error('ERROR LOADING DEPENDENCY', dep.module);\n\n          if(!e.message) {\n            log.error(e);\n            util.die();\n          }\n\n          if(!e.message.startsWith('Cannot find module'))\n            return util.die(e);\n\n          error = [\n            'The plugin',\n            plugin.slug,\n            'expects the module',\n            dep.module,\n            'to be installed.',\n            'However it is not, install',\n            'it by running: \\n\\n',\n            '\\tnpm install',\n            dep.module + '@' + dep.version\n          ].join(' ');\n        }\n      });\n\n    return error;\n  },\n  // loads a plugin\n  // \n  // @param Object plugin\n  //    plugin config object\n  // @param Function next\n  //    callback\n  load: function(plugin, next) {\n\n    plugin.config = config[plugin.slug];\n\n    if(!plugin.config || !plugin.config.enabled)\n      return next();\n\n    if(!_.contains(plugin.modes, gekkoMode)) {\n      log.warn(\n        'The plugin',\n        plugin.name,\n        'does not support the mode',\n        gekkoMode + '.',\n        'It has been disabled.'\n      )\n      return next();\n    }\n\n    log.info('Setting up:');\n    log.info('\\t', plugin.name);\n    log.info('\\t', plugin.description);\n\n    var cannotLoad = pluginHelper.cannotLoad(plugin);\n    if(cannotLoad)\n      return next(cannotLoad);\n\n    if(plugin.path)\n      var Constructor = require(pluginDir + plugin.path(config));\n    else\n      var Constructor = require(pluginDir + plugin.slug);\n\n    if(plugin.async) {\n      inherits(Constructor, Emitter);\n      var instance = new Constructor(util.defer(function(err) {\n        next(err, instance);\n      }), plugin);\n      Emitter.call(instance);\n\n      instance.meta = plugin;\n    } else {\n      inherits(Constructor, Emitter);\n      var instance = new Constructor(plugin);\n      Emitter.call(instance);\n\n      instance.meta = plugin;\n      _.defer(function() {\n        next(null, instance); \n      });\n    }\n\n    if(!plugin.silent)\n      log.info('\\n');\n  }\n}\n\nmodule.exports = pluginHelper;"
  },
  {
    "path": "core/prepareDateRange.js",
    "content": "var _ = require('lodash');\nvar prompt = require('prompt-lite');\nvar moment = require('moment');\n\nvar util = require('./util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + 'log');\n\nvar scan = require(dirs.tools + 'dateRangeScanner');\n\n// helper to store the evenutally detected\n// daterange.\nvar setDateRange = function(from, to) {\n  config.backtest.daterange = {\n    from: moment.unix(from).utc().format(),\n    to: moment.unix(to).utc().format(),\n  };\n  util.setConfig(config);\n}\n\n\nmodule.exports = function(done) {\n  scan((err, ranges) => {\n\n    if(_.size(ranges) === 0)\n      util.die('No history found for this market', true);\n\n    if(_.size(ranges) === 1) {\n      var r = _.first(ranges);\n      log.info('Gekko was able to find a single daterange in the locally stored history:');\n      log.info('\\t', 'from:', moment.unix(r.from).utc().format('YYYY-MM-DD HH:mm:ss'));\n      log.info('\\t', 'to:', moment.unix(r.to).utc().format('YYYY-MM-DD HH:mm:ss'));\n\n      \n      setDateRange(r.from, r.to);\n      return done();\n    }\n\n    log.info(\n      'Gekko detected multiple dateranges in the locally stored history.',\n      'Please pick the daterange you are interested in testing:'\n    );\n\n    _.each(ranges, (range, i) => {\n      log.info('\\t\\t', `OPTION ${i + 1}:`);\n      log.info('\\t', 'from:', moment.unix(range.from).utc().format('YYYY-MM-DD HH:mm:ss'));\n      log.info('\\t', 'to:', moment.unix(range.to).utc().format('YYYY-MM-DD HH:mm:ss'));\n    });\n\n    prompt.get({name: 'option'}, (err, result) => {\n\n      var option = parseInt(result.option);\n      if(option === NaN)\n        util.die('Not an option..', true);\n\n      var range = ranges[option - 1];\n\n      if(!range)\n        util.die('Not an option..', true);\n\n      setDateRange(range.from, range.to);\n      return done();\n    });\n\n  });\n}"
  },
  {
    "path": "core/stats.js",
    "content": "const stats = require('stats-lite');\nconst lodash = require('lodash');\n\n\n// simply monkey patch the stats with other stuff we\n// need and pass on.\n\n// sharpe ratio\n//\n// @param returns (array - list of returns)\n// @param rfreturn (number - risk free return)\n// \nstats.sharpe = (returns, rfreturn) => {\n  return (stats.mean(returns) - rfreturn) / stats.stdev(returns);\n}\n\nmodule.exports = stats;\n"
  },
  {
    "path": "core/talib.js",
    "content": "var semver = require(\"semver\");\nvar _ = require('lodash');\n\n// validate that talib is installed, if not we'll throw an exception which will\n// prevent further loading or out outside this module\ntry {\n    var talib = require(\"talib\");\n} catch (e) {\n    module.exports = null;\n    return;\n}\n\nvar talibError = 'Gekko was unable to configure talib indicator:\\n\\t';\nvar talibGTEv103 = semver.gte(talib.version, '1.0.3');\n\n// Wrapper that executes a talib indicator\nvar execute = function(callback, params) {\n    // talib callback style since talib-v1.0.3\n    var talibCallback = function(err, result) {\n        if(err) return callback(err);\n        callback(null, result.result);\n    };\n\n    // talib legacy callback style before talib-v1.0.3\n    var talibLegacyCallback = function(result) {\n        var error = result.error;\n        talibCallback.apply(this, [error, result]);\n    };\n\n    return talib.execute(params, talibGTEv103 ? talibCallback : talibLegacyCallback);\n}\n\n// Helper that makes sure all required parameters\n// for a specific talib indicator are present.\nvar verifyParams = (methodName, params) => {\n    var requiredParams = methods[methodName].requires;\n\n    _.each(requiredParams, paramName => {\n        if(!_.has(params, paramName)) {\n            throw new Error(talibError + methodName + ' requires ' + paramName + '.');\n        }\n\n        var val = params[paramName];\n\n        if(!_.isNumber(val)) {\n            throw new Error(talibError + paramName + ' needs to be a number');\n        }\n    });\n}\n\nvar methods = {};\n\n\n//////////////////////////////Pattern Recognition//////////////////////////////\nmethods.cdl2crows = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl2crows', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL2CROWS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3blackcrows = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3blackcrows', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3BLACKCROWS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3inside = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3inside', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3INSIDE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3linestrike = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3linestrike', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3LINESTRIKE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3outside = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3outside', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3OUTSIDE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3starsinsouth = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3starsinsouth', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3STARSINSOUTH\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdl3whitesoldiers = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdl3whitesoldiers', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDL3WHITESOLDIERS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlabandonedbaby = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdlabandonedbaby', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLABANDONEDBABY\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdladvanceblock = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdladvanceblock', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLADVANCEBLOCK\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlbelthold = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlbelthold', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLBELTHOLD\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlbreakaway = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlbreakaway', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLBREAKAWAY\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlclosingmarubozu = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlclosingmarubozu', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLCLOSINGMARUBOZU\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlconcealbabyswall = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlconcealbabyswall', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLCONCEALBABYSWALL\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlcounterattack = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlcounterattack', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLCOUNTERATTACK\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdldarkcloudcover = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdldarkcloudcover', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLDARKCLOUDCOVER\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdldoji = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdldoji', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLDOJI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdldojistar = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdldojistar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLDOJISTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdldragonflydoji = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdldragonflydoji', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLDRAGONFLYDOJI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlengulfing = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlengulfing', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLENGULFING\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdleveningdojistar = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdleveningdojistar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLEVENINGDOJISTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdleveningstar = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdleveningstar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLEVENINGSTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdlgapsidesidewhite = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlgapsidesidewhite', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLGAPSIDESIDEWHITE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlgravestonedoji = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlgravestonedoji', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLGRAVESTONEDOJI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhammer = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhammer', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHAMMER\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhangingman = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhangingman', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHANGINGMAN\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlharami = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlharami', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHARAMI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlharamicross = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlharamicross', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHARAMICROSS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhighwave = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhighwave', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHIGHWAVE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhikkake = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhikkake', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHIKKAKE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhikkakemod = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhikkakemod', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHIKKAKEMOD\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlhomingpigeon = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlhomingpigeon', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLHOMINGPIGEON\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlidentical3crows = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlidentical3crows', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLIDENTICAL3CROWS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlinneck = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlinneck', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLINNECK\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlinvertedhammer = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlinvertedhammer', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLINVERTEDHAMMER\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlkicking = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlkicking', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLKICKING\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlkickingbylength = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlkickingbylength', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLKICKINGBYLENGTH\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlladderbottom = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlladderbottom', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLLADDERBOTTOM\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdllongleggeddoji = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdllongleggeddoji', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLLONGLEGGEDDOJI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdllongline = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdllongline', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLLONGLINE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlmarubozu = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlmarubozu', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLMARUBOZU\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlmatchinglow = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlmatchinglow', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLMATCHINGLOW\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlmathold = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdlmathold', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLMATHOLD\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdlmorningdojistar = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdlmorningdojistar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLMORNINGDOJISTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdlmorningstar = {\n    requires: ['optInPenetration'],\n    create: (params) => {\n        verifyParams('cdlmorningstar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLMORNINGSTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            optInPenetration: params.optInPenetration\n        });\n    }\n}\nmethods.cdlonneck = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlonneck', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLONNECK\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlpiercing = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlpiercing', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLPIERCING\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlrickshawman = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlrickshawman', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLRICKSHAWMAN\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlrisefall3methods = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlrisefall3methods', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLRISEFALL3METHODS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlseparatinglines = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlseparatinglines', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSEPARATINGLINES\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlshootingstar = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlshootingstar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSHOOTINGSTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlshortline = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlshortline', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSHORTLINE\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlspinningtop = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlspinningtop', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSPINNINGTOP\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlstalledpattern = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlstalledpattern', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSTALLEDPATTERN\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlsticksandwich = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlsticksandwich', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLSTICKSANDWICH\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdltakuri = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdltakuri', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLTAKURI\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdltasukigap = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdltasukigap', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLTASUKIGAP\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlthrusting = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlthrusting', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLTHRUSTING\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdltristar = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdltristar', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLTRISTAR\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlunique3river = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlunique3river', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLUNIQUE3RIVER\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlupsidegap2crows = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlupsidegap2crows', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLUPSIDEGAP2CROWS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\nmethods.cdlxsidegap3methods = {\n    requires: [],\n    create: (params) => {\n        verifyParams('cdlxsidegap3methods', params);\n        return (data, callback) => execute(callback, {\n            name: \"CDLXSIDEGAP3METHODS\",\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close\n        });\n    }\n}\n\n//////////////////////////////Pattern Recognition//////////////////////////////\n\nmethods.accbands = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('accbands', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ACCBANDS\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ad = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('accbands', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"AD\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            volume: data.volume,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.adosc = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('adosc', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ADOSC\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            volume: data.volume,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInFastPeriod: params.optInFastPeriod,\n            optInSlowPeriod: params.optInSlowPeriod\n        });\n    }\n}\n\nmethods.adx = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('adx', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ADX\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.adxr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('adxr', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ADXR\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.apo = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod', 'optInMAType'],\n    create: (params) => {\n        verifyParams('apo', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"APO\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.length - 1,\n            optInFastPeriod: params.optInFastPeriod,\n            optInSlowPeriod: params.optInSlowPeriod,\n            optInMAType: params.optInMAType\n        });\n    }\n}\n\nmethods.aroon = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('aroon', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"AROON\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.aroonosc = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('aroonosc', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"AROONOSC\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.atr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('atr', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ATR\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.avgprice = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('avgprice', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"AVGPRICE\",\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.open.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.bbands = {\n    requires: ['optInTimePeriod', 'optInNbDevUp', 'optInNbDevDn', 'optInMAType'],\n    create: (params) => {\n        verifyParams('bbands', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"BBANDS\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod,\n            optInNbDevUp: params.optInNbDevUp,\n            optInNbDevDn: params.optInNbDevDn,\n            optInMAType: params.optInMAType\n        });\n    }\n}\n\n///////////////////////////////////////////////////////////////\n\n\n// this.beta = function(data_0, data_1, period) {\n//     return talibWrapper({\n//         name: \"BETA\",\n//         inReal0: data_0,\n//         inReal1: data_1,\n//         startIdx: 0,\n//         endIdx: data_0.length - 1,\n//         optInTimePeriod: period\n//     });\n// };\n\nmethods.bop = {\n    requires: [],\n    create: (params) => {\n        verifyParams('bop', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"BOP\",\n            open: data.open,\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1\n        });\n    }\n}\n\nmethods.cci = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('cci', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"CCI\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.cmo = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('cmo', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"CMO\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\n// this.correl = function(data_0, data_1, period) {\n//     return talibWrapper({\n//         name: \"CORREL\",\n//         inReal0: data_0,\n//         inReal1: data_1,\n//         startIdx: 0,\n//         endIdx: data_0.length - 1,\n//         optInTimePeriod: period\n//     });\n// };\n\nmethods.dema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dema', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"DEMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.dx = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dx', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"DX\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('ema', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"EMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ht_dcperiod = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_dcperiod', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_DCPERIOD\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.ht_dcphase = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_dcphase', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_DCPHASE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.ht_phasor = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_phasor', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_PHASOR\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.ht_sine = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_sine', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_SINE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\n\nmethods.ht_trendline = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_trendline', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_TRENDLINE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.ht_trendmode = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ht_trendmode', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"HT_TRENDMODE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.imi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('imi', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"IMI\",\n            open: data.open,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.open.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.kama = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('kama', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"KAMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.linearreg = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linearreg', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"LINEARREG\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.linearreg_angle = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linearreg_angle', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"LINEARREG_ANGLE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.linearreg_intercept = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linearreg_intercept', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"LINEARREG_INTERCEPT\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.linearreg_slope = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linearreg_slope', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"LINEARREG_SLOPE\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ma = {\n    requires: ['optInTimePeriod', 'optInMAType'],\n    create: (params) => {\n        verifyParams('ma', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod,\n            optInMAType: params.optInMAType\n        });\n    }\n}\n\nmethods.macd = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod', 'optInSignalPeriod'],\n    create: (params) => {\n        verifyParams('macd', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MACD\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInFastPeriod: params.optInFastPeriod,\n            optInSlowPeriod: params.optInSlowPeriod,\n            optInSignalPeriod: params.optInSignalPeriod\n        });\n    }\n}\n\nmethods.macdext = {\n    requires: [\n        'optInFastPeriod',\n        'optInFastMAType',\n        'optInSlowPeriod',\n        'optInSlowMAType',\n        'optInSignalPeriod',\n        'optInSignalMAType'\n    ],\n    create: (params) => {\n        verifyParams('macdext', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MACDEXT\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInFastPeriod: params.optInFastPeriod,\n            optInFastMAType: params.optInFastMAType,\n            optInSlowPeriod: params.optInSlowPeriod,\n            optInSlowMAType: params.optInSlowMAType,\n            optInSignalPeriod: params.optInSignalPeriod,\n            optInSignalMAType: params.optInSignalMAType\n        });\n    }\n}\n\nmethods.macdfix = {\n    requires: ['optInSignalPeriod'],\n    create: (params) => {\n        verifyParams('macdfix', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MACDFIX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInSignalPeriod: params.optInSignalPeriod\n        });\n    }\n}\n\nmethods.mama = {\n    requires: ['optInFastLimit', 'optInSlowLimit'],\n    create: (params) => {\n        verifyParams('mama', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MAMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInFastLimit: params.optInFastLimit,\n            optInSlowLimit: params.optInSlowLimit\n        });\n    }\n}\n\nmethods.mavp = {\n    requires: ['inPeriods', 'optInMinPeriod', 'optInMaxPeriod', 'optInMAType'],\n    create: (params) => {\n        verifyParams('mavp', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MAVP\",\n            inReal: data.close,\n            inPeriods: params.inPeriods,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInMinPeriod: params.optInMinPeriod,\n            optInMaxPeriod: params.optInMaxPeriod,\n            optInMAType: params.optInMAType\n        });\n    }\n}\n\n\nmethods.max = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('max', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MAX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\n\nmethods.maxindex = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('maxindex', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MAXINDEX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.medprice = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('medprice', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MEDPRICE\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.mfi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('mfi', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MFI\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            volume: data.volume,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.midpoint = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('midpoint', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MIDPOINT\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.midprice = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('midprice', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MIDPRICE\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.min = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('min', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MIN\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.minindex = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('minindex', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MININDEX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.minmax = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('minmax', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MINMAX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.minmaxindex = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('minmaxindex', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MINMAXINDEX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.minus_di = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('minus_di', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MINUS_DI\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.minus_dm = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('minus_dm', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MINUS_DM\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.mom = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('mom', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"MOM\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.natr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('natr', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"NATR\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.obv = {\n    requires: [],\n    create: (params) => {\n        verifyParams('obv', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"OBV\",\n            inReal: data.close,\n            volume: data.volume,\n            startIdx: 0,\n            endIdx: data.close.length - 1\n        });\n    }\n}\n\nmethods.plus_di = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('plus_di', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"PLUS_DI\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.plus_dm = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('plus_dm', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"PLUS_DM\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ppo = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod', 'optInMAType'],\n    create: (params) => {\n        verifyParams('ppo', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"PPO\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInFastPeriod: params.optInFastPeriod,\n            optInSlowPeriod: params.optInSlowPeriod,\n            optInMAType: params.optInMAType\n        });\n    }\n}\n\nmethods.roc = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('roc', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ROC\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.rocp = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rocp', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ROCP\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.rocr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rocr', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ROCR\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.rocr100 = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rocr100', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ROCR100\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.rsi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rsi', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"RSI\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.sar = {\n    requires: ['optInAcceleration', 'optInMaximum'],\n    create: (params) => {\n        verifyParams('sar', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"SAR\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInAcceleration: params.optInAcceleration,\n            optInMaximum: params.optInMaximum\n        });\n    }\n}\n\nmethods.sarext = {\n    requires: [\n        'optInStartValue',\n        'optInOffsetOnReverse',\n        'optInAccelerationInitLong',\n        'optInAccelerationLong',\n        'optInAccelerationMaxLong',\n        'optInAccelerationInitShort',\n        'optInAccelerationShort',\n        'optInAccelerationMaxShort'\n\n    ],\n    create: (params) => {\n        verifyParams('sarext', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"SAREXT\",\n            high: data.high,\n            low: data.low,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n\n            optInStartValue: params.optInStartValue,\n            optInOffsetOnReverse: params.optInOffsetOnReverse,\n            optInAccelerationInitLong: params.optInAccelerationInitLong,\n            optInAccelerationLong: params.optInAccelerationLong,\n            optInAccelerationMaxLong: params.optInAccelerationMaxLong,\n            optInAccelerationInitShort: params.optInAccelerationInitShort,\n            optInAccelerationShort: params.optInAccelerationShort,\n            optInAccelerationMaxShort: params.optInAccelerationMaxShort\n        });\n    }\n}\n\nmethods.sma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('sma', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"SMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.stddev = {\n    requires: ['optInTimePeriod', 'optInNbDev'],\n    create: (params) => {\n        verifyParams('stddev', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"STDDEV\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod,\n            optInNbDev: params.optInNbDev\n        });\n    }\n}\n\nmethods.stoch = {\n    requires: [\n        'optInFastK_Period',\n        'optInSlowK_Period',\n        'optInSlowK_MAType',\n        'optInSlowD_Period',\n        'optInSlowD_MAType'\n    ],\n    create: (params) => {\n        verifyParams('stoch', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"STOCH\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n\n            optInFastK_Period: params.optInFastK_Period,\n            optInSlowK_Period: params.optInSlowK_Period,\n            optInSlowK_MAType: params.optInSlowK_MAType,\n            optInSlowD_Period: params.optInSlowD_Period,\n            optInSlowD_MAType: params.optInSlowD_MAType\n        });\n    }\n}\n\n\nmethods.stochf = {\n    requires: [\n        'optInFastK_Period',\n        'optInFastD_Period',\n        'optInFastD_MAType'\n    ],\n    create: (params) => {\n        verifyParams('stochf', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"STOCHF\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n\n            optInFastK_Period: params.optInFastK_Period,\n            optInFastD_Period: params.optInFastD_Period,\n            optInFastD_MAType: params.optInFastD_MAType\n        });\n    }\n}\n\nmethods.stochrsi = {\n    requires: [\n        'optInTimePeriod',\n        'optInFastK_Period',\n        'optInFastD_Period',\n        'optInFastD_MAType'\n    ],\n    create: (params) => {\n        verifyParams('stochrsi', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"STOCHRSI\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n\n            optInTimePeriod: params.optInTimePeriod,\n            optInFastK_Period: params.optInFastK_Period,\n            optInFastD_Period: params.optInFastD_Period,\n            optInFastD_MAType: params.optInFastD_MAType\n        });\n    }\n}\n\nmethods.t3 = {\n    requires: [\n        'optInTimePeriod',\n        'optInFastK_Period',\n        'optInFastD_Period',\n        'optInFastD_MAType'\n    ],\n    create: (params) => {\n        verifyParams('t3', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"T3\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod,\n            optInVFactor: params.optInVFactor\n        });\n    }\n}\n\nmethods.tema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('tema', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TEMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.trange = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('trange', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TRANGE\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.trima = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('trima', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TRIMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.trix = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('trix', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TRIX\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.tsf = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('tsf', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TSF\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.typprice = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('typprice', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"TYPPRICE\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.ultosc = {\n    requires: ['optInTimePeriod1', 'optInTimePeriod2', 'optInTimePeriod3'],\n    create: (params) => {\n        verifyParams('ultosc', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"ULTOSC\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod1: params.optInTimePeriod1,\n            optInTimePeriod2: params.optInTimePeriod2,\n            optInTimePeriod3: params.optInTimePeriod3\n        });\n    }\n}\n\nmethods.variance = {\n    requires: ['optInTimePeriod', 'optInNbDev'],\n    create: (params) => {\n        verifyParams('variance', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"VAR\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod,\n            optInNbDev: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.wclprice = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('wclprice', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"WCLPRICE\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.willr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('willr', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"WILLR\",\n            high: data.high,\n            low: data.low,\n            close: data.close,\n            startIdx: 0,\n            endIdx: data.high.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmethods.wma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('wma', params);\n\n        return (data, callback) => execute(callback, {\n            name: \"WMA\",\n            inReal: data.close,\n            startIdx: 0,\n            endIdx: data.close.length - 1,\n            optInTimePeriod: params.optInTimePeriod\n        });\n    }\n}\n\nmodule.exports = methods;\n\n"
  },
  {
    "path": "core/tools/candleLoader.js",
    "content": "// TODO: properly handle a daterange for which no data is available.\n\nconst batchSize = 1000;\n\nconst _ = require('lodash');\nconst fs = require('fs');\nconst moment = require('moment');\n\nconst util = require('../../core/util');\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst log = require(dirs.core + '/log');\n\nconst adapter = config[config.adapter];\nconst Reader = require(dirs.gekko + adapter.path + '/reader');\nconst daterange = config.daterange;\n\nconst CandleBatcher = require(dirs.core + 'candleBatcher');\n\nconst to = moment.utc(daterange.to).startOf('minute');\nconst from = moment.utc(daterange.from).startOf('minute');\nconst toUnix = to.unix();\n\nif(to <= from)\n  util.die('This daterange does not make sense.')\n\nif(!from.isValid())\n  util.die('invalid `from`');\n\nif(!to.isValid())\n  util.die('invalid `to`');\n\nlet iterator = {\n  from: from.clone(),\n  to: from.clone().add(batchSize, 'm').subtract(1, 's')\n}\n\nvar DONE = false;\n\nvar result = [];\nvar reader = new Reader();\nvar batcher;\nvar next;\nvar doneFn = () => {\n  process.nextTick(() => {\n    next(result);\n  })\n};\n\nmodule.exports = function(candleSize, _next) {\n  next = _.once(_next);\n\n  batcher = new CandleBatcher(candleSize)\n    .on('candle', handleBatchedCandles);\n\n  getBatch();\n}\n\nconst getBatch = () => {\n  reader.get(\n    iterator.from.unix(),\n    iterator.to.unix(),\n    'full',\n    handleCandles\n  )\n}\n\nconst shiftIterator = () => {\n  iterator = {\n    from: iterator.from.clone().add(batchSize, 'm'),\n    to: iterator.from.clone().add(batchSize * 2, 'm').subtract(1, 's')\n  }\n}\n\nconst handleCandles = (err, data) => {\n  if(err) {\n    console.error(err);\n    util.die('Encountered an error..')\n  }\n\n  if(_.size(data) && _.last(data).start >= toUnix || iterator.from.unix() >= toUnix)\n    DONE = true;\n\n  batcher.write(data);\n  batcher.flush();\n\n  if(DONE) {\n    reader.close();\n\n    setTimeout(doneFn, 100);\n\n  } else {\n    shiftIterator();\n    getBatch();\n  }\n}\n\nconst handleBatchedCandles = candle => {\n  result.push(candle);\n}\n"
  },
  {
    "path": "core/tools/configBuilder.js",
    "content": "const fs = require('fs');\nconst _ = require('lodash');\nconst toml = require('toml');\n\nconst util = require('../util');\nconst dirs = util.dirs();\n\nconst getTOML = function(fileName) {\n  var raw = fs.readFileSync(fileName);\n  return toml.parse(raw);\n}\n\n// build a config object out of a directory of TOML files\nmodule.exports = function() {\n  const configDir = util.dirs().config;\n\n  let _config = getTOML(configDir + 'general.toml');\n  fs.readdirSync(configDir + 'plugins').forEach(function(pluginFile) {\n    let pluginName = _.first(pluginFile.split('.'))\n    _config[pluginName] = getTOML(configDir + 'plugins/' + pluginFile);\n  });\n\n  // attach the proper adapter\n  let adapter = _config.adapter;\n  _config[adapter] = getTOML(configDir + 'adapters/' + adapter + '.toml');\n\n  if(_config.tradingAdvisor.enabled) {\n    // also load the strat\n    let strat = _config.tradingAdvisor.method;\n    let stratFile = configDir + 'strategies/' + strat + '.toml';\n    if(!fs.existsSync(stratFile))\n      util.die('Cannot find the strategy config file for ' + strat);\n    _config[strat] = getTOML(stratFile);\n  }\n\n  const mode = util.gekkoMode();\n\n  if(mode === 'backtest')\n    _config.backtest = getTOML(configDir + 'backtest.toml');\n\n  return _config;\n}"
  },
  {
    "path": "core/tools/dataStitcher.js",
    "content": "var _ = require('lodash');\nvar fs = require('fs');\nvar moment = require('moment');\n\nvar util = require('../util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + '/log');\n\nvar Stitcher = function(batcher) {\n  this.batcher = batcher;\n}\n\nStitcher.prototype.ago = function(ts) {\n  var now = moment().utc();\n  var then = moment.unix(ts).utc();\n  return now.diff(then, 'minutes') + ' minutes ago';\n}\n\nStitcher.prototype.verifyExchange = function() {\n  require(dirs.gekko + 'exchange/dependencyCheck');\n  const exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');\n  const slug = config.watch.exchange.toLowerCase();\n  let exchange;\n  try {\n    exchange = exchangeChecker.getExchangeCapabilities(slug);\n  } catch(e) {\n    util.die(e.message);\n  }\n\n  if(!exchange)\n    util.die(`Unsupported exchange: ${slug}`);\n\n  var error = exchangeChecker.cantMonitor(config.watch);\n  if(error)\n    util.die(error, true);\n}\n\nStitcher.prototype.prepareHistoricalData = function(done) {\n  this.verifyExchange();\n\n  // - step 1: check most recent stored candle window\n  // - step 2: check oldest trade reachable by API\n  // - step 3: see if overlap\n  // - step 4: feed candle stream into CandleBatcher\n\n  if(config.tradingAdvisor.historySize === 0)\n    return done();\n\n  var requiredHistory = config.tradingAdvisor.candleSize * config.tradingAdvisor.historySize;\n  var Reader = require(dirs.plugins + config.adapter + '/reader');\n  \n  this.reader = new Reader;\n\n  log.info(\n    '\\tThe trading method requests',\n    requiredHistory,\n    'minutes of historic data. Checking availablity..'\n  );\n\n  var endTime = moment().utc().startOf('minute');\n  var idealStartTime = endTime.clone().subtract(requiredHistory, 'm');\n  \n  this.reader.mostRecentWindow(idealStartTime, endTime, function(localData) {\n    // now we know what data is locally available, what\n    // data would we need from the exchange?\n    \n    if(!localData) {\n      log.info('\\tNo usable local data available, trying to get as much as possible from the exchange..');\n      var idealExchangeStartTime = idealStartTime.clone();\n      var idealExchangeStartTimeTS = idealExchangeStartTime.unix();\n    }\n    else if (idealStartTime.unix() < localData.from) {\n      log.info('\\tLocal data is still too recent, trying to get as much as possible from the exchange');\n      var idealExchangeStartTime = idealStartTime.clone();\n      var idealExchangeStartTimeTS = idealExchangeStartTime.unix();\n    }\n    else {\n      log.debug('\\tAvailable local data:');\n      log.debug('\\t\\tfrom:', this.ago(localData.from));\n      log.debug('\\t\\tto:', this.ago(localData.to));\n\n      log.info('\\tUsable local data available, trying to match with exchange data..')\n      // local data is available, we need the next minute\n\n\n      // make sure we grab back in history far enough\n      var secondsOverlap = 60 * 15; // 15 minutes\n      var idealExchangeStartTimeTS = localData.to - secondsOverlap;\n      var idealExchangeStartTime = moment.unix(idealExchangeStartTimeTS).utc();\n\n      // already set the\n      util.setConfigProperty(\n        'tradingAdvisor',\n        'firstFetchSince',\n        idealExchangeStartTimeTS\n      );\n    }\n\n    // Limit the history Gekko can try to get from the exchange.\n    var minutesAgo = endTime.diff(idealExchangeStartTime, 'minutes');\n    var maxMinutesAgo = 4 * 60; // 4 hours\n    if(minutesAgo > maxMinutesAgo) {\n      log.info('\\tPreventing Gekko from requesting', minutesAgo, 'minutes of history.');\n      idealExchangeStartTime = endTime.clone().subtract(maxMinutesAgo, 'minutes');\n      idealExchangeStartTimeTS = idealExchangeStartTime.unix();\n    } \n\n    log.debug('\\tFetching exchange data since', this.ago(idealExchangeStartTimeTS))\n    this.checkExchangeTrades(idealExchangeStartTime, function(err, exchangeData) {\n      log.debug('\\tAvailable exchange data:');\n      log.debug('\\t\\tfrom:', this.ago(exchangeData.from));\n      log.debug('\\t\\tto:', this.ago(exchangeData.to));\n\n      // in case we have limited local data, and the\n      // exchange would offer more than we have: ignore\n      // the local data..\n      if(\n        localData &&\n        exchangeData &&\n        exchangeData.from < localData.from\n      ) {\n        log.debug('\\tExchange offered more data than locally available. Ignoring local data');\n        localData = false;\n      }\n\n      var stitchable = localData && exchangeData.from <= localData.to;\n      if(stitchable) {\n        log.debug('\\tStitching datasets');\n\n        // we can combine local data with exchange data\n        if(idealStartTime.unix() >= localData.from) {\n          log.info(\n            '\\tFull history locally available.',\n            'Seeding the trading method with all required historical candles.'\n          );\n\n        } else {\n\n          // stitchable but not enough\n\n          log.info(\n            '\\tPartial history locally available, but',\n            Math.round((localData.from - idealStartTime.unix()) / 60),\n            'minutes are missing.')\n          log.info('\\tSeeding the trading method with',\n            'partial historical data (Gekko needs more time before',\n            'it can give advice).'\n          );\n        }\n\n        // seed all historic data up to the point the exchange can provide.\n        var from = localData.from;\n        var to = moment.unix(exchangeData.from).utc()\n          .startOf('minute')\n          .subtract(1, 'minute')\n          .unix();\n\n        log.debug('\\tSeeding with:');\n        log.debug('\\t\\tfrom:', this.ago(from));\n        log.debug('\\t\\tto:', this.ago(to));\n        return this.seedLocalData(from, to, done);\n\n      } else if(!stitchable) {\n        log.debug('\\tUnable to stitch datasets.')\n        // we cannot use any local data..\n        log.info(\n          '\\tNot seeding locally available data to the trading method.'\n        );\n\n        if(exchangeData.from < idealExchangeStartTimeTS) {\n          log.info('\\tHowever the exchange returned enough data anyway!');\n        } else if(localData) {\n          log.info(\n            '\\tThe exchange does not return enough data.',\n            Math.round((localData.from - idealStartTime.unix()) / 60),\n            'minutes are still missing.'\n          );\n        }\n      }\n\n      done();\n\n    }.bind(this));\n  }.bind(this));\n}\n\nStitcher.prototype.checkExchangeTrades = function(since, next) {\n  var provider = config.watch.exchange.toLowerCase();\n  var DataProvider = require(util.dirs().gekko + 'exchange/wrappers/' + provider);\n\n  var exchangeConfig = config.watch;\n\n  // include trader config if trading is enabled\n  if (_.isObject(config.trader) && config.trader.enabled) {\n    exchangeConfig = _.extend(config.watch, config.trader);\n  }\n\n  var watcher = new DataProvider(exchangeConfig);\n  watcher.getTrades(since, function(e, d) {\n    if(e) {\n      util.die(e.message);\n    }\n\n    if(_.isEmpty(d))\n      return util.die(\n        `Gekko tried to retrieve data since ${since.format('YYYY-MM-DD HH:mm:ss')}, however\n        ${provider} did not return any trades.`\n      );\n\n    next(e, {\n      from: _.first(d).date,\n      to: _.last(d).date\n    })\n  });\n}\n\nStitcher.prototype.seedLocalData = function(from, to, next) {\n  this.reader.get(from, to, 'full', function(err, rows) {\n    rows = _.map(rows, row => {\n      row.start = moment.unix(row.start);\n      return row;\n    });\n\n    this.batcher.write(rows);\n    this.batcher.flush();\n    this.reader.close();\n    next();\n\n  }.bind(this));\n}\n\nmodule.exports = Stitcher;\n"
  },
  {
    "path": "core/tools/dateRangeScanner.js",
    "content": "var BATCH_SIZE = 60; // minutes\nvar MISSING_CANDLES_ALLOWED = 3; // minutes, per batch\n\nvar _ = require('lodash');\nvar moment = require('moment');\nvar async = require('async');\n\nvar util = require('../util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + 'log');\n\nvar adapter = config[config.adapter];\nvar Reader = require(dirs.gekko + adapter.path + '/reader');\n\nvar reader = new Reader();\n\n// todo: rewrite with generators or async/await..\nvar scan = function(done) {\n  log.info('Scanning local history for backtestable dateranges.');\n\n  reader.tableExists('candles', (err, exists) => {\n\n    if(err)\n      return done(err, null, reader);\n\n    if(!exists)\n      return done(null, [], reader);\n\n    async.parallel({\n      boundry: reader.getBoundry,\n      available: reader.countTotal\n    }, (err, res) => {\n\n      var first = res.boundry.first;\n      var last = res.boundry.last;\n\n      var optimal = (last - first) / 60;\n\n      log.debug('Available', res.available);\n      log.debug('Optimal', optimal);\n\n      // There is a candle for every minute\n      if(res.available === optimal + 1) {\n        log.info('Gekko is able to fully use the local history.');\n        return done(false, [{\n          from: first,\n          to: last\n        }], reader);\n      }\n\n      // figure out where the gaps are..\n\n      var missing = optimal - res.available + 1;\n\n      log.info(`The database has ${missing} candles missing, Figuring out which ones...`);\n      \n      var iterator = {\n        from: last - (BATCH_SIZE * 60),\n        to: last\n      }\n\n      var batches = [];\n\n      // loop through all candles we have\n      // in batches and track whether they\n      // are complete\n      async.whilst(\n          () => {\n            return iterator.from > first\n          },\n          next => {\n            var from = iterator.from;\n            var to = iterator.to;\n            reader.count(\n              from,\n              iterator.to,\n              (err, count) => {\n                var complete = count + MISSING_CANDLES_ALLOWED > BATCH_SIZE;\n\n                if(complete)\n                  batches.push({\n                    to: to,\n                    from: from\n                  });\n\n                next();\n              }\n            );\n\n            iterator.from -= BATCH_SIZE * 60;\n            iterator.to -= BATCH_SIZE * 60;\n          },\n          () => {\n            if(batches.length === 0) {\n              return done(null, [], reader);\n            }\n\n            // batches is now a list like\n            // [ {from: unix, to: unix } ]\n\n            var ranges = [ batches.shift() ];\n\n            _.each(batches, batch => {\n              var curRange = _.last(ranges);\n              if(batch.to === curRange.from)\n                curRange.from = batch.from;\n              else\n                ranges.push( batch );\n            })\n\n            // we have been counting chronologically reversed\n            // (backwards, from now into the past), flip definitions\n            ranges = ranges.reverse();\n\n            _.map(ranges, r => {\n              return {\n                from: r.to,\n                to: r.from\n              }\n            });\n\n\n            // ranges is now a list like\n            // [ {from: unix, to: unix } ]\n            //\n            // it contains all valid dataranges available for the\n            // end user.\n\n            return done(false, ranges, reader);\n          }\n        )\n    });\n\n  });\n}\n\nmodule.exports = scan;"
  },
  {
    "path": "core/tulind.js",
    "content": "var semver = require(\"semver\");\nvar _ = require('lodash');\n\n// validate that talib is installed, if not we'll throw an exception which will\n// prevent further loading or out outside this module\ntry {\n    var tulind = require(\"tulind\");\n} catch (e) {\n    module.exports = null;\n    return;\n}\n\nvar tulindError = 'Gekko was unable to configure Tulip Indicators:\\n\\t';\n\n// Wrapper that executes a tulip indicator\nvar execute = function(callback, params) {\n    var tulindCallback = function(err, result) {\n        if (err) return callback(err);\n        var table = {}\n        for (var i = 0; i < params.results.length; ++i) {\n            table[params.results[i]] = result[i];\n        }\n        callback(null, table);\n    };\n\n    return params.indicator.indicator(params.inputs, params.options, tulindCallback);\n}\n\n// Helper that makes sure all required parameters\n// for a specific talib indicator are present.\nvar verifyParams = (methodName, params) => {\n    var requiredParams = methods[methodName].requires;\n\n    _.each(requiredParams, paramName => {\n        if(!_.has(params, paramName)) {\n            throw new Error(tulindError + methodName + ' requires ' + paramName + '.');\n        }\n\n        var val = params[paramName];\n\n        if(!_.isNumber(val)) {\n            throw new Error(tulindError + paramName + ' needs to be a number');\n        }\n    });\n}\n\nvar methods = {};\n\nmethods.ad = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ad', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.ad,\n            inputs: [data.high, data.low, data.close, data.volume],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.adosc = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('adosc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.adosc,\n            inputs: [data.high, data.low, data.close, data.volume],\n            options: [params.optInFastPeriod, params.optInSlowPeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.adx = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('adx', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.adx,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.adxr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('adxr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.adxr,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.ao = {\n    requires: [],\n    create: (params) => {\n        verifyParams('ao', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.ao,\n            inputs: [data.high, data.low],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.apo = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('apo', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.apo,\n            inputs: [data.close],\n            options: [params.optInFastPeriod, params.optInSlowPeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.aroon = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('aroon', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.aroon,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['aroonDown', 'aroonUp'],\n        });\n    }\n}\n\nmethods.aroonosc = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('aroonosc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.aroonosc,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.atr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('atr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.atr,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.avgprice = {\n    requires: [],\n    create: (params) => {\n        verifyParams('avgprice', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.avgprice,\n            inputs: [data.open, data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.bbands = {\n    requires: ['optInTimePeriod', 'optInNbStdDevs'],\n    create: (params) => {\n        verifyParams('bbands', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.bbands,\n            inputs: [data.close],\n            options: [params.optInTimePeriod, params.optInNbStdDevs],\n            results: ['bbandsLower', 'bbandsMiddle', 'bbandsUpper'],\n        });\n    }\n}\n\nmethods.bop = {\n    requires: [],\n    create: (params) => {\n        verifyParams('bop', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.bop,\n            inputs: [data.open, data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.cci = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('cci', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.cci,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.cmo = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('cmo', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.cmo,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.cvi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('cvi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.cvi,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.dema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dema', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.dema,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.di = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('di', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.di,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['diPlus', 'diMinus'],\n        });\n    }\n}\n\nmethods.dm = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dm', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.dm,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['dmPlus', 'dmLow'],\n        });\n    }\n}\n\nmethods.dpo = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dpo', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.dpo,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.dx = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('dx', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.dx,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.ema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('ema', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.ema,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.emv = {\n    requires: [],\n    create: (params) => {\n        verifyParams('emv', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.emv,\n            inputs: [data.high, data.low, data.volume],\n            options: [params.optInTimePeriod],\n            results: [],\n        });\n    }\n}\n\nmethods.fisher = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('fisher', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.fisher,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['fisher', 'fisherPeriod'],\n        });\n    }\n}\n\nmethods.fosc = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('fosc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.fosc,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.hma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('hma', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.hma,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.kama = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('kama', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.kama,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.kvo = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('kvo', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.kvo,\n            inputs: [data.high, data.low, data.close, data.volume],\n            options: [params.optInFastPeriod, params.optInSlowPeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.linreg = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linreg', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.linreg,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.linregintercept = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linregintercept', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.linregintercept,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.linregslope = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('linregslope', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.linregslope,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.macd = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod', 'optInSignalPeriod'],\n    create: (params) => {\n        verifyParams('macd', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.macd,\n            inputs: [data.close],\n            options: [params.optInFastPeriod, params.optInSlowPeriod, params.optInSignalPeriod],\n            results: ['macd', 'macdSignal', 'macdHistogram'],\n        });\n    }\n}\n\nmethods.marketfi = {\n    requires: [],\n    create: (params) => {\n        verifyParams('marketfi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.marketfi,\n            inputs: [data.high, data.low, data.volume],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.mass = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('mass', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.mass,\n            inputs: [data.high, data.low],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.medprice = {\n    requires: [],\n    create: (params) => {\n        verifyParams('medprice', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.medprice,\n            inputs: [data.high, data.low],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.mfi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('mfi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.mfi,\n            inputs: [data.high, data.low, data.close, data.volume],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.msw = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('msw', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.msw,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['mswSine', 'mswLead'],\n        });\n    }\n}\n\nmethods.natr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('natr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.natr,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.nvi = {\n    requires: [],\n    create: (params) => {\n        verifyParams('nvi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.nvi,\n            inputs: [data.close, data.volume],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.obv = {\n    requires: [],\n    create: (params) => {\n        verifyParams('obv', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.obv,\n            inputs: [data.close, data.volume],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.ppo = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('ppo', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.ppo,\n            inputs: [data.close],\n            options: [params.optInFastPeriod, params.optInSlowPeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.psar = {\n    requires: ['optInAcceleration', 'optInMaximum'],\n    create: (params) => {\n        verifyParams('psar', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.psar,\n            inputs: [data.high, data.low],\n            options: [params.optInAcceleration, params.optInMaximum],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.pvi = {\n    requires: [],\n    create: (params) => {\n        verifyParams('pvi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.pvi,\n            inputs: [data.close, data.volume],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.qstick = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('qstick', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.qstick,\n            inputs: [data.open, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.roc = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('roc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.roc,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.rocr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rocr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.rocr,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.rsi = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('rsi', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.rsi,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.sma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('sma', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.sma,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.stddev = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('stddev', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.stddev,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.stoch = {\n    requires: ['optInFastKPeriod', 'optInSlowKPeriod', 'optInSlowDPeriod'],\n    create: (params) => {\n        verifyParams('stoch', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.stoch,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInFastKPeriod, params.optInSlowKPeriod, params.optInSlowDPeriod],\n            results: ['stochK', 'stochD'],\n        });\n    }\n}\n\nmethods.sum = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('sum', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.sum,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.tema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('tema', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.tema,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.tr = {\n    requires: [],\n    create: (params) => {\n        verifyParams('tr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.tr,\n            inputs: [data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.trima = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('trima', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.trima,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.trix = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('trix', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.trix,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.tsf = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('tsf', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.tsf,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.typprice = {\n    requires: [],\n    create: (params) => {\n        verifyParams('typprice', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.typprice,\n            inputs: [data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.ultosc = {\n    requires: ['optInTimePeriod1', 'optInTimePeriod2', 'optInTimePeriod3'],\n    create: (params) => {\n        verifyParams('ultosc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.ultosc,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod1, params.optInTimePeriod2, params.optInTimePeriod3],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.vhf = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('vhf', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.vhf,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.vidya = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod', 'optInAlpha'],\n    create: (params) => {\n        verifyParams('vidya', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.vidya,\n            inputs: [data.close],\n            options: [params.optInFastPeriod, params.optInSlowPeriod, params.optInAlpha],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.volatility = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('volatility', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.volatility,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.vosc = {\n    requires: ['optInFastPeriod', 'optInSlowPeriod'],\n    create: (params) => {\n        verifyParams('vosc', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.vosc,\n            inputs: [data.volume],\n            options: [params.optInFastPeriod, params.optInSlowPeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.vwma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('vwma', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.vwma,\n            inputs: [data.close, data.volume],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.wad = {\n    requires: [],\n    create: (params) => {\n        verifyParams('wad', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.wad,\n            inputs: [data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.wcprice = {\n    requires: [],\n    create: (params) => {\n        verifyParams('wcprice', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.wcprice,\n            inputs: [data.high, data.low, data.close],\n            options: [],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.wilders = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('wilders', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.wilders,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.willr = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('willr', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.willr,\n            inputs: [data.high, data.low, data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.wma = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('wma', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.wma,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmethods.zlema = {\n    requires: ['optInTimePeriod'],\n    create: (params) => {\n        verifyParams('zlema', params);\n\n        return (data, callback) => execute(callback, {\n            indicator: tulind.indicators.zlema,\n            inputs: [data.close],\n            options: [params.optInTimePeriod],\n            results: ['result'],\n        });\n    }\n}\n\nmodule.exports = methods;\n\n"
  },
  {
    "path": "core/util.js",
    "content": "var moment = require('moment');\nvar _ = require('lodash');\nvar path = require('path');\nvar fs = require('fs');\nvar semver = require('semver');\nvar program = require('commander');\n\nvar startTime = moment();\n\nvar _config = false;\nvar _package = false;\nvar _nodeVersion = false;\nvar _gekkoMode = false;\nvar _gekkoEnv = false;\n\nvar _args = false;\n\n// helper functions\nvar util = {\n  getConfig: function() {\n    // cache\n    if(_config)\n      return _config;\n\n    if(!program.config)\n        util.die('Please specify a config file.', true);\n\n    if(!fs.existsSync(util.dirs().gekko + program.config))\n      util.die('Cannot find the specified config file.', true);\n\n    _config = require(util.dirs().gekko + program.config);\n    return _config;\n  },\n  // overwrite the whole config\n  setConfig: function(config) {\n    _config = config;\n  },\n  setConfigProperty: function(parent, key, value) {\n    if(parent)\n      _config[parent][key] = value;\n    else\n      _config[key] = value;\n  },\n  getVersion: function() {\n    return util.getPackage().version;\n  },\n  getPackage: function() {\n    if(_package)\n      return _package;\n\n\n    _package = JSON.parse( fs.readFileSync(__dirname + '/../package.json', 'utf8') );\n    return _package;\n  },\n  getRequiredNodeVersion: function() {\n    return util.getPackage().engines.node;\n  },\n  recentNode: function() {\n    var required = util.getRequiredNodeVersion();\n    return semver.satisfies(process.version, required);\n  },\n  // check if two moments are corresponding\n  // to the same time\n  equals: function(a, b) {\n    return !(a < b || a > b)\n  },\n  minToMs: function(min) {\n    return min * 60 * 1000;\n  },\n  defer: function(fn) {\n    return function(args) {\n      var args = _.toArray(arguments);\n      return _.defer(function() { fn.apply(this, args) });\n    }\n  },\n  logVersion: function() {\n    return  `Gekko version: v${util.getVersion()}`\n    + `\\nNodejs version: ${process.version}`;\n  },\n  die: function(m, soft) {\n\n    if(_gekkoEnv === 'child-process') {\n      return process.send({type: 'error', error: '\\n ERROR: ' + m + '\\n'});\n    }\n\n    var log = console.log.bind(console);\n\n    if(m) {\n      if(soft) {\n        log('\\n ERROR: ' + m + '\\n\\n');\n      } else {\n        log(`\\nGekko encountered an error and can\\'t continue`);\n        log('\\nError:\\n');\n        log(m, '\\n\\n');\n        log('\\nMeta debug info:\\n');\n        log(util.logVersion());\n        log('');\n      }\n    }\n    process.exit(1);\n  },\n  dirs: function() {\n    var ROOT = __dirname + '/../';\n\n    return {\n      gekko: ROOT,\n      core: ROOT + 'core/',\n      markets: ROOT + 'core/markets/',\n      exchanges: ROOT + 'exchange/wrappers/',\n      plugins: ROOT + 'plugins/',\n      methods: ROOT + 'strategies/',\n      indicators: ROOT + 'strategies/indicators/',\n      budfox: ROOT + 'core/budfox/',\n      importers: ROOT + 'importers/exchanges/',\n      tools: ROOT + 'core/tools/',\n      workers: ROOT + 'core/workers/',\n      web: ROOT + 'web/',\n      config: ROOT + 'config/',\n      broker: ROOT + 'exchange/'\n    }\n  },\n  inherit: function(dest, source) {\n    require('util').inherits(\n      dest,\n      source\n    );\n  },\n  makeEventEmitter: function(dest) {\n    util.inherit(dest, require('events').EventEmitter);\n  },\n  setGekkoMode: function(mode) {\n    _gekkoMode = mode;\n  },\n  gekkoMode: function() {\n    if(_gekkoMode)\n      return _gekkoMode;\n\n    if(program['import'])\n      return 'importer';\n    else if(program.backtest)\n      return 'backtest';\n    else\n      return 'realtime';\n  },\n  gekkoModes: function() {\n    return [\n      'importer',\n      'backtest',\n      'realtime'\n    ]\n  },\n  setGekkoEnv: function(env) {\n    _gekkoEnv = env;\n  },\n  gekkoEnv: function() {\n    return _gekkoEnv || 'standalone';\n  },\n  launchUI: function() {\n    if(program['ui'])\n      return true;\n    else\n      return false;\n  },\n  getStartTime: function() {\n    return startTime;\n  },\n}\n\n// NOTE: those options are only used\n// in stand alone mode\nprogram\n  .version(util.logVersion())\n  .option('-c, --config <file>', 'Config file')\n  .option('-b, --backtest', 'backtesting mode')\n  .option('-i, --import', 'importer mode')\n  .option('--ui', 'launch a web UI')\n  .parse(process.argv);\n\n// make sure the current node version is recent enough\nif(!util.recentNode())\n  util.die([\n    'Your local version of Node.js is too old. ',\n    'You have ',\n    process.version,\n    ' and you need atleast ',\n    util.getRequiredNodeVersion()\n  ].join(''), true);\n\nmodule.exports = util;\n"
  },
  {
    "path": "core/workers/datasetScan/parent.js",
    "content": "var _ = require('lodash');\nvar moment = require('moment');\nvar async = require('async');\nvar os = require('os');\n\nvar util = require('../../util');\nvar dirs = util.dirs();\n\nvar dateRangeScan = require('../dateRangeScan/parent');\n\nmodule.exports = function(config, done) {\n\n  util.setConfig(config);\n\n  var adapter = config[config.adapter];\n  var scan = require(dirs.gekko + adapter.path + '/scanner');\n\n  scan((err, markets) => {\n\n    if(err)\n      return done(err);\n\n      let numCPUCores = os.cpus().length;\n      if(numCPUCores === undefined)\n         numCPUCores = 1;\n      async.eachLimit(markets, numCPUCores, (market, next) => {\n\n      let marketConfig = _.clone(config);\n      marketConfig.watch = market;\n\n      dateRangeScan(marketConfig, (err, ranges) => {\n        if(err)\n          return next();\n\n        market.ranges = ranges;\n\n        next();\n      });\n\n    }, err => {\n      let resp = {\n        datasets: [],\n        errors: []\n      }\n      markets.forEach(market => {\n        if(market.ranges)\n          resp.datasets.push(market);\n        else\n          resp.errors.push(market);\n      })\n      done(err, resp);\n    })\n  });\n}\n"
  },
  {
    "path": "core/workers/dateRangeScan/child.js",
    "content": "var util = require(__dirname + '/../../util');\n\nvar dirs = util.dirs();\nvar ipc = require('relieve').IPCEE(process);\n\nipc.on('start', config => {\n\n  // force correct gekko env\n  util.setGekkoEnv('child-process');\n\n  // force disable debug\n  config.debug = false;\n\n  // persist config\n  util.setConfig(config);\n\n  var scan = require(dirs.tools + 'dateRangeScanner');\n  scan(\n    (err, ranges, reader) => {\n      reader.close();\n      ipc.send('ranges', ranges);\n      process.exit(0);\n    }\n  );\n});\n\n"
  },
  {
    "path": "core/workers/dateRangeScan/parent.js",
    "content": "var ForkTask = require('relieve').tasks.ForkTask;\nvar fork = require('child_process').fork;\n\nmodule.exports = function(config, done) {\n  var debug = typeof v8debug === 'object';\n  if (debug) {\n    process.execArgv = [];\n  }\n\n  task = new ForkTask(fork(__dirname + '/child'));\n\n  task.send('start', config);\n\n  task.once('ranges', ranges => {\n    return done(false, ranges);\n  });\n  task.on('exit', code => {\n    if(code !== 0)\n      done('ERROR, unable to scan dateranges, please check the console.');\n  });\n}\n"
  },
  {
    "path": "core/workers/loadCandles/child.js",
    "content": "var start = (config, candleSize, daterange) => {\n  var util = require(__dirname + '/../../util');\n\n  // force correct gekko env\n  util.setGekkoEnv('child-process');\n\n  // force disable debug\n  config.debug = false;\n  util.setConfig(config);\n\n  var dirs = util.dirs();\n\n  var load = require(dirs.tools + 'candleLoader');\n  load(config.candleSize, candles => {\n    process.send(candles);\n  })\n}\n\nprocess.send('ready');\n\nprocess.on('message', (m) => {\n  if(m.what === 'start')\n    start(m.config, m.candleSize, m.daterange);\n});\n\nprocess.on('disconnect', function() {\n  process.exit(0);\n})\n"
  },
  {
    "path": "core/workers/loadCandles/parent.js",
    "content": "// example usage:\n\n// let config = {\n//   watch: {\n//     exchange: 'poloniex',\n//     currency: 'USDT',\n//     asset: 'BTC'\n//   },\n//   daterange: {\n//     from: '2016-05-22 11:22',\n//     to: '2016-06-03 19:56'\n//   },\n//   adapter: 'sqlite',\n//   sqlite: {\n//     path: 'plugins/sqlite',\n\n//     dataDirectory: 'history',\n//     version: 0.1,\n\n//     dependencies: [{\n//       module: 'sqlite3',\n//       version: '3.1.4'\n//     }]\n//   },\n//   candleSize: 100\n// }\n\n// module.exports(config, function(err, data) {\n//   console.log('FINAL CALLBACK');\n//   console.log('err', err);\n//   console.log('data', data.length);\n// })\n\n\nconst fork = require('child_process').fork;\nconst _ = require('lodash');\n\nmodule.exports = (config, callback) => {\n  var debug = typeof v8debug === 'object';\n  if (debug) {\n    process.execArgv = [];\n  }\n\n  const child = fork(__dirname + '/child');\n\n  const message = {\n    what: 'start',\n    config\n  }\n\n  const done = _.once(callback);\n\n  child.on('message', function(m) {\n    if(m === 'ready')\n      return child.send(message);\n\n    // else we are done and have candles!\n    done(null, m);\n    if (this.connected) {\n      this.disconnect();\n    }\n  });\n\n  child.on('exit', code => {\n    if(code !== 0)\n      done('ERROR, unable to load candles, please check the console.');\n  });\n}\n"
  },
  {
    "path": "core/workers/pipeline/child.js",
    "content": "/*\n\n  Gekko is a Bitcoin trading bot for popular Bitcoin exchanges written \n  in node, it features multiple trading methods using technical analysis.\n\n  If you are interested in how Gekko works, read more about Gekko's \n  architecture here:\n\n  https://github.com/askmike/gekko/blob/stable/docs/internals/architecture.md\n\n  Disclaimer:\n\n  USE AT YOUR OWN RISK!\n\n  The author of this project is NOT responsible for any damage or loss caused \n  by this software. There can be bugs and the bot may not perform as expected \n  or specified. Please consider testing it first with paper trading and/or \n  backtesting on historical data. Also look at the code to see what how \n  it is working.\n\n*/\n\nvar start = (mode, config) => {\n  var util = require(__dirname + '/../../util');\n\n  // force correct gekko env\n  util.setGekkoEnv('child-process');\n\n  var dirs = util.dirs();\n\n  // force correct gekko mode & config\n  util.setGekkoMode(mode);\n  util.setConfig(config);\n\n  var pipeline = require(dirs.core + 'pipeline');\n  pipeline({\n    config: config,\n    mode: mode\n  });\n}\n\nprocess.send('ready');\n\nprocess.on('message', function(m) {\n  if(m.what === 'start')\n    start(m.mode, m.config);\n\n  if(m.what === 'exit')\n    process.exit(0);\n});\n\nprocess.on('disconnect', function() {\n  console.log('disconnect');\n  process.exit(-1);\n})\n\nprocess\n  .on('unhandledRejection', (message, p) => {\n    console.error('unhandledRejection', message);\n    process.send({type: 'error', message: message});\n  })\n  .on('uncaughtException', err => {\n    console.error('uncaughtException', err);\n    process.send({type: 'error', error: err});\n    process.exit(1);\n  });"
  },
  {
    "path": "core/workers/pipeline/messageHandlers/backtestHandler.js",
    "content": "// Relay the backtest message it when it comes in.\n\nmodule.exports = done => {\n  let backtest;\n\n  return {\n    message: message => {\n      if(message.type === 'error') {\n        done(message.error);\n      }\n\n      if(message.backtest) {\n        done(null, message.backtest);\n      }\n    },\n    exit: status => {\n      if(status !== 0) {\n        if(backtest)\n          console.error('Child process died after finishing backtest');\n        else\n          done('Child process has died.');\n      }\n    }\n  }\n}"
  },
  {
    "path": "core/workers/pipeline/messageHandlers/importerHandler.js",
    "content": "module.exports = cb => {\n\n  return {\n    message: message => {\n\n      if(message.event === 'marketUpdate')\n        cb(null, {\n          done: false,\n          latest: message.payload\n        })\n\n      else if(message.type === 'error') {\n        cb(message.error);\n      }\n\n      else if(message.type === 'log')\n        console.log(message.log);\n    },\n    exit: status => {\n      if(status !== 0)\n        return cb('Child process has died.');\n      else\n        cb(null, { done: true });\n    }\n  }\n}"
  },
  {
    "path": "core/workers/pipeline/messageHandlers/realtimeHandler.js",
    "content": "// pass back all messages as is\n// (except for errors and logs)\n\nmodule.exports = cb => {\n\n  return {\n    message: message => {\n\n      if(message.type === 'error') {\n        cb(message.error);\n      }\n\n      else\n        cb(null, message);\n\n    },\n    exit: status => {\n      if(status !== 0)\n        cb('Child process has died.');\n      else\n        cb(null, { done: true });\n    }\n  }\n}"
  },
  {
    "path": "core/workers/pipeline/parent.js",
    "content": "var fork = require('child_process').fork;\n\nmodule.exports = (mode, config, callback) => {\n  var debug = typeof v8debug === 'object';\n  if (debug) {\n    process.execArgv = [];\n  }\n\n  var child = fork(__dirname + '/child');\n\n  // How we should handle client messages depends\n  // on the mode of the Pipeline that is being ran.\n  var handle = require('./messageHandlers/' + mode + 'Handler')(callback);\n\n  var message = {\n    what: 'start',\n    mode: mode,\n    config: config\n  };\n\n  child.on('message', function(m) {\n    if(m === 'ready')\n      return child.send(message);\n\n    if(m === 'done')\n      return child.send({what: 'exit'});\n\n    handle.message(m);\n  });\n\n  child.on('exit', handle.exit);\n\n  return child;\n}\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3'\nservices:\n  gekko:\n    build: ./\n    volumes:\n      - ./volumes/gekko/history:/usr/src/app/history\n      - ./config.js:/usr/src/app/config.js\n    links:\n      - redis\n#      - postgresql\n    environment:\n     - HOST\n     - PORT\n     - USE_SSL\n    ports: # you can comment this out when using the nginx frontend\n      - \"${PORT}:${PORT}\"\n## optionally set nginx vars if you wish to frontend it with nginx\n#    environment:\n#     - VIRTUAL_HOST=gekko\n#     - PORT=3000\n#     - DOMAIN=gekko\n\n  redis:\n    image: redis:latest\n    volumes:\n      - ./volumes/redis:/data\n## optionally uncomment if you wish to use nginx as a frontend\n#  nginx:\n#    restart: always\n#    image: jwilder/nginx-proxy\n#    ports:\n#     - \"80:80\"\n#    volumes:\n#     - /var/run/docker.sock:/tmp/docker.sock:ro\n## optionally uncomment if you wish to use postgresql as a db\n#  postgresql:\n#    restart: always\n#    image: postgres:9.6-alpine\n#    ports:\n#      - 5432:5432\n#    volumes:\n#      - ./_postgresql:/var/lib/postgresql/data:rw\n#    environment:\n#      POSTGRES_DB: gekko\n#      POSTGRES_USER: username\n#      POSTGRES_PASSWORD: password\n"
  },
  {
    "path": "docker-entrypoint.sh",
    "content": "#!/bin/bash\n\nsed -i 's/127.0.0.1/0.0.0.0/g' /usr/src/app/web/vue/dist/UIconfig.js\nsed -i 's/localhost/'${HOST}'/g' /usr/src/app/web/vue/dist/UIconfig.js\nsed -i 's/3000/'${PORT}'/g' /usr/src/app/web/vue/dist/UIconfig.js\nif [[ \"${USE_SSL:-0}\" == \"1\" ]] ; then\n    sed -i 's/ssl: false/ssl: true/g' /usr/src/app/web/vue/dist/UIconfig.js\nfi\nexec node gekko \"$@\"\n"
  },
  {
    "path": "docs/commandline/Importing.md",
    "content": "# Importing\n\n*Note: this documentation was written for running Gekko via the command line. If you are using the UI you can simply use the importer under the \"local data\" tab.*\n\nIf you want to use Gekko to [backtest against historical data](./backtesting.md), you most likely need some historical data to test against. Gekko comes with the functionality to automatically import historical data from some exchanges. However, only a few exchanges support this. You can find out with which exchanges Gekko is able to do this [here](https://github.com/askmike/gekko#supported-exchanges).\n\n## Setup\n\nFor importing you should [enable and configure](./plugins.md) the following plugin:\n\n - candleWriter (to store the imported data in a database)\n\nBesides that, make sure to configure `config.watch` properly.\n\n## Configure\n\nIn your config set the `importer.daterange` properties to the daterange you would like to import.\n\n## Run\n\n    node gekko --config config.js --import\n\nThe result will be something like this:\n\n    2016-06-26 09:12:16 (INFO): Gekko v0.2.2 started\n    2016-06-26 09:12:16 (INFO): I'm gonna make you rich, Bud Fox. \n\n    2016-06-26 09:12:17 (INFO): Setting up Gekko in importer mode\n    2016-06-26 09:12:17 (INFO): \n    2016-06-26 09:12:17 (INFO): Setting up:\n    2016-06-26 09:12:17 (INFO):      Candle writer\n    2016-06-26 09:12:17 (INFO):      Store candles in a database\n    2016-06-26 09:12:17 (INFO): \n\n    2016-06-26 09:12:17 (WARN): The plugin Trading Advisor does not support the mode importer. It has been disabled.\n    2016-06-26 09:12:17 (WARN): The plugin Advice logger does not support the mode importer. It has been disabled.\n    2016-06-26 09:12:17 (WARN): The plugin Profit Simulator does not support the mode importer. It has been disabled.\n    2016-06-26 09:12:18 (DEBUG):    Processing 798 new trades.\n    2016-06-26 09:12:18 (DEBUG):    From 2015-09-09 12:00:04 UTC to 2015-09-09 13:58:55 UTC. (2 hours)\n    2016-06-26 09:12:20 (DEBUG):    Processing 211 new trades.\n    (...)\n"
  },
  {
    "path": "docs/commandline/about_the_commandline.md",
    "content": "# About the commandline\n\nYou don't have to use the UI to control Gekko, you can also use the commandline if you don't have access to a window manager or browser (on a server for example, or anything else you want to SSH into). This is only recommended for advanced users who feel comfortable editing config files and running shell commands.\n\nUsing the commandline you run one Gekko instance per command, eg. if you want to import 3 markets you need to run Gekko 3 times.\n\n## Configuring Gekko\n\nIf you decide you want to run gekko over the commandline you need to decide two things:\n\n1. What market / settings are you interested in?\n2. What should Gekko do? This is either backtest, import or run live.\n\nFor the first one you configure a config file: copy `gekko/sample-config.js` to something else (for example `gekko/config.js`). Configure the plugins to your liking. What plugins you need to enable does depend on the answer of question 2. Check the documentation under commandline for that feature.\n\n## Running Gekko\n\nFor live mode run:\n\n    node gekko --config config.js\n\nTo backtesting run:\n\n    node gekko --config config.js --backtest\n\nTo import run:\n\n    node gekko --config config.js --import"
  },
  {
    "path": "docs/commandline/backtesting.md",
    "content": "# Backtesting with Gekko\n\n*Note: this documentation was written for running Gekko via the command line. If you are using the UI you can simply use the importer under the \"local data\" tab.*\n\nGekko is able to backtest strategies against historical data.\n\n## Setup\n\nFor backtesting you should [enable and configure](./plugins.md) the following plugins:\n\n - trading advisor (to run your strategy).\n - paper trader (to execute simulated trades).\n - performance analyzer (to calculate how succesfull the strategy would have been).\n\nBesides that, make sure to configure `config.watch`.\n\n## Historical data\n\nGekko requires historical data to backtest strategies against. The easiest way to get this is to let Gekko import historical data, however this is not supported by a lot of exchanges (see [here](https://github.com/askmike/gekko#supported-exchanges)). The second easiest and most universal way is to run Gekko on real markets using the UI (or alternatively via the commandline with the plugin sqliteWriter enabled). Though this takes a while, as you need to run Gekko for a week to have a week of data.\n\n## Configure\n\nIn your config set the `backtest.daterange` to `scan`. This will force Gekko to scan the local database to figure out what dataranges are available. If you already know exactly what daterange you would like to backtest against, you can set the `backtest.daterange` directly (set `backtest.daterange` as an object with the keys `from` and `to` and the values as a data parsable by [moment](http://momentjs.com/docs/#/parsing/)).\n\n## Run\n\n    node gekko --config config.js --backtest\n\nThe result will be something like this:\n\n    2016-06-11 08:53:20 (INFO): Gekko v0.2.1 started\n    2016-06-11 08:53:20 (INFO): I'm gonna make you rich, Bud Fox.\n\n    2016-06-11 08:53:20 (INFO): Setting up Gekko in backtest mode\n    2016-06-11 08:53:20 (INFO):\n    2016-06-11 08:53:20 (WARN): The plugin SQLite Datastore does not support the mode backtest. It has been disabled.\n    2016-06-11 08:53:20 (INFO): Setting up:\n    2016-06-11 08:53:20 (INFO):    Trading Advisor\n    2016-06-11 08:53:20 (INFO):    Calculate trading advice\n    2016-06-11 08:53:20 (INFO):    Using the trading method: DEMA\n    2016-06-11 08:53:20 (INFO):\n\n    2016-06-11 08:53:20 (INFO): Setting up:\n    2016-06-11 08:53:20 (INFO):    Profit Simulator\n    2016-06-11 08:53:20 (INFO):    Paper trader that logs fake profits.\n    2016-06-11 08:53:20 (INFO):\n\n    2016-06-11 08:58:20 (INFO): Profit simulator got advice to long @ 2016-05-30 04:37:00, buying 1.1880062 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to short  @ 2016-05-31 21:37:00, selling 1.1880062 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to long @ 2016-06-01 12:37:00, buying 1.14506098 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to short  @ 2016-06-02 14:57:00, selling 1.14506098 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to long @ 2016-06-02 23:37:00, buying 1.11711818 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to short  @ 2016-06-05 12:57:00, selling 1.11711818 BTC\n    2016-06-11 08:58:21 (INFO): Profit simulator got advice to long @ 2016-06-06 02:37:00, buying 1.08456953 BTC\n    2016-06-11 08:58:22 (INFO): Profit simulator got advice to short  @ 2016-06-07 17:17:00, selling 1.08456953 BTC\n    2016-06-11 08:58:22 (INFO): Profit simulator got advice to long @ 2016-06-08 13:17:00, buying 1.05481755 BTC\n    2016-06-11 08:58:22 (INFO): Profit simulator got advice to short  @ 2016-06-09 14:17:00, selling 1.05481755 BTC\n\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) start time:      2016-05-29 23:34:00\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) end time:      2016-06-10 08:56:00\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) timespan:      11 days days\n\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) start price:       516.19\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) end price:       578.97\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) Buy and Hold profit:     12.162189999999995%\n\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) amount of trades:    10\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) original simulated balance:  616.19000 USD\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) current simulated balance:   602.59867 USD\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) simulated profit:    -13.59133 USD (-2.20570%)\n    2016-06-11 08:53:22 (INFO): (PROFIT REPORT) simulated yearly profit:   -435.53244 USD (-70.68152%)\n"
  },
  {
    "path": "docs/commandline/plugins.md",
    "content": "## Enabling plugins\n\n*Note: this documentation was written for running Gekko via the command line. If you are using the UI you do not have to manually select plugins.*\n\nGekko currently has a couple plugins:\n\n- trading advisor (run a TA strategy against a market)\n- trader (execute advice from the TA strategy on a real exchange)\n- advice logger\n- paper trader\n- Mailer\n- IRC bot\n- Campfire bot\n- Redis beacon\n- XMP Bot\n- and more..\n\nTo configure a plugin, open up your `config.js` file with a text editor and configure the appropiate section.\n\n## Trading Advisor\n\nIf you want Gekko to provide automated trading advice you need to configure this in Gekko. Note that this is a different plugin than the  \"trader\" which is a responsible for actually creating orders based on this advice. (So if you want automated trading you need both this advice as well as the auto trader).\n\nDocumentation about strategies in Gekko can be found [here](../strategies/introduction.md).\n\n### Trader\n\nThis plugin automatically creates orders based on the advice from the \"Trading Advisor\" from the market Gekko is watching. This turns Gekko into an automated trading bot.\n\nBefore Gekko can automatically trade you need to create API keys so that Gekko has the rights to create orders on your behalf, the rights Gekko needs are (naming differs per exchange): get info, get balance/portfolio, get open orders, get fee, buy, sell and cancel order. For all exchanges you need the API key and the API secret, for both Bitstamp and CEX.io you also need your username (which is a number at Bitstamp).\n\nConfigure it like this:\n\n    config.trader = {\n      enabled: true,\n      key: 'your-api-key',\n      secret: 'your-api-secret',\n      username: 'your-username' // your username, only fill in when using bitstamp or cexio\n    }\n\n- enabled indicates whether this is on or off.\n- key is your API key.\n- secret is your API secret.\n- username is the username (only required for CEX.io and Bitstamp).\n\n### Advice logger\n\nThe advice logger is a small plugin that logs new advice calculated by Gekko as soon as there is any. Go to the config and configure it like this:\n\n    config.adviceLogger = {\n      enabled: true\n    }\n\n- enabled indicates whether this is on or off.\n\nThe advice logged advice will look something like this in the terminal:\n\n    2014-01-15 14:31:44 (INFO): We have new trading advice!\n    2014-01-15 14:31:44 (INFO):    Position to take: long\n    2014-01-15 14:31:44 (INFO):    Market price: 5.96\n    2014-01-15 14:31:44 (INFO):    Based on market time: 2014-01-15 14:31:01\n\n### Paper trader\n\nThe paper trader listens to Gekko's advice and on a sell it will swap all (simulated) currency into (simulated) assets at the current price. On a buy it will be the other way around.\n\nGo to the config and configure it like this:\n\n    // do you want Gekko to calculate the profit of its own advice?\n    config.paperTrader = {\n      enabled: true,\n      // report the profit in the currency or the asset?\n      reportInCurrency: true,\n      // start balance, on what the current balance is compared with\n      simulationBalance: {\n        // these are in the unit types configured in the watcher.\n        asset: 1,\n        currency: 100\n      },\n      // only want report after a sell? set to `false`.\n      verbose: false,\n      // how much fee in % does each trade cost?\n      feeMaker: 0.5,\n      feeTaker: 0.6,\n      // Using taker or maker fee?\n      feeUsing: 'maker',\n      // how much slippage should Gekko assume per trade?\n      slippage: 0.1\n    }\n\n- enabled indicates whether this is on or off.\n- reportInCurrency tells Gekko whether it should report in asset or in the currency.\n- simulationBalance tells Gekko with what balance it should start.\n- verbose specifies how often Gekko should log the results (false is after every trade, true is after every candle).\n- fee is the exchange fee (in %) Gekko should take into consideration when simulating orders.\n- slippage is the costs in (in %) associated with not being able to buy / sell at market price.*\n\n*If you are trading a lot and you are buying 100% currency you might not get it all at market price and you have to walk the book in order to take that position. Also note that Gekko uses the candle close price and is unaware of the top asks bids, also take this into account. It is important that you set this number correctly or the resulted calculated profit be very wrong. Read more information [here](http://www.investopedia.com/terms/s/slippage.asp). Take these into consideration when setting a slippage:\n\n- How much spread is there normally on this market?\n- How thick is the top of the book normally?\n- How volatile is this market (the more volatility the bigger the chance you will not get the price you expected)?\n\nThe output will be something like:\n\n    2013-06-02 18:21:15 (INFO): ADVICE is to SHORT @ 117.465 (0.132)\n    2013-06-02 18:21:15 (INFO): (PROFIT REPORT) original balance:    207.465 USD\n    2013-06-02 18:21:15 (INFO): (PROFIT REPORT) current balance:     217.465 USD\n    2013-06-02 18:21:15 (INFO): (PROFIT REPORT) profit:          10.000 USD (4.820%)\n\n### Mailer\n\nMailer will automatically email you whenever Gekko has a new advice.\n\n    // want Gekko to send a mail on buy or sell advice?\n    config.mailer = {\n      enabled: false,       // Send Emails if true, false to turn off\n      sendMailOnStart: true,    // Send 'Gekko starting' message if true, not if false\n\n      Email: 'me@gmail.com',    // Your GMail address\n\n      // You don't have to set your password here, if you leave it blank we will ask it\n      // when Gekko's starts.\n      //\n      // NOTE: Gekko is an open source project < https://github.com/askmike/gekko >,\n      // make sure you looked at the code or trust the maintainer of this bot when you\n      // fill in your email and password.\n      //\n      // WARNING: If you have NOT downloaded Gekko from the github page above we CANNOT\n      // guarantee that your email address & password are safe!\n\n      password: '',       // Your GMail Password - if not supplied Gekko will prompt on startup.\n      tag: '[GEKKO] '      // Prefix all EMail subject lines with this\n    }\n\n- enabled indicates whether this is on or off.\n- sendMailOnStart will email you right away after Gekko started, you can also use this if you are automatically restarting Gekko to see crash behaviour.\n- Email is your email address from which Gekko will send emails (to the same address).\n- password is the email password: Gekko needs to login to your account to send emails to you:\n\n  > You don't have to set your password here, if you leave it blank we will ask it\n  > when Gekko's starts.\n  >\n  > NOTE: Gekko is an open source project < https://github.com/askmike/gekko >,\n  > make sure you looked at the code or trust the maintainer of this bot when you\n  > fill in your email and password.\n  >\n  > WARNING: If you have NOT downloaded Gekko from the github page above we CANNOT\n  > guarantee that your email address & password are safe!\n\n- tag is some text that Gekko will put in all subject lines so you can easily group all advices together.\n\n### IRC bot\n\nIRC bot is a small plugin that connects Gekko to an IRC channel and lets users interact with it using basic commands.\n\n    config.ircbot = {\n      enabled: false,\n      emitUpdates: false,\n      channel: '#your-channel',\n      server: 'irc.freenode.net',\n      botName: 'gekkobot'\n    }\n\n- enabled indicates whether this is on or off.\n- emitUpdates tells Gekko that whenever there is a new advice it should broadcast this in the channel.\n- channel is the IRC channel the bot will connect to.\n- server is the IRC server.\n- botName is the username Gekko will use.\n\n### Campfire bot\n\nCampfire bot is a small plugin that connects Gekko to a Campfire room and lets users interact with it using basic commands.\n\n    config.campfire = {\n      enabled: false,\n      emitUpdates: false,\n      nickname: 'Gordon',\n      roomId: 673783,\n      apiKey: 'e3b0c44298fc1c149afbf4c8996',\n      account: 'your-subdomain'\n    }\n\n- enabled indicates whether this is on or off.\n- emitUpdates tells Gekko that whenever there is a new advice it should broadcast this in the room.\n- roomId is the ID of the Campfire room the bot will connect to.\n- apiKey is the API key for the Campfire user Gekko will connect using.\n- account is the subdomain for the account that the room belongs to.\n\n### Redis beacon\n\nThis is an advanced plugin only for programmers! If you are interested in this read more [here](https://github.com/askmike/gekko/blob/stable/docs/internals/plugins.md#redis-beacon).\n\n    config.redisBeacon = {\n      enabled: false,\n      port: 6379, // redis default\n      host: '127.0.0.1', // localhost\n        // On default Gekko broadcasts\n        // events in the channel with\n        // the name of the event, set\n        // an optional prefix to the\n        // channel name.\n      channelPrefix: '',\n      broadcast: [\n        'small candle'\n      ]\n    }\n\n- enabled indicates whether this is on or off.\n- port is the port redis is running on.\n- host is the redis host.\n- channelPrefix a string that Gekko will prefix all candles with.\n- broadcast is a list of all events you want Gekko to publish.\n\n"
  },
  {
    "path": "docs/commandline/tradebot.md",
    "content": "# Tradebot\n\nYou can set Gekko up as a tradebot, this will instruct Gekko to:\n\n- Watch a live market.\n- Run a strategy (in semi-realtime) over live market data.\n- Automatically create buy/sell orders based on signals coming from the strategy.\n\n*As with everything in Gekko, the tradebot will make decisions based on the strategy selected/configured/created **by YOU**. If you end up losing money, you have no one to blame but yourself.*\n\n## Configuration\n\nFirst, set up Gekko for commandline usage (see [this document](./about_the_commandline.md) for details). After that, configure the following plugins:\n\n- `config.watch` - the market to trade on.\n- `candleWriter` - (optional) also store market data to disk.\n- `tradingAdvisor` - configure the strategy and candle properties.\n- `trader` - configure Gekko access to your exchange account.\n- `performanceAnalyzer` - enable.\n\nTurn off the paperTrader (there can only be 1 trade plugin active per instance).\n\nOnce done, run Gekko like so:\n\n    node gekko --config your-config-file.js\n"
  },
  {
    "path": "docs/extending/add_a_plugin.md",
    "content": "# Plugins\n\nA plugin is a low level module or plugin that can act upon events bubbling\nthrough Gekko. If you want to have custom functionality so that your rocket\nflies to the moon as soon as the price hits X you should create a plugin for it.\n\nAll plugins live in `gekko/plugins`.\n\nNote that in order to use custom plugins, you have to run Gekko over [the commandline](../commandline/about_the_commandline.md).\n\n## Existing plugins:\n\n- Candle Store: save trades to disk.\n- Mailer: mail trading advice to your gmail account.\n- Pushbullet: send messages to Pushbullet devices.\n- Telegram: send messages over Telegram.\n- IRC bot: logs Gekko on in an irc channel and lets users communicate with it.\n- Paper Trader: simulates trades and calculates profit over these (and logs profit).\n- Trading advisor (internal): calculates advice based on market data.\n- Redis beacon (advanced): [see below!](#redis-beacon)\n\n*And more! Take a look in the `gekko/plugins folder.`*\n\n## Implementing a new plugin\n\nIf you want to add your own plugin you need to expose a constructor function inside\n`plugins/[slugname of plugin].js`. The object needs methods based on which event you want\nto listen to. All events can be found in [the events page](../architecture/events.md).\n\nYou also need to add an entry for your plugin inside `plugins.js` which registers your plugin for use with Gekko. Finally you need to add a configuration object to `sample-config.js` with at least:\n\n    config.[slug name of plugin] = {\n      enabled: true\n    }\n\nBesides enabled you can also add other configurables here which users can set themselves. \n\nThat's it! Don't forget to create a pull request of the awesome plugin you've just created!\n"
  },
  {
    "path": "docs/extending/add_an_exchange.md",
    "content": "# Exchanges\n\n*This is a technical document about adding a new exchange to Gekko and Gekko Broker.*\n\nGekko arranges all communication about when assets need to be bought or sold between the *strategy* and *Gekko Broker*. All differences between the different API's are abstracted away just below Gekko Broker inside an \"exchange wrapper\". This document describes all requirements for adding a new exchange wrapper (adding exchange support to Gekko).\n\nWhen you add a new exchange to Gekko you need to expose an object that has methods to query the exchange. This exchange file needs to reside in `gekko/exchange/wrappers` and the filename is the slug of the exchange name + `.js`. So for example the exchange integration with Binance is explained in `gekko/exchange/wrappers/binance.js`.\n\nPlease use a npm module to query an exchange. This will separate the abstract API calls from the Gekko specific stuff (In the case of Bitstamp there was no module yet, so I [created one](https://www.npmjs.com/package/bitstamp)).\n\nFinally Gekko needs to know how it can interact with the exchange, so add a static method `getCapabilities()` that returns it's properties. They are all described [here](#capabilities).\n\n## Gekko's expectations\n\nGekko Broker implements an exchange like so:\n\n    const Exchange = require('./wrapper' + [exchange slug]);\n    this.exchange = new Exchange({key: '', secret: '', username: '', currency: 'USD', asset: 'BTC'});\n\nIt will run the following methods on the exchange object:\n\n### getTrades\n\nWith this single method implemented Gekko won't be able to do live trading, but it will be able to do paper trading and storing market data for backtesting.\n\n    this.watcher.getTrades(since, callback, descending);\n\nIf since is truthy, Gekko requests as much trades as the exchange can give (up to ~10,000 trades, if the exchange supports more you can [create an importer](../features/importing.md)).\n\nThe callback expects an error and a `trades` object. Trades is an array of trade objects in chronological order (0 is older trade, 1 is newer trade). Each trade object needs to have:\n\n- a `date` property (unix timestamp in either string or int)\n- a `price` property (float) which represents the price in [currency] per 1 [asset].\n- an `amount` property (float) which represent the amount of [asset].\n- a `tid` property (float) which represents the tradeID.\n\n## Gekko Broker's expectations\n\nThe methods below are needed for Gekko to automatically trade on the exchange.\n\n### getTicker\n\n    this.exchange.getTicker(callback)\n\nThe callback needs to have the parameters of `err` and `ticker`. Ticker needs to be an object with at least the `bid` and `ask` property in float.\n\n### getFee\n\n    this.exchange.getFee(callback);\n\nThe callback needs to have the parameters of `err` and `fee`. Fee is a float that represents the amount the exchange takes out of the orders Gekko places. If an exchange has a fee of 0.2% this should be `0.002`.\n\n### getPortfolio\n\n    this.exchange.getPortfolio(callback);\n\nThe callback needs to have the parameters of `err` and `portfolio`. Portfolio needs to be an array of all currencies and assets combined in the form of objects, an example object looks like `{name: 'BTC', amount: 1.42131}` (name needs to be an uppercase string, amount needs to be a float).\n\n### getLotSize\n\n    this.exchange.getLotSize(tradeType, amount, size, callback);\n\nThe callback needs to have the parameters of `err` and `lot`. Lot needs to be an object with `amount` and `purchase` size appropriately for the exchange. In the event that the lot is too small, return 0 to both fields and this will generate a lot size warning in the portfolioManager.\n\nNote: This function is currently optional. If not implemented Gekko Broker will fallback to basic lot sizing mechanism it uses internally. However exchanges are not all the same in how rounding and lot sizing work, it is recommend to implement this function.\n\n### buy\n\n    this.exchange.buy(amount, price, callback);\n\n### sell\n\n    this.exchange.sell(amount, price, callback);\n\nThis should create a buy / sell order at the exchange for [amount] of [asset] at [price] per 1 asset. The callback needs to have the parameters `err` and `order`. The order needs to be some id that can be passed back to `checkOrder`, `getOrder` and `cancelOrder`.\n\n### getOrder\n\n    this.exchange.getOrder(order, callback);\n\nWill only be called on orders that have been completed. The order will be something that the manager previously received via the `sell` or `buy` methods. The callback should have the parameters `err` and `order`. Order is an object with properties `price`, `amount` and `date`. Price is the (volume weighted) average price of all trades necessary to execute the order. Amount is the amount of currency traded and Date is a moment object of the last trade part of this order.\n\n### checkOrder\n\n    this.exchange.checkOrder(order, callback);\n\nThe order will be something that the manager previously received via the `sell` or `buy` methods. The callback should have the parameters `err` and a `result` object. The result object will have two or three properties:\n\n- `open`: whether this order is currently in the orderbook.\n- `executed`: whether this order has executed (filled completely).\n- `filledAmount`: the amount of the order that has been filled. This property is only needed when both `open` is true and `completed` is false.\n\n### cancelOrder\n\n    this.exchange.cancelOrder(order, callback);\n\nThe order will be something that the manager previously received via the `sell` or `buy` methods. The callback should have the parameters `err`, `filled` and optionally a `fill` object, `filled` should be true if the order was fully filled before it could be cancelled. If the exchange provided how much was filled before the cancel this should be passed in the `fill object` as a `amountFilled` property. If the exchange provided how much of the original amount is still remaining, pass this as the `remaining` property instead.\n\n### roundPrice\n\n    this.exchange.roundPrice(rawPrice);\n\nShould return a price. Rounds the price into a valid price Gekko Broker can later feed into a buy or sell order. *Note: if representation of the number is important for the exchange (for example if the exchange will not accept numbers expressed in scientific notation) you can return a string from this method (Gekko Broker will perform calculations so the string should be castable to a number.)* \n\n### roundAmount\n\n    this.exchange.roundAmount(rawAmount);\n\nShould return an amount. Rounds the amount into a valid amount Gekko Broker can later feed into a buy or sell order. *Note: if representation of the number is important for the exchange (for example if the exchange will not accept numbers expressed in scientific notation) you can return a string from this method (Gekko Broker will perform calculations so the string should be castable to a number.)*\n\n## Gekko Broker's optional methods\n\n### isValidPrice\n\n    this.exchange.isValidPrice(price);\n\nShould return true or false. If the exchange has restrictions on the price you can submit limit orders at. If there are no such restrictions you should not implement this method.\n\n### isValidLot\n\n    this.exchange.isValidLot(price, amount);\n\nShould return true or false. If the exchange has restrictions on the lot size (order size expressed in \"currency\" amount) you can check for that here. If there are no such restrictions you should not implement this method.\n\n## Error handling\n\nIt is the responsibility of the wrapper to handle errors and retry the call in case of a temporary error. Gekko exposes a retry helper you can use to implement an exponential backoff retry strategy. Your wrapper does need pass a proper error object explaining whether the call can be retried or not. If the error is fatal (for example private API calls with invalid API keys) the wrapper is expected to upstream this error. If the error is retryable (exchange is overloaded or a network error) an error should be passed with the property `notFatal` set to true. If the exchange replied with another error that might be temporary (for example an `Insufficient funds` error right after Gekko canceled an order, which might be caused by the exchange not having updated the balance yet) the error object can be extended with an `retry` property indicating that the call can be retried for n times but after that the error should be considered fatal.\n\nFor implementation refer to the bitfinex implementation, in a gist this is what a common flow looks like:\n\n- (async call) `exchange.buy`, then\n- handle the response and normalize the error so the retry helper understands it, then\n- the retry helper will determine whether the call needs to be retried, then\n    - based on the error it will retry (for example `nonFatal` or `retry`)\n    - if no error it will pass it to your handle function that normalizes the output\n\n## Capabilities\n\nEach exchange *must* provide a `getCapabilities()` static method that returns an object with these parameters:\n\n- `name`: Proper name of the exchange\n- `slug`: slug name of the exchange (needs to match filename in `gekko/exchanges/`)\n- `currencies`: all the currencies supported by the exchange implementation in gekko.\n- `assets`: all the assets supported by the exchange implementation in gekko.\n- `pairs`: all allowed currency / asset combinations that form a market\n- `maxHistoryFetch`: the parameter fed to the getTrades call to get the max history.\n- `providesHistory`: If the getTrades can be fed a since parameter that Gekko can use to get historical data, set this to:\n    - `date`: When Gekko can pass in a starting point in time to start returning data from.\n    - `tid`: When Gekko needs to pass in a trade id to act as a starting point in time.\n    - `false`: When the exchange does not support to give back historical data at all.\n- `fetchTimespan`: if the timespan between first and last trade per fetch is fixed, set it here in minutes.\n- `tradable`: if gekko supports automatic trading on this exchange.\n- `requires`: if gekko supports automatic trading, this is an array of required api credentials gekko needs to pass into the constructor.\n- `forceReorderDelay`: if after canceling an order a new one can't be created straight away since the balance is not updated fast enough, set this to true (only required for exchanges where Gekko can trade).\n- `gekkoBroker`: set this to \"0.6.2\" for now, it indicates the version of Gekko Broker this wrapper is compatible with.\n- `limitedCancelConfirmation` set to true if (in any case) the wrapper does NOT include partial fill information in the response (which is passed as the cancel callback)\n\nBelow is a real-case example how `bistamp` exchange provides its `getCapabilities()` method:\n\n```\nTrader.getCapabilities = function () {\n  return {\n    name: 'Bitstamp',\n    slug: 'bitstamp',\n    currencies: ['USD', 'EUR'],\n    assets: ['BTC', 'EUR'],\n    maxTradesAge: 60,\n    maxHistoryFetch: null,\n    markets: [\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 1, unit: 'currency' } },\n      { pair: ['EUR', 'BTC'], minimalOrder: { amount: 1, unit: 'currency' } },\n      { pair: ['USD', 'EUR'], minimalOrder: { amount: 1, unit: 'currency' } }\n    ],\n    requires: ['key', 'secret', 'username'],\n    fetchTimespan: 60,\n    tid: 'tid',\n    gekkoBroker: '0.6.2',\n    limitedCancelConfirmation: false\n  };\n}\n```\n"
  },
  {
    "path": "docs/extending/other_software.md",
    "content": "# Other Software\n\nSince Gekko version 0.4 Gekko can launch a process which exposes a web (REST and Websocket) API that can be used to control Gekkos (start a backtest, start a running Gekko, etc). This makes it easy for other people to build new functionality on top of Gekko without having to work with Gekko internals, the runtime (or even javascript at all).\n\n## List\n### Backtesters\n- [japonicus](https://github.com/Gab0/japonicus)\n- [gekkoga](https://github.com/gekkowarez/gekkoga)\n- [Gekko-BacktestTool](https://github.com/xFFFFF/GekkoBacktestTool)\n- [Gekko Automated Backtest](https://github.com/tommiehansen/gab)\n- [Gekko Warez Bruteforce Backtester](https://github.com/gekkowarez/bruteforce)\n\n### UI mode\n- [Unofficial Material UI](https://github.com/H256/gekko-quasar-ui)\n- [Controlling bots](https://github.com/CyborgDroid/gekko-python)\n\n### CLI mode\n- [Batch generation of configuration files](https://github.com/bettimms/multi-gekko)\n\n### Plugins\n- [Store trades in Google SpreadSheet](https://github.com/RJPGriffin/google-forms-gekko-plugin)\n"
  },
  {
    "path": "docs/features/backtesting.md",
    "content": "# Backtesting\n\nGekko supports backtesting strategies over historical data. A Backtest is a simulation where you simulate running a strategy over a long time (such as the last 30 days) in a matter of seconds. Backtesting requires having market data locally available already. After a backtest Gekko will provide statistics about the market and the strategy's performance.\n\n![screen shot of gekko backtesting](https://cloud.githubusercontent.com/assets/969743/24838718/8c790a86-1d45-11e7-99ae-e7e551cb40cb.png)\n\n**Important things to remember:**\n\n- Just because a strategy performed well in the past, does not mean it will perform well in the future.\n- Be careful of overfitting, in other words: don't simply tweak a strategy until you get high profit and assume that will be as profitable when going live. Read more about overfitting in [this article](https://laplaceinsights.com/backtesting-strategies-and-overfitting/).\n- The backtest simulation is limited, this is not really a problem on bigger markets (such as BTC/USD) but the differences between backtests and live traders on very low volume markets might be big. Read more about this below in the simplified simulation below.\n\n## Simplified simulation\n\nSimulating trades is done through a module called the paper trader. This module will use market candles together with fee, slippage and spread numbers to estimate trade executions costs. While the default settings work great for most big markets (USD/BTC or BTC/ETH), it becomes a lot less acurate on smaller markets with low volume and liquidity.\n\nIn live trading the notion of the \"price\" is more complicated than a single number. Both `spread` and `slippage` will effect your trade prices: these numbers describe your desired trades in relation to what people are currently offering in the market (this is called the orderbook). Read more about this in [this explanation](https://github.com/askmike/gekko/issues/2380#issuecomment-408744682).\n\nIf you look at the following backtest result:\n\n![screen shot of backtesting at an illiquid market](https://cloud.githubusercontent.com/assets/969743/24840243/8f307022-1d61-11e7-9964-e6614d7433ea.png)\n\nYou can see a lot of \"spikes\" of the price moving up and down. These are not actually price fluctuations but simply trades that happen on both sides of the orderbook (a bid is taken then an ask is taken). How far it jumps up and down is the spread (between the asks and the bids). In these cases the statistics from the simulation won't be very accurate (unless you configured a higher slippage to account for the spread). This is unfortunately a limitation in Gekko's backtesting model.\n"
  },
  {
    "path": "docs/features/importing.md",
    "content": "# Importing\n\nIn order to [backtest](./backtesting.md) your strategies you will need to have historical market data to test with. The easiest way of getting this data is importing it directly from the exchange using the Gekko UI (note that this is not supported at all exchanges, check [this list](../introduction/supported_exchanges.md) to see what exchanges Gekko can import from).\n\nYou can start an import by navigating to the tab \"Local tab\" and scrolling to the bottom and click \"Go to the importer\". This brings you to the importing page with this at the bottom:\n\n![importing wizard](https://user-images.githubusercontent.com/969743/28596822-a79509cc-7192-11e7-9293-53066f598053.png)\n\nOnce you configure the market and daterange you want to watch and click import Gekko will automatically download historical market data from the exchange:\n\n![gekko importer](https://user-images.githubusercontent.com/969743/28597211-914dbe32-7194-11e7-8352-60a69afdf846.png)\n"
  },
  {
    "path": "docs/features/paper_trading.md",
    "content": "# Paper trading\n\nGekko can automatically run a strategy over the live markets and simulate in realtime what happen if you would have traded on its signals. Paper trading and [backtesting](./backtesting.md) are the two simulation modes that come with Gekko. It's a great way to experiment with strategies without putting your money on the line.\n\nYou can start a paper trader by going to live gekkos and clicking on \"Start a new live Gekko\".\n\nKeep in mind that a paper trader is a simulation, and the accuracy depends on the market you decide to run it on (you'll get pretty accurate results on big markets like USD/BTC). You can read more about the details and limitations of the simulation on [the backtesting page](./backtesting.md#Simplified-simulation).\n"
  },
  {
    "path": "docs/features/trading_bot.md",
    "content": "# Trading bot\n\nOnce you have run enough simulations (using [backtesting](./backtesting.md) and [paper trading](./paper_trading.md)) and you are confident in your strategy you can use Gekko as a trading bot.\n\nGekko will run your strategy on the live market and automatically trade on your exchange account when trade signals come out of your strategy.\n\n## Preparation\n\n1. Make sure you are fully confident in your strategy! If you want to play around use either the [paper trader](./paper_trading.md) or the [backtester](./backtesting.md). Once you are confident continue with this list.\n2. Gekko will need to have API keys to your exchange account that have permissions to view balances and orders and create new orders. Keep in mind:\n  - Gekko does NOT need withdrawal access, for your safety DO NOT create API keys that can withdraw.\n  - Make sure you only use the API key for Gekko, and for nothing else. If in doubt create a new key (and remove stale ones).\n  - If possible try to restrict the API key to the IP address you will run Gekko from (this makes moest sense in server environments)\n3. Start your gekko through either the UI or the commandline interface!\n\n## Notes\n\nGekko will trade on the market you configured that consists of two currencies (for example USD/BTC):\n  - Try to not trade either of these currencies on the account you use with Gekko. (in the example above: don't trade any USD nor any BTC). \n  - Try to not withdraw or deposit more of either of these currencies.\n\nWhile Gekko will handle the situations above, all the profit calculations will be incorrect since your balances are taken into account while calculating profits.\n"
  },
  {
    "path": "docs/gekko-broker/introduction.md",
    "content": "# Gekko Broker\n\nOrder execution library for bitcoin and crypto exchanges. This library is Gekko's execution engine for all live orders (simulated orders do not through Gekko Broker, they go through the paper trader). This library is intended for developers of trading systems in need for advanced order types on multiple exchanges over a unified API.\n\n## Introduction\n\nThis library makes it easy to do (advanced) orders all crypto exchanges where Gekko can live trade at. See the complete list [here](https://gekko.wizb.it/docs/introduction/supported_exchanges.html).\n\nThis library allows you to:\n\n- Get basic market data\n  - ticker (BBO)\n  - ~orderbook~ (TODO)\n  - historical trades\n- Get portfolio data\n- Do an (advanced) order:\n  - Submit the order to the exchange\n  - Receive events about the status of the order:\n    - submitted\n    - open (accepted)\n    - partially filled\n    - rejected\n    - completed\n  - Mutate the order\n    - cancel\n    - amend\n      - move\n      - move limit\n- Tracks orders submitted through the library.\n\n## Status\n\nEarly WIP. All communication is via the REST APIs of exchanges. Not all exchanges are supported, see which ones are in [this doc](../introduction/supported_exchanges.md).\n\n## Order types\n\nThis library aims to offer advanced order types, even on exchanges that do not natively support them by tracking the market and supplementing native order support on specific exchanges.\n\nWorking:\n\n- Base orders\n  - [Sticky Order](./sticky_order.md)\n\nTODO:\n\n- Base orders:\n  - Limit Order\n  - Market Order\n- Triggers:\n  - Stop\n  - If Touched (stop but opposite direction)\n\n### Example\n\nSet up a Gekko Broker instance:\n\n    // from the gekko repo (make sure you have deps installed\n    // inside the exchange folder).\n    const Broker = require('../gekko/exchange/GekkoBroker');\n    // or from NPM\n    // const Broker = require('gekko-broker');\n\n    const binance = new Broker({\n      currency: 'USDT',\n      asset: 'BTC',\n      private: true,\n\n      exchange: 'binance',\n      key: 'x', // add your API key\n      secret: 'y' // add your API secret\n    });\n\nNow we have an instance that can create a [sticky order](./sticky_order.md):\n\n    const type = 'sticky';\n    const side = 'buy';\n    const amount = 1;\n\n    const order = binance.createOrder(type, side, amount);\n\n    order.on('statusChange', s => console.log(now(), 'new status', s));\n    order.on('fill', s => console.log(now(), 'filled', s));\n    order.on('error', s => console.log(now(), 'error!', e));\n    order.on('completed', a => {\n      console.log(new Date, 'completed!');\n      order.createSummary((err, s) => {\n        console.log(new Date, 'summary:');\n        console.log(JSON.stringify(s, null, 2));\n      });\n    });\n\nThis one doesn't have an upper limit price for what it will buy at. It will stick it's bid offer at BBO until it's filled. If you have a limit in mind you can specify it when creating, do this instead:\n\n    const order = binance.createOrder(type, side, amount, { limit: 100 });\n\nIt will never offer to buy for more than 100, even if the BBO is above 100 (the bid will end up deep in the book).\n\nAt any point in time you can change the limit (or the amount), for example:\n\n    order.moveLimit(120);\n\nRunning the above example (without setting a limit and moving it) will yield:\n\n    root@foxtail:~/gb/nusadua# node b\n    2018-07-29 03:46:02 new status SUBMITTED\n    2018-07-29 03:46:02 new status OPEN\n    2018-07-29 03:46:04 filled 1\n    2018-07-29 03:46:04 new status FILLED\n    2018-07-29T03:46:04.127Z 'completed!'\n    2018-07-29T03:46:04.358Z 'summary:'\n    {\n      \"price\": 0.0017479,\n      \"amount\": 1,\n      \"date\": \"2018-07-29T03:46:02.576Z\",\n      \"side\": \"buy\",\n      \"orders\": 1,\n      \"fees\": {\n        \"BNB\": 0.00075\n      },\n      \"feePercent\": 0.075\n    }\n\nNOTE: not all status changes are documented and more events are planned but not implemented.\n\n### TODO\n\n- finish all exchange integrations that gekko supports\n- finish all order types and triggers (under todo)\n- implement websocket support (per exchange)\n- use native move API calls wherever possible (poloniex)\n"
  },
  {
    "path": "docs/gekko-broker/sticky_order.md",
    "content": "# Sticky Order\n\nAn advanced order that stays at the top of the book (until the optional limit). The order will automatically stick to the best BBO until the complete amount has been filled.\n\nTODO:\n\n- implement fallback for when this order is alone at the top, some spread before everyone else\n- finalize API\n- add more events / ways to debug\n- pull ticker data out of this order market data should flow from the broker (so we can easier move to at least public websocket streams).\n\n## Example usage\n\n    const Broker = require('gekko-broker');\n\n    const gdax = new Broker({\n      currency: 'EUR',\n      asset: 'BTC',\n\n      exchange: 'gdax',\n\n      // Enables access to private endpoints.\n      // Needed to create orders and fetch portfolio\n      private: true,\n\n      key: 'x',\n      secret: 'y',\n      passphrase: 'z'\n    });\n\n    gdax.portfolio.setBalances(console.log);\n\n    const type = 'sticky';\n    const amount = 0.5;\n    const side = 'buy';\n    const limit = 6555;\n\n    const order = gdax.createOrder(type, side, amount, { limit });\n    order.on('statusChange', status => console.log(status));\n    order.on('filled', result => console.log(result));\n    order.on('completed', () => {\n      order.createSummary(summary => console.log)\n    });\n\n    // mutate like so\n\n    // order.moveAmount(1);\n    // order.moveLimit(6666);"
  },
  {
    "path": "docs/gekko-broker/wrapper_api.md",
    "content": "# Wrapper API\n\nGekko Broker is a library that sits between trading applications and Gekko Broker Exchange Wrappers. Which means it has two APIs to communicate with other code:\n\n![diagram describing Gekko Broker API interface](https://user-images.githubusercontent.com/969743/41892153-566293a0-7941-11e8-9998-7a5b5b554ffd.png)\n\nThis document descibres the API layer between the exchange wrappers and Gekko Broker.\n\n## Wrapper API spec\n\nThe current API documentation is currently located [here](../extending/add_an_exchange.md).\n\n## Wrapper API Changelog\n\n### Gekko 0.5.x to Gekko (Broker) 0.6.0\n\nNOTE: this API design might still have minor changes leading up to the release of Gekko 0.6. See [this thread](https://forum.gekko.wizb.it/thread-57279-post-59207.html) for more information.\n\n- The wrapper files are now nested different (from `gekko/exchanges` to `gekkobroker/wrappers` (which equals `gekko/exchange/wrappers` for Gekko users).\n- cancelOrder now requires a second parameter to be passed (that indicates whether the order was filled before it was canceled), see [details](https://github.com/askmike/gekko/commit/0e301f7d66e24ec97327f5f01380f691cc2d3725#diff-dbfe320ca090e208be32459d98fc11ed).\n- checkOrder now expects an object with a few properties to be returned, see [details](https://github.com/askmike/gekko/commit/e0d4a7362cd74b4b4f50759b1012ce489ea44a0c#diff-dbfe320ca090e208be32459d98fc11ed).\n- Error handling has gotten a lot more complex, with an updated error interface between a retry system (provided by Gekko) and the exchange wrapper. [Read more here](https://github.com/askmike/gekko/commit/e0d4a7362cd74b4b4f50759b1012ce489ea44a0c#diff-dbfe320ca090e208be32459d98fc11ed).\n"
  },
  {
    "path": "docs/installation/configuring_gekko_on_a_server.md",
    "content": "# Configuring Gekko on a server\n\n*NOTE: unfortunately configuring Gekko to run on a server is hard. Unless you are running in a completely trusted network (home network) you WILL need to get an SSL certificate, upstream Gekko through a webserver, etc. I am creating an official Gekko service called [Gekko Plus](https://gekkoplus.com/) that will NOT require any of this stuff.*\n\nGekko runs great headless (on a server, raspberry PI) but the default configuration assumes that you will be using a browser from the same machine to access the interface.\n\n# Installation\n\nPlease see the normal [installing gekko](./installing_gekko.md) document, but before starting gekko please update the configuration as stated below:\n\n# Configuring Gekko\n\nIn order to setup Gekko so that you can access it remotely you need to open and edit the following file: `gekko/web/vue/dist/UIconfig.js`. You need to configure this file according to your use case:\n\n- You want to Gekko headless in a trusted environment (eg. on a raspberry pi or old laptop in your home network) - [see here](#configuring-gekko-to-run-headless-in-a-trusted-environment).\n- You want to run Gekko in the cloud on a server - [see here](#configuring-gekko-to-run-in-the-cloud).\n\n## Configuring Gekko to run headless in a trusted environment\n\nEdit the uiconfig file like so:\n\n    const CONFIG = {\n        headless: true,\n        api: {\n            host: '0.0.0.0',\n            port: 3000,\n        },\n        ui: {\n            ssl: false,\n            host: 'x.x.x.x', // Set this to the IP of the machine that will run Gekko\n            port: 3000,\n            path: '/'\n        },\n        adapter: 'sqlite'\n\n    }\n\nYou can now access the Gekko UI by going to `http://x.x.x.x:3000` in a browser (change `x.x.x.x` with the IP of the machine that will run Gekko).\n\n\n## Configuring Gekko to run in the cloud\n\nImportant note: if you expose Gekko to the open internet (or on any non trusted network) you are recommended to put a secure reverse proxy (for example with both [SSL](#Obtaining-a-SSL-certificate) and [BasicAuth](#Create-htpasswd-for-basic-password-authentication)) in front of it. While we believe Gekko is hard to exploit, it allows for 24/7 backtesting which will drain your machine's resources (possible DoS).\n\nThe following assumes you configured a reverse proxy, if you did not simply follow [these instructions](#Configuring-NGINX-as-a-reverse-proxy) to do so.\n\n\n    const CONFIG = {\n        headless: true,\n        api: {\n            host: '127.0.0.1',\n            port: 3000,\n        },\n        ui: {\n            ssl: true,\n            host: 'gekko.example.com',\n            port: 443,\n            path: '/' // change this if you are serving from something like `example.com/gekko`\n        },\n        adapter: 'sqlite'\n    }\n\n\n## Configuring NGINX as a reverse proxy\n\nNGINX is a highly configurable, lightweight, yet easily deployed webserver allowing features such as a reverse proxying using secure sockets layer with authentication and much more.\n\nInstalling NGINX using your Operating Systems package manager of choice is pretty straight forward. For Debian Linux it is a simple sudo apt-get install nginx\n\nOnce NGINX is installed you will need to modify the configuration file. For Debian Linux the config is located at /etc/nginx/sites-enabled/default\n\n    server {\n        listen 80;\n        listen [::]:80;\n        server_name gekko.example.com;\n        return 301 https://$server_name$request_uri;\n    }\n\n    upstream websocket {\n        server localhost:3000;\n    }\n\n    server {\n        listen 443 ssl;\n        listen [::]:443 ssl;\n        root /var/www/html;\n\n        ssl_certificate /etc/nginx/ssl/nginx.crt;\n        ssl_certificate_key /etc/nginx/ssl/nginx.key;\t\n\n        location / {\n                proxy_buffers 8 32k;\n                proxy_buffer_size 64k;\n\n                proxy_pass http://websocket;\n                proxy_set_header X-Real-IP $remote_addr;\n                proxy_set_header Host $http_host;\n                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n                proxy_set_header X-NginX-Proxy true;\n\n                proxy_http_version 1.1;\n                proxy_set_header Upgrade $http_upgrade;\n                proxy_set_header Connection \"upgrade\";\n\n                proxy_read_timeout 86400s;\n                proxy_send_timeout 86400s;\n\n                auth_basic \"Restricted Content\";\n                auth_basic_user_file /etc/nginx/.htpasswd;\n        }\n    }\n\n\n## Obtaining a SSL certificate\n\nYour OS may or may not ship with openssl preinstalled. In the case it doesn't, simply install openssl using your package manager of choice. eg: `sudo apt-get install openssl`.\n\nBelow you can choose between creating a self signed certificate useful if you do not have a fqdn (fully qualified domain name), or if you by chance do have a fqdn you can use certbot to obtain a Let's Encrypt CA signed certificate.\n\n\n### To create a self signed certificate:\n\n    sudo mkdir /etc/nginx/ssl\n    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt\n\n\n### To obtain a Let's Encrypt CA signed certificate:\n\nInstall certbot, a client to obtain signed ssl certificates for your domain.\n\n    sudo apt-get install certbot\n\nRun the following command:\n\n    certbot certonly --standalone -d example.com -d gekko.example.com\n\nModify your NGINX config and replace the ssl lines with the following:\n\n        ssl_certificate                 /etc/letsencrypt/live/example.com/fullchain.pem;\n        ssl_certificate_key             /etc/letsencrypt/live/example.com/privkey.pem;\n        add_header                      Strict-Transport-Security \"max-age=31536000\";\n\n\n## Create htpasswd for basic password authentication\n\nChange username to desired username and enter password when prompted:\n\n    printf \"username:`openssl passwd -apr1`\\n\" >> /etc/nginx/.htpasswd\n"
  },
  {
    "path": "docs/installation/installing_gekko.md",
    "content": "# Installing Gekko\n\n*NOTE: unfortunately installing and managing Gekko is hard. You will need to touch the commandline and install a few developer tools. I am creating an official Gekko service called [Gekko Plus](https://gekkoplus.com/) that will NOT require any installation.*\n\n- *Windows user? Please see the doc [installing Gekko on windows](./installing_gekko_on_windows.md) instead.*\n- *Docker user? You can run Gekko in a docker container, see [installing Gekko using Docker](./installing_gekko_using_docker.md) instead.*\n- *Server user? In order to run Gekko headless, see [configuring Gekko on a server](./configuring_gekko_on_a_server.md) instead.*\n\nHere is a video of me explaining how to install Gekko the easiest way possible:\n\n[![screen shot 2017-04-20 at 00 03 45](https://cloud.githubusercontent.com/assets/969743/25205894/e7f4ea64-255c-11e7-891b-28c080a9fbf2.png)](https://www.youtube.com/watch?v=R68IwVujju8)\n\n\nTo get Gekko running you need to do the following:\n\n- install nodejs\n- install git\n- download Gekko\n- install Gekko & Gekko Broker dependencies\n\n## Installing nodejs\n\nGekko requires [nodejs](https://nodejs.org/en/) to be installed. Go ahead and install this if it's not already (Gekko requires at least version 8.11.2). We advice to download the current LTS.\n\n## Installing git\n\nAs part of Gekko's installation process git is used, see [this guide](https://www.linode.com/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/) for installation instructions. If you do not already have git on your system.\n\n## Downloading Gekko\n\nThe recommended way of downloading Gekko is by using git. This makes keeping Gekko up to date a lot easier. Run this in a terminal:\n\n    git clone git://github.com/askmike/gekko.git -b stable\n    cd gekko\n\nThis will download the latest stable version of Gekko, remove the final `-b stable` part to download the current latest release (which might not be as stable).\n\nAlternatively you can manually download the latest stable version of Gekko on the [releases page](https://github.com/askmike/gekko/releases).\n\n## Installing Gekko's dependencies\n\nOnce you have Gekko downloaded you need to install the dependencies, open your terminal and navigate to the gekko folder and run:\n\n    npm install --only=production\n\n*NOTE: You may see a vulnerability warning from NPM, if you run npm audit with --force, Gekko will break. See [here](https://github.com/askmike/gekko/issues/2585#issuecomment-428450997).*\n\nYou also need to install Gekko Broker's dependencies, run:\n\n    cd exchange\n    npm install --only=production\n    cd ..\n\n## Starting Gekko\n\nAfter all the above you can start Gekko by running the following in your terminal:\n\n    node gekko --ui\n\n## Updating Gekko\n\nSee the [updating Gekko](./updating_gekko.md) doc.\n"
  },
  {
    "path": "docs/installation/installing_gekko_on_raspberry_pi_2_or_3.md",
    "content": "# Installing Gekko on Raspberry Pi 2 or 3\n\nThis manual is intended for a Raspberry Pi 2 or 3 with freshly installed Raspbian Stretch (Lite).\n\nTo get Gekko running on your Pi you need to do the following:\n\n- update your package lists\n- install nodejs\n- download Gekko\n- install Gekko's dependencies\n- (optional) Configure your Pi as a headless server in your local network\n\n## Update your package lists\n\n    sudo apt-get update\n    sudo apt-get upgrade\n\n## Installing nodejs\n\nWe recommend installing the latest LTS Version of Node, currently 8.x.x\n\n    curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -\n    sudo apt-get install -y nodejs\n\nImportant: Ignore the errors!\n=> It automatically builds from source instead, it can take over 10 minutes! Do not abort the process\n\n## Downloading Gekko\n\nThe recommended way of downloading Gekko is by using git. This makes keeping Gekko up to date a lot easier. Run this in a terminal:\n\n    sudo apt-get install git\n    git clone git://github.com/askmike/gekko.git -b stable\n    cd gekko\n\nThis will download the latest stable version of Gekko, remove the final `-b stable` part to download the current latest release (which might not be as stable).\n\n## Installing Gekko's dependencies\n\nOnce you have Gekko downloaded you need to install the dependencies, open your terminal and navigate to the gekko folder and run:\n\n    npm install --only=production\n    cd exchange\n    npm install --only=production\n    cd ..\n\n## Configure your Pi as a headless server\n\n    cd web/vue/dist\n    nano UIconfig.js\n\nSet headless to true\n\nSet api.host to 0.0.0.0\n\nSet ui.host to Pi's IP address (e.g. 192.168.1.74)\n\n## Starting Gekko\n\nAfter all the above you can start Gekko by running the following in your terminal:\n\n    node gekko --ui\n\nOpen your browser and type in Pi's IP:port (default port: 3000)\n\n## Updating Gekko\n\nSee the [updating Gekko](./updating_gekko.md) doc.\n\n## Run gekko in background\nIf you access Pi headless via SSH, you have to use a software like tmux to run Gekko in background\n\n## Installing Gekko on Raspberry Pi 1\nIt is possible to run Gekko on Raspberry Pi 1, but you have to manually install Nodejs armv6 version\n"
  },
  {
    "path": "docs/installation/installing_gekko_on_windows.md",
    "content": "# Installing Gekko on windows\n\n*NOTE: unfortunately installing and managing Gekko is hard. You will need to touch the commandline and install a few developer tools. I am creating an official Gekko service called [Gekko Plus](https://gekkoplus.com/), it will NOT require any installation.*\n\n### Note:\n#### Windows does not natively support TA-lib. We are currently working on implementing the Tulip Indicators Library, which will provide similar functionality (see [#708](https://github.com/askmike/gekko/issues/708)).\n#### For advanced users only: As a temporary workaround until [#708](https://github.com/askmike/gekko/issues/708) is implemented, TA-lib can be used on Windows through Bash on Windows 10. See \"Installing Gekko on Windows with bash on Windows 10\"\n\nHere is a youtube video I made that shows exactly how to set up Gekko:\n\n[![screen shot 2017-04-20 at 00 03 45](https://cloud.githubusercontent.com/assets/969743/25205894/e7f4ea64-255c-11e7-891b-28c080a9fbf2.png)](https://www.youtube.com/watch?v=R68IwVujju8)\n\nTo get Gekko running on Windows you need to do the following:\n\n- install nodejs\n- download Gekko\n- install Gekko's dependencies\n\n## Install nodejs\n\nGekko runs on nodejs so we have to install that first. Head over the [nodejs homepage](http://nodejs.org/) and install the LTS version of nodejs.\n\n## Install Gekko\n\nThe easiest way to download Gekko is to go to the [Github repo](https://github.com/askmike/gekko) and click on the 'zip' button at the top. Once you have downloaded the zip file it's the easiest to extract it. When you have done that we can begin with the cool stuff:\n\n### Open up command line\n\n* Start \n* Type in 'cmd.exe'\n* Press enter\n\n### Install dependencies\n\n(After every command, press enter)\n\nFirst navigate to Gekko:\n\n    cd Downloads\n    cd gekko-stable\n    cd gekko-stable\n    \nInstall Gekko's dependencies:\n\n    npm install --only=production\n\n*NOTE: You may see a vulnerability warning from NPM, if you run npm audit with --force, Gekko will break. See [here](https://github.com/askmike/gekko/issues/2585#issuecomment-428450997).*\n\nInstall Gekko Broker's dependencies:\n\n    cd exchange\n    npm install --only=production\n    cd ..\n\n### Install Tulip Indicators\n\nIf you are using Windows you will need to install python and the VC++ 2015 build tool, the easiest way to do this is through node as an administrator:\n\n    npm install windows-build-tools --global --production\n\nOnce your build tools are installed, or for other operating systems\n\n    npm install tulind --only=production\n    \n### Starting Gekko\n\n    node gekko --ui\n\nYour browser should automatically open with the UI. If it doesn't, manually browse to [http://localhost:3000](http://localhost:3000).\n    \n### Stopping Gekko\n\nIn the command line hold `ctrl` + `c`.\n\n### Updating Gekko\n\nSee the [updating Gekko](./updating_gekko.md) doc.\n"
  },
  {
    "path": "docs/installation/installing_gekko_on_windows_with_bash_on_windows_10.md",
    "content": "# Installing Gekko on Windows with bash on Windows 10\n\n*NOTE: unfortunately installing and managing Gekko is hard. You will need to touch the commandline and install a few developer tools. I am creating an official Gekko service called [Gekko Plus](https://gekkoplus.com/), it will NOT require any installation.*\n\n### Note: \n#### This guide is for advance users only! This is a temporary solution until [#708](https://github.com/askmike/gekko/issues/708) is implemented\n#### You must be running a 64-bit version of Windows 10 to use Bash on Windows 10\n#### TA-lib does not support Windows 10, but it can be used on Bash on Windows 10 by following these instructions \n\n\n## To get Gekko running on Bash on Windows you need to do the following:\n\n- enable Bash on Windows 10\n- install nodejs\n- install git\n- download and install Gekko and its dependencies\n- edit the handle.js file\n- install the correct version of TA-lib\n\n## Enable Bash on Windows 10\n\nTo install Bash shell on your Windows 10 PC, do the following (see [here](https://www.windowscentral.com/how-install-bash-shell-command-line-windows-10) for more info):\n\n- Open Settings. \n- Click on Update & security. \n- Click on For Developers.\n- Under \"Use developer features\", select the Developer mode option to setup the environment to install Bash.\n- On the message box, click Yes to turn on developer mode.\n- After the necessary components install, you'll need to restart your computer. \n- Once your computer reboots, open Control Panel. \n- Click on Programs.\n- Click on Turn Windows features on or off.\n- Check the Windows Subsystem for Linux (beta) option.\n- Click OK.\n- Once the components installed on your computer, click the Restart now button to complete the task.\n\nAfter your computer restarts, you will notice that Bash will not appear in the \"Recently added\" list of apps, this is because Bash isn't actually installed yet. Now that you have setup the necessary components, use the following steps to complete the installation of Bash:\n\n- Open Start, do a search for bash.exe, and press Enter.\n- On the command prompt, type y and press Enter to download and install Bash from the Windows Store.\n\nThen you'll need to create a default UNIX user account. This account doesn't have to be the same as your Windows account. Enter the username in the required field and press Enter (you can't use the username \"admin\"). Close the \"bash.exe\" command prompt.\nNow that you completed the installation and setup, you can open the Bash tool from the Start menu like you would with any other app.\n\n## Install nodejs\n\nGekko runs on nodejs so we have to install that first. \n\nOpen up bash and install node.js: (taken from [here](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions))\n\n```\nsudo apt-get update\ncurl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -\nsudo apt-get install -y nodejs\nsudo apt-get install -y build-essential\n```\n\n## Install Gekko and its dependencies\n\nThe easiest way to download Gekko is to use Git: \n\n- Install Git\n\n`sudo apt-get install git`\n\n- Download and install gekko in you home directory (/home/yourusername): (taken from [here](https://gekko.wizb.it/docs/installation/installing_gekko.html)):\n\n```\ngit clone git://github.com/askmike/gekko.git\ncd gekko\nnpm install --only=production\ncd exchange\nnpm install --only=production\ncd ..\n```\n\n*NOTE: You may see a vulnerability warning from NPM, if you run npm audit with --force, Gekko will break. See [here](https://github.com/askmike/gekko/issues/2585#issuecomment-428450997).*\n\n### Starting Gekko\n\n`node gekko --ui`\n\nYour browser should automatically open with the UI. If it doesn't, manually browse to [http://localhost:3000](http://localhost:3000).\n    \n### Stopping Gekko\n\nIn bash hold `ctrl` + `c`.\n\n### Updating Gekko\n\nSee the [updating Gekko](./updating_gekko.md) doc.\n"
  },
  {
    "path": "docs/installation/installing_gekko_using_docker.md",
    "content": "# Installing Gekko using Docker\n\nInstalling and running gekko in a docker container for use on the same machine is simple with the following commands:\n\n```\n$ docker-compose build\n$ docker-compose up -d\n```\n\nYou can now find your gekko instance running on `localhost:3000`.\n\n## Installing for external access\n\nHowever if you want to run Gekko on another machine (in the cloud, on a server), you need to specify the host machine and its port like so:\n\n```\n$ docker-compose build\n$ HOST=mydomain.com PORT=3001 docker-compose up -d\n``` \n\nYou can now find your gekko instance running on `mydomain.com:3001`.\n\nIf running behind an SSL-terminating proxy, make sure to set `USE_SSL=1` to tell the Gekko to use the HTTPS and WSS protocols instead of the default HTTP and WS protocols.\n\nTo see logs: `docker logs -f gekko_gekko_1`. View which dockers are running by executing `docker ps`.\n"
  },
  {
    "path": "docs/installation/updating_gekko.md",
    "content": "# Updating Gekko\n\n## Prepare\n\nBefore updating your local version of Gekko it's good to keep a few things in mind:\n\n- If you have configured a UIconfig (to run Gekko on a server for example) make a copy of the UIconfig file (stored in `gekko/web/vue/dist/`) first and call it something else (such as `my-UIconfig.js`). After that revert the file to it's original state (which can be found in `gekko/web/baseUIconfig.js/`) prior to updating (or git will complain).\n- Check the changelog (found in the [releases page](https://github.com/askmike/gekko/releases)) for breaking changes) regarding:\n  - (in case you changed the UIconfig) for changes in the UIconfig.\n  - (in case you were using non standard strategies) strategy API, to make sure your strategies will run in the new version.\n  - any other breaking changes specified inside the release log (such as required node and or browser versions).\n\n## Updating to a new stable release\n\nRun the following commands inside the Gekko directory:\n\n    git checkout stable\n    git pull\n    npm install --only=production\n    cd exchange\n    npm install --only=production\n    cd ..\n\n## Updating the develop branch\n\nThe develop branch contains the most recent code as we are working on Gekko. In most scenarios this should considered less stable. But note that once a bug is found and fixed the fixes are applied here immediately while it takes the release of a new version to have these changes available in the stable branch.\n\n    git checkout develop\n    git pull\n    npm install --only=production\n    cd exchange\n    npm install --only=production\n    cd ..\n\n### Compiling the frontend on the develop branch\n\nIf you are using the UI and it changed since the latest release you need to manually recompile it since (as of v0.6.2) Gekko only ships compiled frontends with new releases.\n\n    cd web/vue\n    npm install\n    npm run build\n    cd ../.."
  },
  {
    "path": "docs/internals/architecture.md",
    "content": "# Gekko's architecture\n\n![Gekko architecture](https://wizb.it/gekko/static/architecture.jpg)\n\nEvery Gekko instance has two core components:\n\n- A market\n- A GekkoStream\n\nCommunication between those two components is handled by Node.JS' [Stream API](https://nodejs.org/api/stream.html). The Market implements a Readable Stream interface while the GekkoStream implements a Writeable Stream interface.\n\n## A Market\n\nAll markets in Gekko eventually output `candle` data. Where these candles come from and how old they are does not matter to the GekkoStream they get piped into. On default Gekko looks for markets in the [`core/markets/` directory](https://github.com/askmike/gekko/tree/stable/core/markets). The top orange block in the picture is a BudFox market (the default semi-realtime market that gets live data from exchanges).\n\nExample Markets that come included with Gekko are:\n\n- **BudFox** (a realtime market): this market stays on indefinitely and outputs candles from the live markets in semi-realtime (cryptocurrency exchanges run 24/7).\n- **backtest**: this market reads candles from a database and outputs them as fast as the GekkoStream is able to consume them (the GekkoStream will run TA strategies over these candles).\n- **importer**: the importer market will fetch historical data from an exchange and pass on (to the GekkoStream who inserts them in a database).\n\n## A GekkoStream\n\nA GekkoStream is nothing more than a collection of [plugins](../commandline/plugins.md). Plugins are simple modules that can subscribe to events, and do something based on event data. The most basic event every GekkoStream has is the \"candle\" event, this event comes from the market.\n\nHowever **plugins are allowed to broadcast their own events, which other plugins can subscribe to**. An example of this is the `tradingAdvisor` plugin. This plugin will implement a [strategy](../strategies/introduction.md) that will be fed candle data. As soon as the strategy suggests to take a certain position in the market (\"I detect an uptrend, I advice to go **long**\") it will broadcast an `advice` event. The `paperTrader` is a plugin that simulates trading using these advices, the `trader` is a plugin that creates real market orders based on these advices. You can decide to only turn the `paperTrader` on or to turn the `trader` on (you now have a live trading bot).\n\nWhen you run a backtest using Gekko the following things happen:\n\n- Gekko configures a `backtest` market.\n- Gekko loads all configured plugins that are supported in the `backtest` mode* into a GekkoStream.\n- Gekko pipes the market into the GekkoStream and voila!\n\n\\*Gekko refuses to load plugins that are unsupported in specific modes. During backtests you **never** want to enable the real trader to enter market orders. Because if you would the advice would be based on specific moments in the backtest, not on the current state of the market.\n\n## Plugins & Adapters\n\nThose two core components describe the majority of Gekko's flow. A lot \"core functionality\" like saving candles to disk are simply plugins that push all candles to a database.\n\n## Separated architecture\n\nThe modular nature of Gekko makes it very dynamic and allows for rapidly creating new plugins. However there is an ugly side to this story:\n\nThe `tradingAdvisor` runs TA strategies against a market. The problem however is that most TA indicators need some history before they can give accurate results. If you want to use an EMA (exponential moving average), you need some history to base the initial average on. But because the tradingAdvisor doesn't know what market data is going to be made available later by the market, it needs to do some fetching itself and compare that to locally available market data (stored in the local database) to see if it can stitch the two sources.\n"
  },
  {
    "path": "docs/internals/budfox.md",
    "content": "# BudFox\n\n**Similar to the [movie Wallstreet](https://en.wikipedia.org/wiki/Wall_Street_(1987_film)), Gekko delegates the dirty work of getting fresh data to Bud Fox. Bud Fox delivers the data to Gekko who uses this data to make investment decisions.**\n\nWhenever Gekko works with realtime market data, it spawns a BudFox to fetch and transform the data for every market (exchange + asset + pair, for example: `bitstamp USD/BTC`). Bud Fox will keep on fetching data from the market in semi-realtime, turn historical trades into minutely candles (and make sure every minute of data has a candle).\n\nBudFox exposes a stream of `candles` which are fed to Gekko.\n\n## Advanced Usage\n\nBudFox is a small part of Gekko's core that aggregates realtime market data from any supported exchange into a readable stream of candles. Example usage:\n\n    var config = {\n        exchange: 'Bitstamp',\n        currency: 'USD',\n        asset: 'BTC'\n    }\n\n    new BudFox(config)\n      .start()\n      // convert JS objects to JSON string\n      .pipe(new require('stringify-stream')())\n      // output to standard out\n      .pipe(process.stdout);\n\nOutputs:\n\n    {\"start\":\"2015-02-02T23:08:00.000Z\",\"open\":238.21,\"high\":239.35,\"low\":238.21,\"close\":238.66,\"vwp\":8743.778447997309,\"volume\":203.6969347,\"trades\":56}\n    {\"start\":\"2015-02-02T23:09:00.000Z\",\"open\":239.03,\"high\":240,\"low\":238.21,\"close\":239.19,\"vwp\":8725.27119145289,\"volume\":323.66383462999994,\"trades\":72}\n    {\"start\":\"2015-02-02T23:10:00.000Z\",\"open\":239.19,\"high\":239.8,\"low\":234.68,\"close\":235,\"vwp\":6664.509955946812,\"volume\":114.67727173,\"trades\":48}\n    {\"start\":\"2015-02-02T23:11:00.000Z\",\"open\":237.77,\"high\":238.51,\"low\":235,\"close\":238.1,\"vwp\":3158.835462414369,\"volume\":41.47081054999999,\"trades\":28}\n    {\"start\":\"2015-02-02T23:12:00.000Z\",\"open\":237,\"high\":238,\"low\":236.78,\"close\":237.9,\"vwp\":1634.5173557116634,\"volume\":70.58755061,\"trades\":22}\n    {\"start\":\"2015-02-02T23:13:00.000Z\",\"open\":237.95,\"high\":238.49,\"low\":237.95,\"close\":238.49,\"vwp\":604.219141331534,\"volume\":12.196531389999999,\"trades\":7}\n    {\"start\":\"2015-02-02T23:14:00.000Z\",\"open\":238.51,\"high\":241,\"low\":237.89,\"close\":241,\"vwp\":7610.305142999085,\"volume\":579.5321983399998,\"trades\":67}\n    {\"start\":\"2015-02-02T23:15:00.000Z\",\"open\":238.12,\"high\":239.76,\"low\":238.12,\"close\":239.1,\"vwp\":1828.5872875471068,\"volume\":31.16232463,\"trades\":17}\n    {\"start\":\"2015-02-02T23:16:00.000Z\",\"open\":239.1,\"high\":239.76,\"low\":239.1,\"close\":239.67,\"vwp\":1339.3753800771717,\"volume\":5.56431998,\"trades\":12}\n    {\"start\":\"2015-02-02T23:17:00.000Z\",\"open\":239.27,\"high\":239.99,\"low\":239.25,\"close\":239.92,\"vwp\":1519.3392752690336,\"volume\":6.984999999999999,\"trades\":14}\n    {\"start\":\"2015-02-02T23:18:00.000Z\",\"open\":239.92,\"high\":239.98,\"low\":238.98,\"close\":238.98,\"vwp\":4162.807256131301,\"volume\":21.17212333,\"trades\":29}\n    {\"start\":\"2015-02-02T23:19:00.000Z\",\"open\":239,\"high\":239,\"low\":238.15,\"close\":238.33,\"vwp\":1627.2581467076204,\"volume\":31.682705360000003,\"trades\":15}\n    {\"start\":\"2015-02-02T23:20:00.000Z\",\"open\":238.33,\"high\":239.95,\"low\":238.33,\"close\":239,\"vwp\":3648.661808492067,\"volume\":128.35564560999998,\"trades\":23}\n    // etc..\n"
  },
  {
    "path": "docs/internals/events.md",
    "content": "# Events\n\nAs described in the [architecture](./architecture.md) events play a key role in the complete system: they relay all information between separate components (like [plugins](./plugins.md)). This makes the codebase scalable, testable and it separates concerns.\n\nif you run the Gekko UI events are relayed between core components as well as broadcasted (via the UI server) to the web UI. This means that all events broadcasted by any plugin automatically end up in the web UI.\n\nNote that all events from Gekko come from a plugin (with the exception of the `candle` event, which comes from the market), and no plugin is required for Gekko to run, this means it might be possible that some events are never broadcasted since their originating plugin is not active. If a plugin wants to listen to an event that will never be broadcasted (because of a lack of another plugin) this will be warned in the console like so:\n\n    (WARN): Paper Trader wanted to listen to the tradingAdvisor, however the tradingAdvisor is disabled.\n\n## List of events emitted by standard plugins\n\n- [candle](#candle-event): Every time Gekko calculates a new one minute candle from the market.\n- [stratWarmupCompleted](#stratWarmupCompleted-event): When the strategy is done warming up.\n- [advice](#advice-event): Every time the trading strategy has a new trading signal.\n- [stratUpdate](#stratUpdate-event): Every time the strategy has processed a new strat candle.\n- [stratNotification](#stratNotification-event): Every time the strategy emit new strategy notification.\n- [tradeInitiated](#tradeInitiated-event): Every time a trading plugin (either the live trader or the paper trader) is going to start a new trade (buy or sell).\n- [tradeCompleted](#tradeCompleted-event): Every time a trading plugin (either the live trader or the paper trader) has completed a trade.\n- [tradeAborted](#tradeAborted-event): Every time a trading plugin (either the live trader or the paper trader) has NOT acted on new advice (due to insufficient funds or a similar reason).\ntrader) has NOT acted on new advice (due to unsufficiant funds or a similar reason).\n- [tradeErrored](#tradeErrored-event): Every time the live trader was unable to execute an initialized.\n- [tradeCancelled](#tradeCancelled-event): Every time the live trader cancelled a not yet executed trade.\n- [portfolioChange](#portfolioChange-event): Every time the content of the portfolio has changed.\n- [portfolioValueChange](#portfolioValueChange-event): Every time value of the portfolio has changed.\n- [performanceReport](#performanceReport-event): Every time the profit report was updated.\n- [roundtrip](#roundtrip-event): Every time a new roundtrip has been completed.\n- [triggerCreated](#triggerCreated-event): Every time a trader has created a new trigger.\n- [triggerFired](#triggerFired-event): Every time a created trigger has fired.\n- [triggerAborted](#triggerAborted-event): Every time a created trigger has been aborted due to new advice.\n\nBeside those there are also two additional market events that are only emitted when Gekko is running in realtime mode (NOT during a backtest for performance reasons).\n\n- [marketStart](#marketStart-event): Once, when the market just started.\n- [marketUpdate](#marketUpdate-event): Whenever the market has fetched new raw market data.\n\n### candle event\n\n- What: An object containing a one minute candle from the market.\n- When: In liquid markets roughly every minute.\n- Subscribe: Your plugin can subscribe to this event by registering the `processCandle` method.\n- Async: When subscribing to this event the second argument will be a callback which you are expected to call when done handling this event.\n- Notes:\n  - Depending on the gekko configuration these candles might be historical on startup. If this is a concern for consumers, make sure to deal with this properly.\n  - In illiquid markets (of less than a trade per minute) Gekko will calculate these candles in batches and a few might come at the same time.\n  - These are always one minute candles, this is the lowest level of market data flowing through a gekko stream.\n- Example:\n      {\n        start: [moment object of the start time of the candle],\n        open: [number, open of candle],\n        high: [number, high of candle],\n        low: [number, low of candle],\n        close: [number, close of candle],\n        vwp: [number, average weighted price of candle],\n        volume: [number, total volume volume],\n        trades: [number, amount of trades]\n      }\n\n### stratWarmupCompleted event\n\n- What: An object signaling that the strategy is now completely warmed up\nand will start signaling advice.\n- When: Once the strategy consumed more market data than defined by the required history.\n- Subscribe: You can subscribe to this event by registering the `processWarmupCompleted` method.\n- Notes:\n  - This event is triggered on init when the strategy does not require any history (and thus no warmup time).\n- Example:\n      {\n        start: [moment object of the start time of the first candle after the warmup],\n      }\n\n### stratCandle event\n\n- What: An object describing an updated strat candle the strat has processed.\n- When: when the strategy is initialized is started.\n- Subscribe: You can subscribe to this event by registering the `processStratCandle` method.\n- Notes:\n  - This is the candle that the strategy sees: if you configured the candleSize to 60 (minutes) this event will contain a 60 minute candle.\n  - Strat Candles are emitted while the strategy is still warming up (before the `stratWarmupCompleted` event).\n- Example:\n      {\n        start: [moment object of the start time of the candle],\n        open: [number, open of candle],\n        high: [number, high of candle],\n        low: [number, low of candle],\n        close: [number, close of candle],\n        vwp: [number, average weighted price of candle],\n        volume: [number, total volume volume],\n        trades: [number, amount of trades]\n      }\n\n\n### stratUpdate event\n\n- What: An object describing updated state of the strategy based on a new strat candle.\n- When: when the strategy has\n- Subscribe: You can subscribe to this event by registering the `processStratUpdate` method.\n- Notes:\n  - Strat updates are emitted while the strategy is still warming up (before the `stratWarmupCompleted` event).\n- Example:\n      {\n        date: [moment object of the start time of the candle],\n        indicators: {\n          mymacd: [number, result of running this indicator over current candle]\n        }\n      }\n\n### stratNotification event\n\n- What: An object describing new notification from your strategy\n- When: when the strategy emit using `this.notify()` function\n- Subscribe: You can subscribe to this event by registering the `processStratNotification` method.\n- Example:\n      {\n        date: [moment object of the start time of the candle],\n        content: [String content notification in strategy]\n      }\n\n\n### advice event\n\n- What: An advice from the strategy, the advice will either be LONG or SHORT.\n- When: This depends on the strategy and the candleSize.\n- Subscribe: You can subscribe to this event by registering the `processAdvice` method.\n- Example:\n      {\n        recommendation: [position to take, either long or short],\n        date: [moment object of this advice],\n        id: [string identifying this unique trade],\n        trigger: {\n          type: [type of trigger, currently always \"trailingStop\"],\n          // optional parameters per type of trigger\n        }\n      }\n\n### tradeInitiated event\n\n- What: An object signaling that a new trade will be executed.\n- When: At the same time as the advice event if the trader will try to trade.\n- Subscribe: You can subscribe to this event by registering the `processTradeInitiated` method.\n- Example:\n      {\n        id: [string identifying this unique trade],\n        adviceId: [number specifying the advice id this trade is based on],\n        action: [either \"buy\" or \"sell\"],\n        date: [moment object, exchange time trade completed at],\n        portfolio: [object containing amount in currency, asset and total balance],\n        balance: [number, total worth of portfolio]\n      }\n\n### tradeAborted event\n\n- What: An object signaling the fact that the trader will ignore the advice.\n- When: At the same time as the advice event if the trader will NOT try to trade.\n- Subscribe: You can subscribe to this event by registering the `processTradeAborted` method.\n- Example:\n      {\n        id: [string identifying this unique trade],\n        adviceId: [number specifying the advice id this trade is based on],\n        action: [either \"buy\" or \"sell\"],\n        date: [moment object, exchange time trade completed at],\n        reason: [string explaining why the trade was aborted]\n      }\n\n### tradeCancelled event\n\n- What: An object signaling the fact that the a trade originally initiated was now cancelled.\n- When: After a receiving a tradeInitiated event and than a advice event (without a tradeCompleted event between them).\n- Subscribe: You can subscribe to this event by registering the `processTradeCanceled` method.\n- Example:\n      {\n        id: [string identifying this unique trade],\n        adviceId: [number specifying the advice id this trade is based on],\n        date: [moment object, exchange time trade completed at]\n      }\n\n### tradeErrored event\n\n- What: An object singaling the fact that the a trade orginially initiated was now cancelled\n- When: After a tradeInitiated event\n- Subscribe: You can subscribe to this event by registering the `processTradeErrored` method.\n- Example:\n      {\n        id: [string identifying this unique trade],\n        adviceId: [number specifying the advice id this trade is based on],\n        date: [moment object, exchange time trade completed at],\n        reason: [string explaining why the trade was aborted]\n      }\n\n### tradeCompleted event\n\n- What: Details of a completed trade.\n- When: Some point in time after the tradeInitiated event.\n- Subscribe: You can subscribe to this event by registering the `processTradeCompleted` method.\n- Example:\n      {\n        id: [string identifying this unique trade],\n        adviceId: [number specifying the advice id this trade is based on],\n        action: [either \"buy\" or \"sell\"],\n        price: [number, average price that was sold at],\n        amount: [number, how much asset was trades (excluding \"cost\")],\n        cost: [number the amount in currency representing fee, slippage and other execution costs],\n        date: [moment object, exchange time trade completed at],\n        portfolio: [object containing amount in currency and asset],\n        balance: [number, total worth of portfolio],\n        feePercent: [the cost in fees],\n        effectivePrice: [executed price - fee percent, if effective price of buy is below that of sell you are ALWAYS in profit.]\n      }\n\n### portfolioChange event\n\n- What: An object containing new portfolio contents (amount of asset & currency).\n- When: Some point in time after the advice event, at the same time as the tradeCompleted event.\n- Subscribe: You can subscribe to this event by registering the `processPortfolioChange` method.\n- Example:\n      {\n        currency: [number, portfolio amount of currency],\n        asset: [number, portfolio amount of asset],\n      }\n\n### portfolioValueChange event\n\n- What: An object containing the total portfolio worth (amount of asset & currency calculated in currency).\n- When: Every time the value of the portfolio has changed, if the strategy is in a LONG position this will be every minute.\n- Subscribe: You can subscribe to this event by registering the `processPortfolioValueChange` method.\n- Example:\n      {\n        value: [number, portfolio amount of currency]\n      }\n\n### performanceReport event\n\n- What: An object containing a summary of the performance of the \"tradebot\" (advice signals + execution).\n- When: Once every new candle.\n- Subscribe: You can subscribe to this event by registering the `processPerformanceReport` method.\n- Example:\n      {\n        startTime: Moment<'2017-03-25 19:41:00'>,\n        endTime: Moment<'2017-03-25 20:01:00'>,\n        timespan: 36000000,\n        market: -0.316304880517734,\n        balance: 1016.7200029226638,\n        profit: -26.789997197336106,\n        relativeProfit: -2.5672966425099304,\n        yearlyProfit: '-704041.12634599',\n        relativeYearlyProfit: '-67468.55576516',\n        startPrice: 945.80000002,\n        endPrice: 942.80838846,\n        trades: 10,\n        roundtrips: 5,\n        startBalance: 1043.5100001199999,\n        sharpe: -2.676305165560598\n      }\n\n### roundtripInitiated event\n\n- What: A summary of a started roundtrip.\n- When: After every tradeCompleted with action `buy`.\n- Subscribe: You can subscribe to this event by registering the `processRoundtripInitiated` method.\n- Example:\n      {\n        id: [string identifying this roundtrip],\n        entryAt: Moment<'2017-03-25 19:41:00'>,\n        entryPrice: 10.21315498,\n        entryBalance: 98.19707799420277,\n        exitAt: Moment<'2017-03-25 19:41:00'>,\n        exitPrice: 10.22011632,\n        exitBalance: 97.9692176,\n        duration: 3600000,\n        pnl: -0.2278603942027786,\n        profit: -0.2320439659276161,\n      }\n\n### roundtripUpdate event\n\n- What: An updated summary of a currently open roundtrip.\n- When: On every candle for as long as the bot is in a long position.\n- Subscribe: You can subscribe to this event by registering the `processRoundtripUpdate` method.\n- Example:\n      {\n        id: [string identifying this roundtrip],\n        at: Moment<'2017-03-25 19:41:00'>,\n        duration: 3600000,\n        uPnl: -0.2278603942027786,\n        uProfit: -0.2320439659276161,\n      }\n\n### roundtrip event\n\n- What: A summary of a completed roundtrip (buy + sell signal).\n- When: After every roundtrip: a completed sell trade event that superceded a buy sell trade event.\n- Subscribe: You can subscribe to this event by registering the `processRoundtrip` method.\n- Example:\n      {\n        id: [string identifying this roundtrip],\n        entryAt: Moment<'2017-03-25 19:41:00'>,\n        entryPrice: 10.21315498,\n        entryBalance: 98.19707799420277,\n        exitAt: Moment<'2017-03-25 19:41:00'>,\n        exitPrice: 10.22011632,\n        exitBalance: 97.9692176,\n        duration: 3600000,\n        pnl: -0.2278603942027786,\n        profit: -0.2320439659276161,\n      }\n\n### triggerCreated event\n\n- What: A summary of a created trigger.\n- When: After a buy advice that includes a stop.\n- Subscribe: You can subscribe to this event by registering the `processTriggerCreated` method.\n- Example:\n      {\n        id: [string identifying this trigger],\n        date: Moment<'2017-03-25 19:41:00'>,\n        type: type: \"trailingStop\",\n        properties: {\n          initialPrice: 100,\n          trail: 10\n        }\n      }\n\n### triggerFired event\n\n- What: A message indicating a created trigger has fired\n- When: As soon as the trigger fired\n- Subscribe: You can subscribe to this event by registering the `processTriggerFired` method.\n- Example:\n      {\n        id: [string identifying this trigger],\n        date: Moment<'2017-03-25 19:41:00'>\n      }\n\n### triggerAborted event\n\n- What: A message indicating a created trigger has been aborted\n- When: After an advice signal indicating a sell\n- Subscribe: You can subscribe to this event by registering the `processTriggerAborted` method.\n- Example:\n      {\n        id: [string identifying this trigger],\n        date: Moment<'2017-03-25 19:41:00'>\n      }\n\n### marketStart event\n\n- What: A moment object describing the first date of the market data.\n- When: When the market is started.\n- Subscribe: Your plugin can subscribe to this event by registering the `processMarketStart` method.\n- Example:\n      [moment object describing the date of the first market data]\n\n### marketUpdate event\n\n- What: A moment object describing the point in time for up to which the market has market data.\n- When: Every few seconds.\n- Subscribe: Your plugin can subscribe to this event by registering the `processMarketUpdate` method.\n- Example:\n      [moment object describing the date of the latest market data]\n"
  },
  {
    "path": "docs/internals/gekko_ui.md",
    "content": "# Gekko UI\n\nWhen you launch Gekko UI, you start a basic nodejs webserver with 3 components:\n\n- It will serve frontend (HTML/CSS/JS) files for frontend written as a [vuejs app](https://vuejs.org/) (v2.5.16).\n- It will will handle API requests as [koa](http://koajs.com/) (v1) routes, it will also start a websocket server used to broadcast messages in realtime (used for long lived processes Importing and Live Gekkos for example). The server API documentation can be found [here](./server_api.md).\n\n## Gekko UI Frontend\n\nThe frontend is setup as a very basic vue app. Additionally the following libraries are used:\n\n- [Reconnecting websocket](https://github.com/joewalnes/reconnecting-websocket)\n- [Moment](http://momentjs.com/)\n- [d3.js](https://d3js.org/)\n- [toml](https://github.com/BinaryMuse/toml-node)\n- [humanizeDuration](https://github.com/EvanHahn/HumanizeDuration.js)\n\nThe vue app itself uses the following libraries:\n\n- [marked](https://github.com/chjj/marked)\n- [pug](https://github.com/pugjs) (all html is either written in pug of markdown)\n- [vue-router](https://github.com/vuejs/vue-router)\n- [vuex](https://github.com/vuejs/vuex)\n- [superagent](https://github.com/visionmedia/superagent) (cross browser ajax)\n\n### Developing for the Gekko UI frontend\n\nYou first need to install all developer dependencies so the frontend app can be recompiled on your machine.\n\n    cd gekko/web/vue\n    npm install\n\nAfter this you can launch a hot reload version of the app which will automatically recompile the frontend and reload your browser:\n\n    # path to webserver\n    cd gekko/web\n    # launch the server - we use this API\n    node server\n\n    # path to vue app\n    cd vue\n    npm run serve\n\nGekko UI is now served from port 8080, the webpack dev server will compile the vue app (in memory) and intercept all calls to the app itself (`/dist/js/app.xxx.js`) and serve the in memory app. It is important to note that this UI still talks to the API served from the `node server` command (on default http://localhost:3000/api).\n\n\nIf you have configured Gekko to run on non standards ports (using the UIconfig), you can have your config applied to the development environment by copying `gekko/web/vue/dist/UIconfig.js` to `gekko/web/vue/public/UIconfig.js`.\n\n### Compiling the Gekko UI frontend\n\n*Note: as part of the compilation process Gekko will reset the UIconfig in both `gekko/web/vue/dist/UIconfig.js` and `gekko/web/vue/public/UIconfig.js`. Only compile if you are ready to lose your personal changes.*\n\nWhen you are done developing you can compile the app using these instructions:\n\n    # path to vue app\n    cd gekko/web/vue\n    npm run build\n"
  },
  {
    "path": "docs/internals/plugins.md",
    "content": "# Plugins\n\n*This is a technical document explaining the role of Plugins in the Gekko codebase. For a non technical document about available plugins, see [here](../commandline/plugins.md).*\n\nWithin Gekko most functionality is encapsulated into \"plugins\". These are simple modules that process some data (from [Gekko events](./events.md)) and do something with it. For example emitting a new event or sending a message out to some external service like telegram, or doing a live trade at an exchange.\n\nWhenever you run a Gekko (live trader, paper trader, backtester or importer) you are simply running a number of plugins and feeding them with market data. For a more detailed explanation, see the [architecture doc](./architecture.md).\n\nFor example, there is a plugin called the paperTrader which is responsible for simulating trades (used in [backtests](../features/backtesting.md) and [paper trading](../features/paper_trading.md)). It does this by listening to advice events coming from a strategy, and simulating trades whenever they fire (and firing trade events). Find a longer list of plugins that come with Gekko [here](../commandline/plugins.md).\n\n- All plugins are javascript files that expose a constructor function (or ES6 class).\n- All plugins are stored in `gekko/plugins`.\n- All plugins are described in the file [`gekko/plugins.js`](https://github.com/askmike/gekko/blob/develop/plugins.js), this way Gekko knows how/when the plugin can be used (for example it does not make sense to run a telegram bot that will emit all trades in a backtest).\n\n## Structure of a plugin\n\nA plugin can be a very simple module that simply listens to some event:\n\n\n    // A plugin that will buy Champagne when we MOON\n\n    // example: doesn't actually work..\n    const alexa = require('alexa');\n\n    const MOON = 1000000;\n\n    const Plugin = function() {}\n\n    Plugin.prototype.processPortfolioValueChange = function(event) {\n      if(event.value > MOON) {\n        alexa.say('Alexa, buy the best Champagne!');\n      }\n    };\n\n    module.exports = Plugin;\n\nHave a look at the [events doc](./events.md) for all events your plugin can subscribe to. For technical inspiration it's easiest to look at the code of Gekko's plugins (here [`gekko/plugins.js`](https://github.com/askmike/gekko/blob/develop/plugins.js))."
  },
  {
    "path": "docs/internals/server_api.md",
    "content": "# Server API\n\nThe Gekko project has three major components:\n\n - [Actual Gekko instance](./architecture.md)\n - A nodejs server that:\n   - starts and manages gekkos\n   - broadcasts all updates from all gekkos and tracks their overall state\n   - has API calls to query and manage historical data (by importing more for example)\n - [A web UI (vue frontend project)](./gekko_ui.md)\n\nThe nodejs server can also be used standalone as a webserver in combination with your own software (such as a new UI, a mobile app or a higher level backtester), see [other software](../extending/other_software.md) for examples).\n\nThe server exposes two different APIs: A websocket API to push gekko updates and a REST API for everything else.\n\nWhen you run `node gekko --ui` it will automatically start a server. You can also do this manually by running:\n\n    cd gekko/web\n    node server\n\nThe server will now run on the host/port configured in `gekko/web/vue/public/UIConfig.js` (under api.host).\n\n## REST API\n\n### GET /api/info\n\nGet version information of current running Gekko Server.\n\nNOTE: The API does not have dedicated versioning, instead it uses the version of the complete Gekko project.\n\n**response**\n\n```\n{ \"version\": \"0.6.0\" }\n```\n\n### GET /api/strategies\n\nGet all strategies known to this Gekko. The value of the `params` key is a TOML string.\n\n**response**\n\n```\n[\n  {\n    \"name\": \"DEBUG_single-advice\",\n    \"params\": \"\"\n  },\n  {\n    \"name\": \"DEBUG_toggle-advice\",\n    \"params\": \"\"\n  },\n  {\n    \"name\": \"DEMA\",\n    \"params\": \"weight = 21\\n\\n[thresholds]\\ndown = -0.025\\nup = 0.025\\n\"\n  },\n  {\n    \"name\": \"MACD\",\n    \"params\": \"short = 10\\nlong = 21\\nsignal = 9\\n\\n[thresholds]\\ndown = -0.025\\nup = 0.025\\npersistence = 1\"\n  },\n  // etc.\n]\n```\n\n### GET /api/apiKeys\n\nReturns a list of exchanges that this Gekko has API keys stored for.\n\nNOTE: for security reasons the Gekko never exposes the API keys themselves.\n\n**response**\n\n```\n[\"bitstamp\",\"bitfinex\"]\n```\n\n### GET /api/imports\n\nReturns a list of currently running data imports.\n\n**response**\n\n```\n[\n  {\n    \"watch\": {\n      \"exchange\": \"poloniex\",\n      \"currency\": \"USDT\",\n      \"asset\": \"BTC\"\n    },\n    \"id\": \"765606096903592\",\n    \"latest\": \"2018-04-03T07:13:00Z\",\n    \"from\": \"2018-04-03 05:13\",\n    \"to\": \"2018-07-03 05:13\",\n    \"done\": false\n  }\n]\n```\n\n### GET /api/gekkos\n\nReturns a list of currently running and archived Gekkos.\n\n**response**\n\n```\n{\n  \"live\": {\n    \"2018-07-03-13-14-papertrader-384222057313623\": {\n      \"mode\": \"realtime\",\n      \"config\": {\n        // complete config that was passed when creating\n      },\n      \"id\": \"2018-07-03-13-14-papertrader-384222057313623\",\n      \"type\": \"leech\",\n      \"logType\": \"papertrader\",\n      \"active\": true,\n      \"stopped\": false,\n      \"errored\": false,\n      \"errorMessage\": false,\n      \"events\": {\n        \"initial\": {\n          \"candle\": {\n            \"id\": 419824,\n            \"start\": \"2018-07-03T04:47:00.000Z\",\n            \"open\": 6664.79999887,\n            \"high\": 6664.79999887,\n            \"low\": 6659.99999989,\n            \"close\": 6659.99999989,\n            \"vwp\": 6662.402395386147,\n            \"volume\": 0.001202,\n            \"trades\": 3\n          },\n          \"portfolioChange\": {\n            \"asset\": 1,\n            \"currency\": 100\n          },\n          \"portfolioValueChange\": {\n            \"balance\": 6759.99999989\n          }\n        },\n        \"latest\": {\n          \"candle\": {\n            \"id\": 419849,\n            \"start\": \"2018-07-03T05:12:00.000Z\",\n            \"open\": 6643.21466865,\n            \"high\": 6656.58532982,\n            \"low\": 6643.01,\n            \"close\": 6656,\n            \"vwp\": 6643.884436854498,\n            \"volume\": 1.9966113400000003,\n            \"trades\": 15\n          },\n          \"portfolioChange\": {\n            \"asset\": 1,\n            \"currency\": 100\n          },\n          \"portfolioValueChange\": {\n            \"balance\": 6756\n          }\n        }\n      },\n      \"start\": \"2018-07-03T05:14:23.582Z\",\n      \"latestUpdate\": \"2018-07-03T05:14:24.090Z\"\n    }\n  },\n  \"archive\": {}\n}\n```\n\n### GET /api/exchanges\n\nReturns a list of supported exchanges with meta information (such as supported features and tradable markets).\n\n**response**\n\n```\n{\n    \"name\": \"Bitstamp\",\n    \"slug\": \"bitstamp\",\n    \"currencies\": [\n        \"USD\",\n        // and more\n    ],\n    \"assets\": [\n        \"BTC\",\n        // and more\n    ],\n    \"maxTradesAge\": 60,\n    \"maxHistoryFetch\": null,\n    \"markets\": [\n        {\n            \"pair\": [\n                \"USD\",\n                \"EUR\"\n            ],\n            \"minimalOrder\": {\n                \"amount\": 5,\n                \"unit\": \"currency\"\n            },\n            \"precision\": 2\n        },\n        // and more\n    ],\n    \"requires\": [\n        \"key\",\n        \"secret\",\n        \"username\"\n    ],\n    \"fetchTimespan\": 60,\n    \"tid\": \"tid\",\n    \"tradable\": true\n}\n```\n\n### POST /api/addApiKey\n\nAdds an API key for an exchange account to Gekko. As of now only 1 API keypair can be added per exchange.\n\n**request**\n\n```\n{\n  \"exchange\": \"bitstamp\",\n  \"values\": {\n    \"key\": \"x\",\n    \"secret\": \"y\"\n  }\n}\n```\n\n**response**\n\n```\n{\n    \"status\": \"ok\"\n}\n```\n\n### POST /api/removeApiKey\n\nRemoves an API key from Gekko.\n\n**request**\n\n```\n{\n  \"exchange\": \"bitstamp\"\n}\n```\n\n**response**\n\n```\n{\n    \"status\": \"ok\"\n}\n```\n\n### POST /api/scan\n\nScans a daterange to find all datasets for a specific market.\n\n**request**\n\n```\n{\n  \"watch\": {\n    exchange: \"bitstamp\",\n    \"currency\": \"USD\",\n    \"asset\": \"BTC\"\n  }\n}\n```\n\n**response**\n\n```\n[\n    {\n        \"to\": 1464787560,\n        \"from\": 1464783960\n    },\n    {\n        \"to\": 1479115560,\n        \"from\": 1471112760\n    }\n]\n```\n\n### POST /api/scansets\n\nScans the database for all datasets for all markets.\n\n**request**\n\n```\n{}\n```\n\n**response**\n\n```\n{\n    \"datasets\": [\n        {\n            \"exchange\": \"bitfinex\",\n            \"currency\": \"USD\",\n            \"asset\": \"BTC\",\n            \"ranges\": [\n                {\n                    \"to\": 1508551500,\n                    \"from\": 1508493900\n                }\n            ]\n        },\n        {\n            \"exchange\": \"binance\",\n            \"currency\": \"USDT\",\n            \"asset\": \"BTC\",\n            \"ranges\": [\n                {\n                    \"to\": 1514351280,\n                    \"from\": 1510632480\n                },\n                {\n                    \"to\": 1522915680,\n                    \"from\": 1522678080\n                }\n            ]\n        },\n    ],\n    \"errors\": [\n        {\n            \"exchange\": \"poloniex\",\n            \"currency\": \"BTC\",\n            \"asset\": \"BTC\"\n        }\n    ]\n}\n```\n\n### POST /api/backtest\n\nPerform a backtest.\n\n**request**\n\n*(a valid gekko config object)*\n\nTweak the `config.backtestResultExporter.data` object to control what is included in the output. For example skip `stratCandles` if you only care about the final profit report. This way the server won't include megabytes of candle data in the output.\n\n```\n{\n    \"watch\": {\n        \"exchange\": \"poloniex\",\n        \"currency\": \"USDT\",\n        \"asset\": \"ETH\"\n    },\n    \"paperTrader\": {\n        \"feeMaker\": 0.25,\n        \"feeTaker\": 0.25,\n        \"feeUsing\": \"maker\",\n        \"slippage\": 0.05,\n        \"simulationBalance\": {\n            \"asset\": 1,\n            \"currency\": 100\n        },\n        \"reportRoundtrips\": true,\n        \"enabled\": true\n    },\n    \"tradingAdvisor\": {\n        \"enabled\": true,\n        \"method\": \"MACD\",\n        \"candleSize\": 60,\n        \"historySize\": 10\n    },\n    \"MACD\": {\n        \"short\": 10,\n        \"long\": 21,\n        \"signal\": 9,\n        \"thresholds\": {\n            \"down\": -0.025,\n            \"up\": 0.025,\n            \"persistence\": 1\n        }\n    },\n    \"backtest\": {\n        \"daterange\": {\n            \"from\": \"2016-06-01T11:57:00Z\",\n            \"to\": \"2016-11-13T14:57:00Z\"\n        }\n    },\n    \"backtestResultExporter\": {\n        \"enabled\": true,\n        \"writeToDisk\": false,\n        \"data\": {\n            \"stratUpdates\": false,\n            \"roundtrips\": true,\n            \"stratCandles\": true,\n            \"stratCandleProps\": [\n                \"open\"\n            ],\n            \"trades\": true\n        }\n    },\n    \"performanceAnalyzer\": {\n        \"riskFreeReturn\": 2,\n        \"enabled\": true\n    }\n}\n```\n\n**response**\n\n```\n{\n    \"performanceReport\": {\n        \"startTime\": \"2018-04-02 14:08:00\",\n        \"endTime\": \"2018-04-05 04:08:00\",\n        \"timespan\": \"3 days\",\n        \"market\": -2.159980297428632,\n        \"startBalance\": 7083.86,\n        \"balance\": 7424.849452897501,\n        \"profit\": 340.989452897501,\n        \"relativeProfit\": 4.813610840664566,\n        \"yearlyProfit\": 48210.518806418906,\n        \"relativeYearlyProfit\": 680.5684867631334,\n        \"startPrice\": 6983.86,\n        \"endPrice\": 6833.01,\n        \"trades\": 3,\n        \"exposure\": 0.3709677419354839,\n        \"sharpe\": null,\n        \"downside\": null,\n        \"alpha\": 343.14943319492966\n    },\n    \"roundtrips\": [\n        {\n            \"id\": 0,\n            \"entryAt\": 1522685280,\n            \"entryPrice\": 7019.99,\n            \"entryBalance\": 7119.6899337771,\n            \"exitAt\": 1522768080,\n            \"exitPrice\": 7365,\n            \"exitBalance\": 7447.19106625,\n            \"duration\": 82800000,\n            \"pnl\": 327.5011324729003,\n            \"profit\": 4.599935327508788\n        },\n        // and more\n    ],\n    \"stratCandles\": [\n        {\n            \"open\": 6990.06,\n            \"start\": 1522678080\n        },\n        // and more\n    ],\n    \"trades\": [\n        {\n            \"id\": \"trade-1\",\n            \"adviceId\": \"advice-1\",\n            \"action\": \"buy\",\n            \"cost\": 0.30000000000000027,\n            \"amount\": 1.01420229,\n            \"price\": 7019.99,\n            \"portfolio\": {\n                \"asset\": 1.08661475,\n                \"currency\": 0\n            },\n            \"balance\": 7119.6899337771,\n            \"date\": 1522685280\n        },\n        // and more\n    ]\n}\n```\n\n### POST /api/import\n\nStart a data import.\n\n**request**\n\n*(a valid gekko config object)*\n\n\n```\n{\n    \"watch\": {\n        \"exchange\": \"poloniex\",\n        \"currency\": \"USDT\",\n        \"asset\": \"BTC\"\n    },\n    \"importer\": {\n        \"daterange\": {\n            \"from\": \"2018-04-03 05:46\",\n            \"to\": \"2018-07-03 05:46\"\n        }\n    },\n    \"candleWriter\": {\n        \"enabled\": true\n    }\n}\n```\n\n**response**\n\nNOTE: this only contains information regarding the started import, updates are pushed through the websocket.\n\n```\n{\n    \"watch\": {\n        \"exchange\": \"poloniex\",\n        \"currency\": \"USDT\",\n        \"asset\": \"BTC\"\n    },\n    \"id\": \"7324830525419355\",\n    \"latest\": \"\",\n    \"from\": \"2018-04-03 05:46\",\n    \"to\": \"2018-07-03 05:46\"\n}\n```\n\n### POST /api/startGekko\n\nStart a gekko instance\n\n**request**\n\n*(a valid gekko config object)*\n\nIn order to start a stratRunner, pass a config object that includes plugins required for a stratrunner (such as paperTrader, tradingAdvisor and performanceAnalyzer).\n\n```\n{\n    \"watch\": {\n        \"exchange\": \"poloniex\",\n        \"currency\": \"USDT\",\n        \"asset\": \"BTC\"\n    },\n    \"candleWriter\": {\n        \"enabled\": true,\n    },\n    \"type\": \"market watcher\",\n    \"mode\": \"realtime\"\n}\n```\n\n**response**\n\nNOTE: this only contains information regarding the started gekko, updates from are pushed through the websocket.\n\n```\n{\n    \"mode\": \"realtime\",\n    \"config\": {\n      // config that was passed in the request\n    },\n    \"id\": \"2018-07-03-13-49-watcher-404457189518044\",\n    \"type\": \"watcher\",\n    \"logType\": \"watcher\",\n    \"active\": true,\n    \"stopped\": false,\n    \"errored\": false,\n    \"errorMessage\": false,\n    \"events\": {\n        \"initial\": {},\n        \"latest\": {}\n    },\n    \"start\": \"2018-07-03T05:49:06.685Z\"\n}\n```\n\n### POST /api/stopGekko\n\nStop a gekko instance\n\n**request**\n\n```\n{\n    \"id\": \"2018-07-03-13-49-watcher-404457189518044\"\n}\n```\n\n**response**\n\n```\n{\n    \"status\": \"ok\"\n}\n```\n\n### POST /api/deleteGekko\n\nDelete a stopped gekko instance from the archive.\n\n**request**\n\n```\n{\n    \"id\": \"2018-07-03-13-49-watcher-404457189518044\"\n}\n```\n\n**response**\n\n```\n{\n    \"status\": \"ok\"\n}\n```\n\n### POST /api/getCandles\n\nLoad candles directly from the database.\n\n**request**\n\n```\n{\n    \"watch\": {\n        \"exchange\": \"poloniex\",\n        \"currency\": \"USDT\",\n        \"asset\": \"BTC\"\n    },\n    \"daterange\": {\n        \"to\": \"2018-07-03T05:53:00.000Z\",\n        \"from\": \"2018-07-03T05:40:00.000Z\"\n    },\n    \"candleSize\": 1\n}\n```\n\n**response**\n\n```\n[\n    {\n        \"start\": 1530596400,\n        \"open\": 6645.49999958,\n        \"high\": 6649.83970225,\n        \"low\": 6642,\n        \"close\": 6642,\n        \"vwp\": 6644.840723040122,\n        \"volume\": 0.007383000000000001,\n        \"trades\": 23\n    },\n    {\n        \"start\": 1530596460,\n        \"open\": 6649.69979936,\n        \"high\": 6649.69979936,\n        \"low\": 6642,\n        \"close\": 6648.89999912,\n        \"vwp\": 6645.926390922748,\n        \"volume\": 0.007383450000000001,\n        \"trades\": 21\n    },\n    // etc.\n]\n```\n\n## Websocket API\n\nA websocket server is started at the basepath of the API. Connecting to it means you'll receive update messages. Messages you send to the server via the websocket connection are completely ignored, to control the server use the REST API instead.\n\nThe possible messages are:\n\n### import_update\n\nWhenever there is an update regarding a running import.\n\n```\n{\n  type: 'import_update',\n  import_id: '7324830525419355',\n  updates: {\n    latest: '2018-07-03T05:49:06.685Z',\n    done: false\n  }\n}\n```\n\n### import_error\n\nWhenever there is a fatal error in a running import. After receiving this the import will not continue.\n\n```\n{\n  type: 'import_error',\n  import_id: '7324830525419355',\n  error: \"Error string\"\n}\n```\n\n### gekko_new\n\nWhenever a new Gekko has been started.\n\n```\n{\n    \"type\": \"gekko_new\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\",\n    \"state\": {\n        \"mode\": \"realtime\",\n        \"config\": {\n          // the complete config that was passed\n        },\n        \"id\": \"2018-07-03-16-37-watcher-938815758693549\",\n        \"type\": \"watcher\",\n        \"logType\": \"watcher\",\n        \"active\": true,\n        \"stopped\": false,\n        \"errored\": false,\n        \"errorMessage\": false,\n        \"events\": {\n            \"initial\": {},\n            \"latest\": {}\n        },\n        \"start\": \"2018-07-03T08:37:51.965Z\"\n    }\n}\n```\n\n### gekko_event\n\nWhenever a gekko instance has a new Gekko event. See the [gekko events doc](../events.md) for a list of all possible events and details.\n\n```\n{\n    \"type\": \"gekko_event\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\",\n    \"event\": {\n        \"type\": \"candle\",\n        \"payload\": {\n            \"start\": \"2018-07-03T08:38:00.000Z\",\n            \"open\": 6623.00000066,\n            \"high\": 6623.00000066,\n            \"low\": 6623.00000066,\n            \"close\": 6623.00000066,\n            \"vwp\": 6623.00000066,\n            \"volume\": 0,\n            \"trades\": 0\n        }\n    }\n}\n```\n\n### gekko_stopped\n\nWhenever a Gekko has been stopped, does not fire when the instance had a fatal error. For that see `gekko_error`.\n\n```\n{\n    \"type\": \"gekko_stopped\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\"\n}\n```\n\n### gekko_error\n\n\nWhenever a gekko received a fatal error and crashed.\n\n```\n{\n    \"type\": \"gekko_error\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\",\n    \"error\": \"Error message\"\n}\n```\n\n\n### gekko_archived\n\nWhenever the server does not consider the instance to be relevant anymore, fires after a gekko has been stopped or had a fatal error. After this event the gekko instance is placed in an in memory archive. It will stay here stale (as it won't be updated) until it's deleted.\n\n```\n{\n    \"type\": \"gekko_stopped\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\"\n}\n```\n\n### gekko_deleted\n\nWhenever an archived gekko instance got deleted.\n\n```\n{\n    \"type\": \"gekko_stopped\",\n    \"id\": \"2018-07-03-16-37-watcher-938815758693549\"\n}\n```\n"
  },
  {
    "path": "docs/introduction/about_gekko.md",
    "content": "# About Gekko\n\nGekko is a **free and open source** Bitcoin TA trading and backtesting platform that connects to popular Bitcoin exchanges. It is written in javascript and runs on [nodejs](http://nodejs.org).\n\n*Use Gekko at your own risk.*\n\n![screen shot of gekko backtesting](https://user-images.githubusercontent.com/969743/35054500-fc705b46-fbac-11e7-9652-306c468505a3.png)\n\n## The gist\n\nGekko is a tool that makes it very easy to automate your own trading strategies.\n\n![gist of gekko](https://gekko.wizb.it/_static/gekko-gist.png)\n\nYou can either create your own trading strategy or start with the built-in example strategies. Once you have a strategy you can use Gekko to automatically run it in a few different ways:\n\n- **Backtest**: You can start a simulation of the strategy over a historical data period and Gekko will tell you what would have happened (which trades would have been performed as well as overall performance and risk metrics).\n- **Paper trader**: You can run the strategy in realtime simulate trading (trade with fake money) to see in realtime how profitable your strategy would have been.\n- **Tradebot**: You can run the strategy in realtime and automatically execute orders based on the signals.\n\nAll the above modes can be run from the user interface, this interface will show charts and performance/risk statistics.\n\nHere is a video that explains Gekko's core concepts:\n\n[![youtube video explaining gekko](https://gekko.wizb.it/_static/yt-gist.jpg)](https://www.youtube.com/watch?v=PKIxZ-Qaphk)\n\n## Strategies\n\nGekko comes with some [example strategies](../strategies/introduction.md) (which implement a single indicator). But with some basic javascript you can [create your own strategies](../strategies/creating_a_strategy.md). You can use over 130 indicators to create your perfect prediction model (using [Talib's indicators](../strategies/talib_indicators.md) or [Tulip's indicators](../strategies/tulip_indicators.md)). *Why don't you combine Bollinger Bands, CCI and MACD with a STOCHRSI indicator?*\n\n## Automated Trading platform\n\nGekko can watch the realtime markets, automatically executing and evaluating your strategies in the process. Whilst doing this Gekko will store all market data it sees, this makes it possible to later simulate trading strategies against historical data to see whether they would have been profitable (backtesting).\n\n## Limitations\n\nGekko is not built for HFT or anything related to being the fastest (like arbitrage) as well as some other things. Please see the [scope page](./scope.md) to read more about what you can and cannot do with Gekko.\n\n## How does Gekko work?\n\n![Gekko architecture](https://wizb.it/gekko/static/architecture.jpg)\n\nRead more in the [architecture documentation](../internals/architecture.md).\n\n## Credits\n\n* The title is inspired by [Bateman](https://github.com/fearofcode/bateman).\n* This project is inspired by the [GoxTradingBot](https://github.com/virtimus/GoxTradingBot/) Chrome plugin (which in turn is inspired by [Goomboo's journal](https://bitcointalk.org/index.php?topic=60501.0)).\n\n## Final\n\nIf Gekko helped you in any way, you can always leave me a tip at (BTC) 13r1jyivitShUiv9FJvjLH7Nh1ZZptumwW\n\n## Disclaimer\n\nGekko (nor anyone behind this project) DOES NOT give investment advice. All advice seen within Gekko is the result of running YOUR OWN strategies against the market. On top of that there might be bugs in the code - Gekko DOES NOT come with ANY warranty.\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Mike van Rossum <mike@mvr.me>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "docs/introduction/getting_help.md",
    "content": "# Getting Help\n\nAre you getting stuck installing or using Gekko? Are you struggling with understanding Gekko? Running into problems creating your own plugin or strategy? Do you want to discuss awesome things you want to do with Gekko? This page will explain what to do!\n\n## Online community\n\nIf you have trouble with anything specific or you want to provide any type of feedback the online community is the place to be. You can find the community at:\n\n1. [The online webforum](https://forum.gekko.wizb.it)\n2. [The discord channel](https://discord.gg/26wMygt)\n\nThese communities are the place for things like:\n\n- Solving installation problems\n  - Solving installation errors\n  - Helping set up Gekko on a server or embedded device\n- Requesting/requesting new features and or changes such as:\n  - New exchanges to add\n  - New plugins to add\n  - General new features\n- Getting clarity on what Gekko can do and how it works\n\n## Technical discussion\n\nThe links above are always the first place to go to when discussing new features. But if you've found a clear bug or you want to **keep the complete discussion 100% technical (meaning completely code and architecture related)** you can use the [bug tracker on github](https://github.com/askmike/gekko/issues). Note that we are trying to keep all other discussions out of the bug tracker to keep the whole thing manageable :)\n"
  },
  {
    "path": "docs/introduction/roadmap.md",
    "content": "# Roadmap\n\nGekko is ever evolving and we are constantly working on new features and upgrades!\n\nThis is a small selection of things currently on the roadmap:\n\n## Current TODO\n\n- Improve stability of new event and backtest engine\n- Port the old supported exchanges to Gekko Broker\n- new UI, see [here](https://forum.gekko.wizb.it/thread-1429-post-58996.html)\n- advanced orders from your strategy (Take Profit and Stop Loss)"
  },
  {
    "path": "docs/introduction/scope.md",
    "content": "# Scope\n\nGekko is a free and open source tool that is designed as a starters kit for automated trading on cryptocurrency markets. Gekko aims to have a low barrier entry to writing your own strategies (however a basic scripting knowledge in javascript is required for users who create their own strategies). This page will discuss the scope of some components of Gekko, explaining how things are done and why they are done a certain way.\n\n## Market data\n\nGekko aggregates all market data into minutely candles (OHLC, VWP and amount of trades). This means Gekko only has to store candles on disk, which take up a predictable amount of space on your harddrive. The tradebot will use some additional market data (the orderbook) to execute orders efficiently, but this data is not visible anywhere else.\n\n## Strategies\n\nStrategies are simple scripts that handle new market data (OHLC candles) as well as calculated indicator results (strategies specify what indicators they want with which settings). Every time there is new data the strategy can determine to signal either LONG or SHORT. That's about it! This very simple design (candles + indicator values go in => signals come out) is quite powerful.\n\nUnfortunately this simple design can sometimes be limiting, here are some limitations:\n\n- Since strategies are only fed candles (and indicator values):\n - Strategies cannot act on a smaller timeframe than 1 minute.\n - Strategies cannot see any trades.\n - Strategies cannot look at the orderbook.\n- Strategies do not know what the current portfolio looks like.\n- Strategies can only trigger a LONG or SHORT which signals to go \"all in\".\n\n## Execution strategy\n\nWhen you are using Gekko for a real tradebot Gekko will create orders at the exchange whenever your strategy signals an advice (long or short). If your strategy signal a long advice Gekko will try to buy as much \"asset\" as it can get with all your \"currency\" (if your strat is running on USD/BTC that would mean buying BTC with all your USD). As for creating the orders Gekko is conservative and stays on your side of the orderbook (this means you don not lose on the spread, slippage or taker fees). An example:\n\nIf your strategy signals a LONG signal and this is the current orderbook:\n\n<img width=\"279\" alt=\"screen shot 2017-08-26 at 23 26 22\" src=\"https://user-images.githubusercontent.com/969743/29745564-0bb096a6-8ab6-11e7-8bdb-12a6c0274482.png\">\n\nGekko will try to buy bitcoin by placing a limit order at a price of `4336.29` in the hope someone sells into the order. Every few seconds Gekko will readjust the order to stay on top of the orderbook. *Note that order simulation (in the paper trader and backtester) is handled differently, since the orderbook is not used in the simulation.*\n"
  },
  {
    "path": "docs/introduction/supported_exchanges.md",
    "content": "## Supported exchanges\n\nGekko is able to directly communicate with the APIs of a number of exchanges. However communication with some exchanges is somewhat limited. Gekko makes the distinction between the following features:\n\n- Monitoring: Gekko is able to retrieve live market data from the exchange. Gekko can store and run trading simulations over this data.\n- Live Trading: Gekko is able to automatically execute orders (based on the signals of your strategy). This turns Gekko into a trading bot.\n- Importing: Gekko is able to retrieve historical market data. This way you can easily get a month of market data over which you can [backtest][1] your strategy.\n\n| Exchange              | Monitoring | Live Trading | Importing | Notes                     |\n| --------------------- |:----------:|:------------:|:---------:| ------------------------- |\n| [Binance][24]         | ✓          | ✓            | ✓         |                           |\n| [Poloniex][2]         | ✓          | ✓            | ✓         |                           |\n| [GDAX][3]             | ✓          | ✓            | ✓         |                           |\n| [BTCC][4]*            | ✓          | ✓            | ✓         | (=BTCChina)               |\n| [Bitstamp][5]*        | ✓          | ✓            | ✕         |                           |\n| [Kraken][6]           | ✓          | ✓            | ✓         |                           |\n| [Bitfinex][7]         | ✓          | ✓            | ✓         |                           |\n| [Bittrex][8]          | ✓          | ✕            | ✕         | API problems ([#2310][26])|\n| [coinfalcon][25]      | ✓          | ✓            | ✓         |                           |\n| [The Rock Trading][28]| ✓          | ✓            | ✓         |                           |\n| [EXMO][27]            | ✓          | ✓            | ✕         |                           |\n| [wex.nz][9]*          | ✓          | ✓            | ✕         |                           |\n| [Gemini][10]*         | ✓          | ✓            | ✕         |                           |\n| [Okcoin.cn][11]*      | ✓          | ✓            | ✕         | China, see [#352][20]     |\n| [Cex.io][12]*         | ✓          | ✕            | ✕         |                           |\n| [BTC Markets][13]*    | ✓          | ✓            | ✕         |                           |\n| [Luno][14]            | ✓          | ✓            | ✓         | previously BitX           |\n| [lakeBTC][15]*        | ✓          | ✕            | ✕         |                           |\n| [meXBT][16]*          | ✓          | ✕            | ✕         | see [here][21]            |\n| [zaif][17]*           | ✓          | ✕            | ✕         |                           |\n| [lakeBTC][18]*        | ✓          | ✕            | ✕         |                           |\n| [bx.in.th][19]*       | ✓          | ✕            | ✕         |                           |\n| [bitcoin.co.id][22]*  | ✓          | ✓            | ✕         |                           |\n| [Quadriga CX][23]*    | x          | x            | ✕         | Exchange is down.         | |\n\n\n*Temporary disabled since 0.6! If you were planning on using this exchange please e-mail me (address at the bottom of this page).\n\n[1]: ../features/backtesting.md\n[2]: https://poloniex.com\n[3]: https://gdax.com\n[4]: https://btcc.com\n[5]: https://bitstamp.com\n[6]: https://kraken.com\n[7]: https://bitfinex.com\n[8]: https://bittrex.com\n[9]: https://wex.nz\n[10]: https://gemini.com\n[11]: https://www.okcoin.cn\n[12]: https://cex.io\n[13]: https://btcmarkets.net\n[14]: https://www.luno.com\n[15]: https://lakebtc.com\n[16]: https://mexbt.com\n[17]: https://zaif.jp/trade_btc_jpy\n[18]: https://lakebtc.com\n[19]: https://bx.in.th\n[20]: https://github.com/askmike/gekko/pull/352\n[21]: https://github.com/askmike/gekko/issues/288#issuecomment-223810974\n[22]: https://vip.bitcoin.co.id/\n[23]: https://quadrigacx.com/\n[24]: https://www.binance.com/?ref=11236330\n[25]: https://coinfalcon.com/?ref=CFJSQBMXZZDS\n[26]: https://github.com/askmike/gekko/pull/2310\n[27]: https://exmo.com\n[28]: https://www.therocktrading.com/\n"
  },
  {
    "path": "docs/introduction/supporting_the_project.md",
    "content": "# Supporting the project\n\nGekko is free and open source software. We don't make any money by publishing it, keeping it up to date or providing support.\n\nIf Gekko helped you in any way (financially or otherwise) feel free to donate. If you want to see a specific feature implemented faster, feel free to [send an e-mail](mailto:gekko@mvr.me) to discuss.\n\n- Bitcoin tip jar: 13r1jyivitShUiv9FJvjLH7Nh1ZZptumwW\n- Ethereum tip jar: 0x46e9249ADc30F5bfc6632e1d0b4286496d071Be7"
  },
  {
    "path": "docs/strategies/creating_a_strategy.md",
    "content": "# Creating a strategy\n\n*Have you made your own strategy? Gekko Plus is hosting an official Strategy contest: submit your strategy and have a change to win 0.1 BTC! Read more details on [Gekko Plus](https://app.gekkoplus.com/contest).*\n\nStrategies are the core of Gekko's trading bot. They look at the market and decide what to do based on technical analysis indicators. A single strategy is limited to a single market on a single exchange.\n\nGekko currently comes with [a couple of strategies](./introduction.md) out of the box. Besides those you can also write your own strategy in javascript. If you want to understand how to create your own strategy you can watch this video or read the tech docs on this page.\n\n[![youtube video on how to create gekko strategies](https://gekko.wizb.it/_static/create-strat-vid.jpg)](https://www.youtube.com/watch?v=6-74ZhrG0BE)\n\nA strategy is a module with a few functions that get market data in the form of candles ([OHLC](https://en.wikipedia.org/wiki/Open-high-low-close_chart), volume, and the average weighted price) and output trading advice.\n\n## Strategy boilerplate\n\n    // Let's create our own strategy\n    var strat = {};\n\n    // Prepare everything our strat needs\n    strat.init = function() {\n      // your code!\n    }\n\n    // What happens on every new candle?\n    strat.update = function(candle) {\n      // your code!\n    }\n\n    // For debugging purposes.\n    strat.log = function() {\n      // your code!\n    }\n\n    // Based on the newly calculated\n    // information, check if we should\n    // update or not.\n    strat.check = function(candle) {\n      // your code!\n    }\n\n    // Optional for executing code\n    // after completion of a backtest.\n    // This block will not execute in\n    // live use as a live gekko is\n    // never ending.\n    strat.end = function() {\n      // your code!\n    }\n\n    module.exports = strat;\n\n# Strategy lifecycle methods\n\nThe above boilerplate contains four functions. These functions are executed by Gekko like so:\n\n- When Gekko starts: run init.\n- On each new candle:\n  - run [update](#update-function)\n  - once the strategy has completed warmup:\n    - run [log](#log-function)\n    - run [check](#check-function)\n\n### init function\n\nExecuted when the trading strategy starts. Your strategy can initialize state and [register indicators](#Indicators).\n\n### update function\n\nThis function executes on every new candle. You can access the latest candle as the first (and only) parameter (it's also stored in `this.candle`).\n\n### log function\n\nThe log function is executed on every new candle when the `debug` flag is on (always off when running in the UI, as configured in [the config](../commandline/about_the_commandline.md) for CLI gekkos). Logging is used to log certain state from the strategy and can be used to debug your strategy to get more insights in why it took certain decisions.\n\n### check function\n\nMost strategies need to warmup before the trading strategy can be started. For example the strategy may be calculating a moving average for the first 3 candles, as such it must have at least 3 candles to output a number the strategy logic relies on. The check function is executed after the warmup period is over. The default required history is 0. You can set it like so in your init function:\n\n    this.requiredHistory = 5; // require 5 candles before giving advice\n\nIf you find out in the check function that you want to give new advice to the trader you can use the advice function:\n\n    this.advice({\n      direction: 'long', // or short\n      trigger: { // ignored when direction is not \"long\"\n        type: 'trailingStop',\n        trailPercentage: 5\n        // or:\n        // trailValue: 100\n      }\n    });\n\nThe trigger is optional, if the direction is long and the trigger is specified as a trailingStop this will request the trader to create a trail stop trigger.\n\n### candle variable\n\nThe following list of candle variables will be available when writing strategies, they are part of the candle object which is given to your `update` and `check` functions (it's also accessable through `this.candle`).\n\n - candle.close: the closing price of the candle\n - candle.high: the highest price of the candle\n - candle.low: the lowest price of the candle\n - candle.volume: the trading volume of that candle\n - candle.trades: number of trades in that candle\n\n## Things to keep in mind\n\n- You can activate your own strategy by setting `config.tradingAdvisor.strategy` to `custom` (or whatever you named your file inside the `gekko/strategies`) in the loaded config.\n- Gekko will execute the `update` function for every new candle. A candle is the size in minutes configured at `config.tradingAdvisor.candleSize` in the loaded config.\n- It is advised to set history `config.tradingAdvisor.historySize` the same as the requiredHistory as Gekko will use this property to create an initial batch of candles.\n- Never rely on anything based on system time because each method can run on live markets as well as during backtesting. You can look at the `candle.start` property which is a `moment` object of the time the candles started.\n\n## Strategy tools\n\nTo help you Gekko has a number of strategy tools.\n\n### Indicators\n\nGekko supports a few indicators natively, in addition to the integration of indicators from the library [TA-lib](http://ta-lib.org/).\n\n#### Example usage\n\nIf you want to use an indicator you can add it in the `init` function and Gekko will handle the updating for you on every candle (before the update and before the check call):\n\n    // add a native indicator\n    this.addIndicator('name', 'type', parameters);\n\nor\n\n    // add a TA-lib indicator\n    this.addTalibIndicator('name', 'type', parameters);\n\nor\n\n    // add a Tulip indicator\n    this.addTulipIndicator('name', 'type', parameters);\n\nThe first parameter is the name, the second is the indicator type you want and the third is an object with all indicator parameters. If you want an MACD indicator you can do it like so:\n\nIn your init function:\n\n    // add a native indicator\n    var parameters = {short: 10, long: 20, signal: 9};\n    this.addIndicator('mynativemacd', 'MACD', parameters);\n\n    // add a TA-lib indicator\n    var parameters = {optInFastPeriod: 10, optInSlowPeriod: 21, optInSignalPeriod: 9};\n    this.addTalibIndicator('mytalibmacd', 'macd', parameters);\n\n    // add a Tulip indicator\n    var parameters = {optInFastPeriod: 10, optInSlowPeriod: 21, optInSignalPeriod: 9};\n    this.addTulipIndicator('mytulipmacd', 'macd', parameters);\n\nIn your check or update function:\n\n    var result = this.indicators.mytalibmacd.result;\n\nSee the [TA-lib indicators](./talib_indicators.md) document for a list of all supported TA-lib indicators and their required parameters.\n\nSee the [Tulip indicators](./tulip_indicators.md) document for a list of all supported Tulip indicators and their required parameters.\n\n### Strategy parameters\n\nAdjust strategy execution by creating custom strategy parameters. This way the same strategy can execute strategies concurrently using different parameters for different markets. For example the MACD strategy has parameters concerning the underlying MACD indicator (such as values for the LONG and SHORT EMAs). Create custom configuration settings in the `config/strategies` directory:\n\n    // custom settings:\n    config.custom = {\n      my_custom_setting: 10,\n    };\n\nRetrieve them in your strategy like this:\n\n    // anywhere in your code:\n    log.debug(this.settings.my_custom_setting); // Logs 10\n\n___Note that the name of your configuration must be the same as the name of the strategy___\n\n### External libraries\n\nGekko uses a few general purpose libraries internally.  The API from those libraries are available to you as well.  Most notable libraries are [lodash](http://lodash.com/) (similar as underscore) and [async](https://github.com/caolan/async).\n\nYou can load them like so:\n\n    // before any other code\n    var _ = require('lodash');\n    var async = require('async');\n\n### Logging\n\nGekko has a small logger you can use (preferably in your log function):\n\n    // before any other code\n    var log = require('../core/log.js');\n\n    // in your log function\n    log.debug('hello world');\n\n\n-----\n\nTake a look at the existing methods, if you have questions feel free to create an issue. If you created your own awesome strategies and want to share it with the world feel free to contribute it to gekko.\n"
  },
  {
    "path": "docs/strategies/gekko_indicators.md",
    "content": "# Gekko indicators\n\nWhen [creating your own strategy](./creating_a_strategy.md) there are a few built in indicators you can use that ship with Gekko.\n\n## Example\n\nIf you want to use the MACD indicator from Gekko, you need to register it in your strategy like so:\n\n    method.init = function() {\n      var settings = {\n        short: 10,\n        long: 21,\n        signal: 9\n      };\n\n      // add the indicator to the strategy\n      this.addIndicator('mymacd', 'MACD', settings);\n    }\n\n    method.check = function() {\n      // use indicator results\n      var macdiff = this.indicators.mymacd.result;\n\n      // do something with macdiff\n    }\n\n## Indicators\n\nHere is a list of all supported indicators, click on them to read more about what they are and how to implement them in Gekko:\n\n- [EMA](#EMA)\n- [PPO](#PPO)\n- [CCI](#CCI)\n- [DEMA](#DEMA)\n- [LRC](#LRC)\n- [MACD](#MACD)\n- [RSI](#RSI)\n- [SMA](#SMA)\n- [TSI](#TSI)\n- [UO](#UO)\n\n### EMA\n\n> **What is an 'Exponential Moving Average - EMA'**\n> \"An exponential moving average (EMA) is a type of moving average that is similar to a simple moving average, except that more weight is given to the latest data. It's also known as the exponentially weighted moving average. This type of moving average reacts faster to recent price changes than a simple moving average.\"\n\n*[More info on investopedia](http://www.investopedia.com/terms/e/ema.asp).*\n\nYou can implement the EMA like so:\n\n    method.init = function() {\n      var weight = 10;\n\n      // add the indicator to the strategy\n      this.addIndicator('myema', 'EMA', weight);\n    }\n\n    method.check = function() {\n      // use indicator results\n      var ema = this.indicators.myema.result;\n\n      // do something with macdiff\n    }\n\n\n### PPO\n> **What is the 'Percentage Price Oscillator - PPO'**\n> \"The percentage price oscillator (PPO) is a technical momentum indicator showing the relationship between two moving averages.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/p/ppo.asp).*\n\n### CCI\n> **What is the 'Commodity Channel Index - CCI'**\n> \"The Commodity Channel Index​ (CCI) is a momentum based technical trading tool used most often to help determine when an investment vehicle is reaching a condition of being overbought or oversold.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/c/commoditychannelindex.asp).*\n\n### DEMA\n\n> **What is the 'Double Exponential Moving Average - DEMA'**\n> \"The DEMA is a fast-acting moving average that is more responsive to market changes than a traditional moving average. It was developed in an attempt to create a calculation that eliminated some of the lag associated with traditional moving averages.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/d/double-exponential-moving-average.asp).*\n\n### LRC\n\n> **What is the 'Linear Regression Channel - LRC'**\n> \"This indicator plots a line that best fits the prices specified over a user-defined time period. The Linear Regression Curve is used mainly to identify trend direction and is sometimes used to generate buy and sell signals.\"\n\n*[More info on Interactive Brokers](https://www.interactivebrokers.co.uk/en/software/tws/usersguidebook/technicalanalytics/linearregressioncurve.htm).*\n\n### MACD\n> **What is the 'Moving Average Convergence Divergence - MACD'**\n> \"Moving average convergence divergence (MACD) is a trend-following momentum indicator that shows the relationship between two moving averages of prices.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/m/macd.asp).*\n\n### RSI\n> **What is the 'Relative Strength Index - RSI'**\n> \"Compares the magnitude of recent gains and losses over a specified time period to measure speed and change of price movements of a security. It is primarily used to attempt to identify overbought or oversold conditions in the trading of an asset.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/r/rsi.asp).*\n\n### SMA\n> **What is the 'Simple Moving Average - SMA'**\n> \"A simple moving average (SMA) is an arithmetic moving average calculated by adding the closing price of the security for a number of time periods and then dividing this total by the number of time periods.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/s/sma.asp).*\n\n### TSI\n\n> **What is the 'True Strength Index - TSI'**\n> \"A technical momentum indicator that helps traders determine overbought and oversold conditions of a security by incorporating the short-term purchasing momentum of the market with the lagging benefits of moving averages.\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/t/tsi.asp).*\n\n### UO\n\n> **What is the 'Ultimate Oscillator - UO'**\n> \"A technical indicator that uses the weighted average of three different time periods to reduce the volatility and false transaction signals that are associated with many other indicators that mainly rely on a single time period\"\n\n*[More info on investopedia](https://www.investopedia.com/terms/u/ultimateoscillator.asp).*\n"
  },
  {
    "path": "docs/strategies/introduction.md",
    "content": "# Gekko Strategies\n\nGekko uses [technical analysis indicators](http://www.investopedia.com/articles/active-trading/102914/technical-analysis-strategies-beginners.asp) inside **strategies**.\n\nThis investment advice is going to be either **long** or **short**. Long indicates that Gekko the asset should be bought and short indicates that it should be sold.\n\nIf you are familiar with javascript you can easily create your own strategies. Here is a video explaining everything you need to know:\n\n[![youtube video on how to create gekko strategies](https://gekko.wizb.it/_static/create-strat-vid.jpg)](https://www.youtube.com/watch?v=6-74ZhrG0BE)\n\nBelow you can find simple and exemplary strategies that come with Gekko. These strategies come with Gekko and serve as examples.\n\nGekko currently comes with the following example strategies:\n\n - [DEMA](#DEMA)\n - [MACD](#MACD)\n - [PPO](#PPO)\n - [RSI](#RSI)\n - [StochRSI](#StochRSI)\n - [CCI](#CCI)\n - [talib-macd](#talib-macd)\n - [tulip-macd](#tulip-macd)\n\n### DEMA\n\nThis strategy uses `Exponential Moving Average crossovers` to determine the current trend the\nmarket is in. Using this information it will suggest to ride the trend. Note that this is\nnot MACD because it just checks whether the longEMA and shortEMA are [threshold]% removed\nfrom each other.\n\nThis strategy is fairly popular in bitcoin trading due to Bitcointalk user Goomboo. Read more about this strategy in [his topic](https://bitcointalk.org/index.php?topic=60501.0) or [here](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages).\n\nYou can configure the following parameters:\n\n    # EMA weight (α)\n    # the higher the weight, the more smooth (and delayed) the line\n    short = 10\n    long = 21\n\n    [thresholds]\n    down = -0.025\n    up = 0.025\n\n- short is the short EMA that moves closer to the real market (including noise)\n- long is the long EMA that lags behind the market more but is also more resistant to noise.\n- the down threshold and the up threshold tell Gekko how big the difference in the lines needs to be for it to be considered a trend. If you set these to 0 each line cross would trigger new advice.\n\n### MACD\n\nThe MACD is one of the most popular trend watching **indicators** in finance, it was created by Gerald Appel in the late 1970s. By using multiple price averages (EMAs) of different periods (one that follows the market more closely and one that lags behind, only catching bigger price swings). The indicator itself ouputs multiple numbers, when comparing them they can be interepted as signals that show when the trend of the price is changing.\n\nThe MACD **strategy** in Gekko is a simple strategy that implements the indicator. By comparing the difference between the EMAs from the signal the strategy triggers buy and sell signals. The strategy does come with additional logic:\n\n- **thresholds**: a signal will be triggered as soon as the difference goes above or below a configurable threshold, making the strategy more flexible than simply checking if the difference is above or below zero. If you set these to 0 each line cross would trigger new advice.\n- **persistance**: instead of trading as soon the difference is above or below the threshold, the strategy will wait a few candles to see if the difference keeps persisting. Only if it does the strategy will actually signal to Gekko to buy or sell. By setting persistance to 0 this behaviour is disabled.\n- **short** is the short EMA that moves closer to the real market (including noise)\n- **long** is the long EMA that lags behind the market more but is also more resistant to noise.\n- **signal** is the EMA weight calculated over the difference from short/long.\n\nRead more about it [here](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_convergence_divergence_macd).\n\nYou can configure the following parameters:\n\n    # EMA weight (α)\n    # the higher the weight, the more smooth (and delayed) the line\n    short = 10\n    long = 21\n    signal = 9\n\n    # the difference between the EMAs (to act as triggers)\n    [thresholds]\n    down = -0.025\n    up = 0.025\n    # How many candle intervals should a trend persist\n    # before we consider it real?\n    persistence = 1\n\n### PPO\n\nVery similar to MACD but also a little different, read more [here](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:price_oscillators_ppo).\n\nYou can configure the following parameters:\n\n    # EMA weight (α)\n    # the higher the weight, the more smooth (and delayed) the line\n    short = 12\n    long = 26\n    signal = 9\n\n    # the difference between the EMAs (to act as triggers)\n    [thresholds]\n    down = -0.025\n    up = 0.025\n    # How many candle intervals should a trend persist\n    # before we consider it real?\n    persistence = 2\n\n- short is the short EMA that moves closer to the real market (including noise)\n- long is the long EMA that lags behind the market more but is also more resistant to noise.\n- signal is the EMA weight calculated over the difference from short/long.\n- the down threshold and the up threshold tell Gekko how big the difference in the lines needs to be for it to be considered a trend. If you set these to 0 each line cross would trigger new advice.\n- persistence tells Gekko how long the thresholds needs to be met until Gekko considers the trend to be valid.\n\n### RSI\n\nThe RSI indicator is and old but ever popular trend watching **indicator**, introduced in 1978 by J. Welles Wilder this simple indicator has never stopped to be a popular tool for traders. In its essence RSI follows a simple formula to measure the speed by which the price is changing. When the price keeps going up at an accelarating rate the market might be overbought and a reversal might come next.\n\nThe RSI **strategy** in Gekko is a simple strategy that implements the RSI indicator. By calculating the RSI as the market develops this strategy can trigger buy or sell signals based on the RSI going too high (overbought) or too low (oversold). The strategy does come with additional logic:\n\n- **interval** is the amount of periods the RSI should use.\n- **thresholds** determine what level of RSI would trigger an up or downtrend.\n- **persistance**: instead of trading as soon the difference is above or below the threshold, the strategy will wait a few candles to see if the difference keeps persisting. Only if it does the strategy will actually signal to Gekko to buy or sell. By setting persistance to 0 this behaviour is disabled.\n\nRead more about it [here](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi).\n\nYou can configure the following parameters:\n\n    interval = 14\n\n    [thresholds]\n    low = 30\n    high = 70\n    # How many candle intervals should a trend persist\n    # before we consider it real?\n    persistence = 2\n\n### StochRSI\n\nThe StochRSI indicator uses an RSI indicator at its core and as such is similar to the RSI strategy that uses this indicator. The difference is that after the RSI is calculated a stochastic oscillator is calculated over the resulting RSI values. When a market is trending upwards for a long time the RSI values tend to go and stay high. The stochastic oscillator will compare the RSI values from the last period with eachother. This results in the StochRSI indicator therefor indicate how high or low the RSI values have been historically over the last n periods.\n\nThe StochRSI **strategy** in Gekko is a simple strategy that implements the StochRSI indicator. By calculating the StochRSI as the market develops this strategy can trigger buy or sell signals based on the signal going too high (overbought) or too low (oversold). The strategy does come with configurables:\n\n- **interval**: This setting defines both the RSI interval used to calculate the RSI values as well as the historical period used by the stochastic oscillator to compare RSI values with.\n- **persistance**: instead of trading as soon the difference is above or below the threshold, the strategy will wait a few candles to see if the difference keeps persisting. Only if it does the strategy will actually signal to Gekko to buy or sell. By setting persistance to 0 this behaviour is disabled.\n- **thresholds**: The high and low thresholds are defined as numbers between 1 and 100. Different from StochRSI in other trading systems, this number indicates a percentage instead of a fraction of 1.\n\nYou can configure the following parameters:\n\n    interval = 3\n\n    [thresholds]\n    low = 20\n    high = 80\n    persistence = 3\n\n### CCI\n\nYou can configure the following parameters:\n\n    # constant multiplier. 0.015 gets to around 70% fit\n    constant = 0.015\n\n    # history size, make same or smaller than history\n    history = 90\n\n    [thresholds]\n    up = 100\n    down = -100\n    persistence = 0\n\n[TODO!]\n\n### talib-macd\n\nSimilar to the default MACD strategy, this showcases how to add a TA-lib indicator to a strategy.\n\nYou can configure the following parameters:\n\n    [parameters]\n    optInFastPeriod = 10\n    optInSlowPeriod = 21\n    optInSignalPeriod = 9\n\n    [thresholds]\n    down = -0.025\n    up = 0.025\n\n### tulip-macd\n\nSimilar to the default MACD strategy, this showcases how to add a Tulip indicator to a strategy.\n\nYou can configure the following parameters:\n\n    [parameters]\n    optInFastPeriod = 10\n    optInSlowPeriod = 21\n    optInSignalPeriod = 9\n\n    [thresholds]\n    down = -0.025\n    up = 0.025\n\n[TODO!]\n"
  },
  {
    "path": "docs/strategies/talib_indicators.md",
    "content": "# TA-lib indicators\n\nWhen writing [your own strategy](./creating_a_strategy.md) you can use all indicators offered by [the TA-lib library](http://ta-lib.org/function.html). Gekko will pass the correct market data to TA-lib and you only have to provide the `optIn` configurable parameters.\n\n## Install\n\n### Bash on Windows, OSX or Linux\n\nOpen your terminal. Then:\n\n```\ncd ~/gekko\nnpm install talib --no-save\n```\n\n## Example\n\nIf you want to use the MACD indicator from TA-lib, you need to register it in your strategy like so:\n\n    method.init = function() {\n      var customMACDSettings = {\n        optInFastPeriod: 10,\n        optInSlowPeriod: 21,\n        optInSignalPeriod: 9\n      }\n\n      // add the indicator to the strategy\n      this.addTalibIndicator('mymacd', 'macd', customMACDSettings);\n    }\n\n    method.check = function() {\n      // use indicator results\n      var result = this.talibIndicators.mymacd.result;\n      var macddiff = result['outMACD'] - result['outMACDSignal'];\n\n      // do something with macdiff\n    }\n\n## TA-lib Indicators\n\nHere is a list of all supported indicators, click on them to see the required parameters.\n\n- [ACCBANDS](#accbands)\n- [AD](#ad)\n- [ADOSC](#adosc)\n- [ADX](#adx)\n- [ADXR](#adxr)\n- [APO](#apo)\n- [AROON](#aroon)\n- [AROONOSC](#aroonosc)\n- [ATR](#atr)\n- [AVGPRICE](#avgprice)\n- [BBANDS](#bbands)\n- [BOP](#bop)\n- [CCI](#cci)\n- [CMO](#cmo)\n- [DEMA](#dema)\n- [DX](#dx)\n- [EMA](#ema)\n- [HT_DCPERIOD](#ht_dcperiod)\n- [HT_DCPHASE](#ht_dcphase)\n- [HT_PHASOR](#ht_phasor)\n- [HT_SINE](#ht_sine)\n- [HT_TRENDLINE](#ht_trendline)\n- [HT_TRENDMODE](#ht_trendmode)\n- [IMI](#imi)\n- [KAMA](#kama)\n- [LINEARREG](#linearreg)\n- [LINEARREG_ANGLE](#linearreg_angle)\n- [LINEARREG_INTERCEPT](#linearreg_intercept)\n- [LINEARREG_SLOPE](#linearreg_slope)\n- [MA](#ma)\n- [MACD](#macd)\n- [MACDEXT](#macdext)\n- [MACDFIX](#macdfix)\n- [MAMA](#mama)\n- [MAVP](#mavp)\n- [MAX](#max)\n- [MAXINDEX](#maxindex)\n- [MEDPRICE](#medprice)\n- [MFI](#mfi)\n- [MIDPOINT](#midpoint)\n- [MIDPRICE](#midprice)\n- [MIN](#min)\n- [MININDEX](#minindex)\n- [MINMAX](#minmax)\n- [MINMAXINDEX](#minmaxindex)\n- [MINUS_DI](#minus_di)\n- [MINUS_DM](#minus_dm)\n- [MOM](#mom)\n- [NATR](#natr)\n- [OBV](#obv)\n- [PLUS_DI](#plus_di)\n- [PLUS_DM](#plus_dm)\n- [PPO](#ppo)\n- [ROC](#roc)\n- [ROCP](#rocp)\n- [ROCR](#rocr)\n- [ROCR100](#rocr100)\n- [RSI](#rsi)\n- [SAR](#sar)\n- [SAREXT](#sarext)\n- [SMA](#sma)\n- [STDDEV](#stddev)\n- [STOCH](#stoch)\n- [STOCHF](#stochf)\n- [STOCHRSI](#stochrsi)\n- [T3](#t3)\n- [TEMA](#tema)\n- [TRANGE](#trange)\n- [TRIMA](#trima)\n- [TRIX](#trix)\n- [TSF](#tsf)\n- [TYPPRICE](#typprice)\n- [ULTOSC](#ultosc)\n- [VARIANCE](#variance)\n- [WCLPRICE](#wclprice)\n- [WILLR](#willr)\n- [WMA](#wma)\n\n## API\n\n### accbands\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ad\n\nRequired parameters:\n\n - optInTimePeriod\n\n### adosc\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### adx\n\nRequired parameters:\n\n - optInTimePeriod\n\n### adxr\n\nRequired parameters:\n\n - optInTimePeriod\n\n### apo\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n - optInMAType\n\n### aroon\n\nRequired parameters:\n\n - optInTimePeriod\n\n### aroonosc\n\nRequired parameters:\n\n - optInTimePeriod\n\n### atr\n\nRequired parameters:\n\n - optInTimePeriod\n\n### avgprice\n\nRequired parameters:\n\n - optInTimePeriod\n\n### bbands\n\nRequired parameters:\n\n - optInTimePeriod\n - optInNbDevUp\n - optInNbDevDn\n - optInMAType\n\n### bop\n\nThis indicator does not require any parameters.\n\n### cci\n\nRequired parameters:\n\n - optInTimePeriod\n\n### cmo\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dema\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dx\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ema\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ht_dcperiod\n\nThis indicator does not require any parameters.\n\n### ht_dcphase\n\nThis indicator does not require any parameters.\n\n### ht_phasor\n\nThis indicator does not require any parameters.\n\n### ht_sine\n\nThis indicator does not require any parameters.\n\n### ht_trendline\n\nThis indicator does not require any parameters.\n\n### ht_trendmode\n\nThis indicator does not require any parameters.\n\n### imi\n\nRequired parameters:\n\n - optInTimePeriod\n\n### kama\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linearreg\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linearreg_angle\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linearreg_intercept\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linearreg_slope\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ma\n\nRequired parameters:\n\n - optInTimePeriod\n - optInMAType\n\n### macd\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n - optInSignalPeriod\n\n### macdext\n\nRequired parameters:\n\n - optInFastPeriod\n - optInFastMAType\n - optInSlowPeriod\n - optInSlowMAType\n - optInSignalPeriod\n - optInSignalMAType\n\n### macdfix\n\nRequired parameters:\n\n - SignalPeriod\n\n### mama\n\nRequired parameters:\n\n - optInFastLimit\n - optInSlowLimit\n\n### mavp\n\nRequired parameters:\n\n - inPeriods\n - optInMinPeriod\n - optInMaxPeriod\n - optInMAType\n\n### max\n\nRequired parameters:\n\n - optInTimePeriod\n\n### maxindex\n\nRequired parameters:\n\n - optInTimePeriod\n\n### medprice\n\nRequired parameters:\n\n - optInTimePeriod\n\n### mfi\n\nRequired parameters:\n\n - optInTimePeriod\n\n### midpoint\n\nRequired parameters:\n\n - optInTimePeriod\n\n### midprice\n\nRequired parameters:\n\n - optInTimePeriod\n\n### min\n\nRequired parameters:\n\n - optInTimePeriod\n\n### minindex\n\nRequired parameters:\n\n - optInTimePeriod\n\n### minmax\n\nRequired parameters:\n\n - optInTimePeriod\n\n### minmaxindex\n\nRequired parameters:\n\n - optInTimePeriod\n\n### minus_di\n\nRequired parameters:\n\n - optInTimePeriod\n\n### minus_dm\n\nRequired parameters:\n\n - optInTimePeriod\n\n### mom\n\nRequired parameters:\n\n - optInTimePeriod\n\n### natr\n\nRequired parameters:\n\n - optInTimePeriod\n\n### obv\n\nThis indicator does not require any parameters.\n\n### plus_di\n\nRequired parameters:\n\n - optInTimePeriod\n\n### plus_dm\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ppo\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n - optInMAType\n\n### roc\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rocp\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rocr\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rocr100\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rsi\n\nRequired parameters:\n\n - optInTimePeriod\n\n### sar\n\nRequired parameters:\n\n - optInAcceleration\n - optInMaximum\n\n### sarext\n\nRequired parameters:\n\n - optInStartValue\n - optInOffsetOnReverse\n - optInAccelerationInitLong\n - optInAccelerationLong\n - optInAccelerationMaxLong\n - optInAccelerationInitShort\n - optInAccelerationShort\n - optInAccelerationMaxShort\n\n### sma\n\nRequired parameters:\n\n - optInTimePeriod\n\n### stddev\n\nRequired parameters:\n\n - optInTimePeriod\n - optInNbDev\n\n### stoch\n\nRequired parameters:\n\n - optInFastK_Period\n - optInSlowK_Period\n - optInSlowK_MAType\n - optInSlowD_Period\n - optInSlowD_MAType\n\n### stochf\n\nRequired parameters:\n\n - optInFastK_Period\n - optInFastD_Period\n - optInFastD_MAType\n\n### stochrsi\n\nRequired parameters:\n\n - optInTimePeriod\n - optInFastK_Period\n - optInFastD_Period\n - optInFastD_MAType\n\n### t3\n\nRequired parameters:\n\n - optInTimePeriod\n - optInFastK_Period\n - optInFastD_Period\n - optInFastD_MAType\n\n### tema\n\nRequired parameters:\n\n - optInTimePeriod\n\n### trange\n\nRequired parameters:\n\n - optInTimePeriod\n\n### trima\n\nRequired parameters:\n\n - optInTimePeriod\n\n### trix\n\nRequired parameters:\n\n - optInTimePeriod\n\n### tsf\n\nRequired parameters:\n\n - optInTimePeriod\n\n### typprice\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ultosc\n\nRequired parameters:\n\n - optInTimePeriod\n\n### variance\n\nRequired parameters:\n\n - optInTimePeriod\n - optInNbDev\n\n### wclprice\n\nRequired parameters:\n\n - optInTimePeriod\n\n### willr\n\nRequired parameters:\n\n - optInTimePeriod\n\n### wma\n\nRequired parameters:\n\n - optInTimePeriod\n"
  },
  {
    "path": "docs/strategies/tulip_indicators.md",
    "content": "# Tulip indicators\n\nWhen writing [your own strategy](./creating_a_trading_method.md) you can use all indicators offered by [the Tulip Indicators library](https://tulipindicators.org/). Gekko will pass the correct market data to Tulip and you only have to provide the `optIn` configurable parameters.\n\n## Install\n\n### Bash on Windows, OSX or Linux\n\nOpen your terminal. Then:\n\n```\ncd ~/gekko\nnpm install tulind --no-save\n```\n\n## Example\n\nIf you want to use the MACD indicator from Tulip, you need to register it in your strategy like so:\n\n    method.init = function() {\n      var customMACDSettings = {\n        optInFastPeriod: 10,\n        optInSlowPeriod: 21,\n        optInSignalPeriod: 9\n      }\n\n      // add the indicator to the strategy\n      this.addTulipIndicator('mymacd', 'macd', customMACDSettings);\n    }\n\n    method.check = function() {\n      // use indicator results\n      var result = this.tulipIndicators.mymacd.result;\n      var macddiff = result['macd'] - result['macdSignal'];\n\n      // do something with macdiff\n    }\n\n## Tulip Indicators\n\nHere is a list of all supported indicators, click on them to see the required parameters.\n\n- [AD](#ad)\n- [ADOSC](#adosc)\n- [ADX](#adx)\n- [ADXR](#adxr)\n- [AO](#ao)\n- [APO](#apo)\n- [AROON](#aroon)\n- [AROONOSC](#aroonosc)\n- [ATR](#atr)\n- [AVGPRICE](#avgprice)\n- [BBANDS](#bbands)\n- [BOP](#bop)\n- [CCI](#cci)\n- [CMO](#cmo)\n- [CVI](#cvi)\n- [DEMA](#dema)\n- [DI](#di)\n- [DM](#dm)\n- [DPO](#dpo)\n- [DX](#dx)\n- [EMA](#ema)\n- [EMV](#emv)\n- [FISHER](#fisher)\n- [FOSC](#fosc)\n- [HMA](#hma)\n- [KAMA](#kama)\n- [KVO](#kvo)\n- [LINREG](#linreg)\n- [LINREGINTERCEPT](#linregintercept)\n- [LINREGSLOPE](#linregslope)\n- [MARKETFI](#marketfi)\n- [MASS](#mass)\n- [MEDPRICE](#medprice)\n- [MFI](#mfi)\n- [MSW](#msw)\n- [NATR](#natr)\n- [NVI](#nvi)\n- [OBV](#obv)\n- [PPO](#ppo)\n- [PSAR](#psar)\n- [PVI](#pvi)\n- [QSTICK](#qstick)\n- [ROC](#roc)\n- [ROCR](#rocr)\n- [RSI](#rsi)\n- [SMA](#sma)\n- [STOCH](#stoch)\n- [SUM](#sum)\n- [TEMA](#tema)\n- [TR](#tr)\n- [TRIMA](#trima)\n- [TRIX](#trix)\n- [TSF](#tsf)\n- [TYPPRICE](#typprice)\n- [ULTOSC](#ultosc)\n- [VHF](#vhf)\n- [VIDYA](#vidya)\n- [VOLATILITY](#volatility)\n- [VOSC](#vosc)\n- [VWMA](#vwma)\n- [WAD](#wad)\n- [WCPRICE](#wcprice)\n- [WILDERS](#wilders)\n- [WILLR](#willr)\n- [WMA](#wma)\n- [ZLEMA](#zlema)\n\n## API\n\n### ad\n\nThis indicator does not require any parameters.\n\n### adosc\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### adx\n\nMore information on the [**Average Directonal Movement Index**](https://en.wikipedia.org/wiki/Average_directional_movement_index)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### adxr\n\nThe **Average Directional Movement Index Rating** is used as a risk indicator for a security in an [adx](#adx) system. It evaluates the risk (volatility) of a security by smoothing the amplitude readings of the trend function of the adx. It is calculated as follows\n\n    ADX plus the ADX (n-time periods ago) divided by 2\n\nHigher readings conform to lower risk and lower readings conform to higher risk.\nA investor wanting to lower the portfolio risk will therefore use securities with higher adxr ratings.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ao\n\nMore information about the [**Awesome Oscillator**](https://www.tradingview.com/wiki/Awesome_Oscillator_(AO))\n\nThis indicator does not require any parameters.\n\n### apo\n\nThe **Absolute Price Oscillator** displays the difference between two exponential moving averages of a security's price and is expressed as an absolute value. It rates the trends strength in relation to the moving between the two moving averages with short-term momentum being the catalyst.\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### aroon\n\nMore information about the [Aroon](https://www.tradingview.com/wiki/Aroon) Indicator.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### aroonosc\n\nThe Aroon Oscillator belongs to the group of trend-following indicators and uses parts of the Aroon Indicator (namely \"Aroon Up\" and \"Aroon Down\") to indicate the strength of a current trend and the likelihood that it will continue. The Aroon Oscillator is calculated by subtracting Aroon Up from Aroon Down. Readings above zero indicate that an uptrend is present, while readings below zero indicate that a downtrend is present.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### atr\n\nMore information about the [Average True Range](https://www.tradingview.com/wiki/Average_True_Range_(ATR))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### avgprice\n\nThe average price indicator calculates the mean of the open, high, low, and close of a bar\n\n    open + high + low + close / 4\n\nThis indicator does not require any parameters.\n\n### bbands\n\nMore information about [Bollinger Bands](https://www.tradingview.com/wiki/Bollinger_Bands_(BB))\n\nRequired parameters:\n\n - optInTimePeriod\n - optInNbStdDevs\n\n### bop\n\nThe Balance of Power indicator measures the market strength of buyers against sellers by assessing the ability of each side to drive prices to an extreme level. The calculation is: \n\n    Balance of Power = (Close price – Open price) / (High price – Low price) \n    \nThe resulting value can be smoothed by a moving average.\n\nThis indicator does not require any parameters.\n\n### cci\n\nMore information about the [Commodity Channel Index](https://www.tradingview.com/wiki/Commodity_Channel_Index_(CCI))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### cmo\n\nThe Chande Momentum Oscillator is a technical momentum indicator. The indicator is created by calculating the difference between the sum of all recent higher closes and the sum of all recent lower closes and then dividing the result by the sum of all price movement over a given time period. The result is multiplied by 100 to give the -100 to +100 range. The defined time period is usually 20 periods.\n\n    CMO = 100 * ((Sh - Sd)/ ( Sh + Sd ) )\n\nWhere:\n\nSh = Sum of the difference between the current close and previous close on up days for the specified period. Up days are days when the current close is greater than the previous close.\n \nSd = Sum of the absolute value of the difference between the current close and the previous close on down days for the specified period. Down days are days when the current close is less than the previous close.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### cvi\n\nMore information about the [Chaikin Volatility Index](https://www.tradingview.com/wiki/Chaikin_Oscillator) also called the Chaikin Oscillator.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dema\n\nMore information about the [DEMA](https://en.wikipedia.org/wiki/Double_exponential_moving_average)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### di\n\nMore information about the [Directional Indicator](https://en.wikipedia.org/wiki/Average_directional_movement_index)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dm\n\nMore information about the [Directional Movement Index](https://en.wikipedia.org/wiki/Average_directional_movement_index)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dpo\n\nMore information about the [Detrended Price Oscillator](https://en.wikipedia.org/wiki/Detrended_price_oscillator)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### dx\n\nMore information about the [Directional Movement Index](https://en.wikipedia.org/wiki/Average_directional_movement_index)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### ema\n\nExponential Moving Average (EMA) is similar to Simple Moving Average (SMA), measuring trend direction over a period of time. However, whereas SMA simply calculates an average of price data, EMA applies more weight to data that is more current. Because of its unique calculation, EMA will follow prices more closely than a corresponding SMA.\n\n    EMA = (K x (C - P)) + P\n\nWhere:\n\n - C = Current Price \n - P = Previous periods EMA (A SMA is used for the first periods calculations) \n - K = Exponential smoothing constant\n\nRequired parameters:\n\n - optInTimePeriod\n\n### emv\n\nMore information about the [Ease of Movement](https://www.tradingview.com/wiki/Ease_of_Movement_(EOM))\n\nThis indicator does not require any parameters.\n\n### fisher\n\nThe Fisher Transform is a technical indicator that converts prices into a Gaussian normal distribution. The indicator enables traders to create a nearly Gaussian probability density function by normalizing prices. That is, the transformation makes peak swings relatively rare events and unambiguously identifies price reversals on a chart. \n\n    Y = 0.5 * ln ((1+X)/(1-X))\n \nWhere:\n\n - \"ln\" denotes the abbreviated form of the natural logarithm\n - \"X\" denotes the transformation of price to a level between -1 and 1 for ease of calculation\n\nRequired parameters:\n\n - optInTimePeriod\n\n### fosc\n\nThe forecast oscillator attempts to predict price action by comparing the results of a linear regression trendline to the actual price for that day. Positive values of the oscillator occur when the forecast price is above the actual price and negative values when the forecast price is below. If prices are consistently below the forecast, then a downturn in prices is likely. Conversely, if prices are consistently above the forecast then an upturn in prices is likely.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### hma\n\nBasic forms of moving averages like the Simple Moving Average lag price. The Exponential and Weighted Moving Averages were developed to address this lag by placing more emphasis on more recent data. The Hull Moving Average in contrast is an extremely fast and smooth moving average, it almost eliminates lag altogether and manages to improve smoothing at the same time.\n\n    HMA= WMA(2*WMA(n/2) − WMA(n)),sqrt(n))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### kama\n\nThe Kaufman adaptive moving average belongs to the group of \"intelligent\" indicators. It´s concept addresses the fact that noisy markets should have a lagging indicator and trending markets should have a leading indicator. So it adapts itself to lag in sideways markets and lead in trending markets.\n\n    KAMA(t) = KAMA(t-1) + sc(t) x (Price-KAMA(t-1))\n\nWhere:\n\n - KAMA(t) is the new adaptive moving average value\n - KAMA(t-1) is the previous adaptive moving average value\n - Price is the current price\n - sc(t) is the smoothing constant\n\nRequired parameters:\n\n - optInTimePeriod\n\n### kvo\n\nThe Klinger Volume Oscillator measures trends of money flows based upon volume. The KO is derived from three types of data: the high-low price range, volume, and accumulation/distribution. Price range is a measure of movement and the force behind that movement is volume. Accumulation is when the sum of today's [high]+[low]+[close] is greater than yesterday's. Distribution is when today's sum is less than the yesterday's. When the sums are equal, the existing trend is maintained.\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### linreg\n\nThe Linear Regression is a smoothing functions that works by preforming linear least squares regression over a moving window. It then uses the linear model to predict the value for the current bar.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linregintercept\n\nMore information about the [Linear Regression Intercept](https://en.wikipedia.org/wiki/Simple_linear_regression)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### linregslope\n\nMore information about the [Linear Regression Intercept](https://en.wikipedia.org/wiki/Simple_linear_regression)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### macd\n\nMore information about the [MACD](https://www.tradingview.com/wiki/MACD_(Moving_Average_Convergence/Divergence))\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n - optInSignalPeriod\n\n### marketfi\n\nThe Market Facilitation Index indicator combines price and volume in the analysis to establish the effectiveness of price movement by computing the price movement per volume unit. To calculate the Market Facilitation Index indicator the difference between the low and the high price are taken and divided by the volume.\n\nThis indicator does not require any parameters.\n\n### mass\n\nThe Mass Index indicator is used for finding trend reversals, based on the premise that reversals are likely to happen when the price range widens. It does not have a directional bias. The calculation, which compares the previous trading ranges (highs minus lows), uses Exponential Moving Averages (EMA). If there is substantial movement, the Mass Index Indicator increases if there is insubstantial movement the Mass Index Indicator decreases. \n\nFormula (usually a 9 period EMA is used)\n\n    Single EMA = (x)-period exponential moving average (EMA) of the high-low differential  \n    Double EMA = (y)-period EMA of the (x)-period EMA of the high-low differential \n    EMA Ratio = Single EMA divided by Double EMA \n    Mass Index = 25-period sum of the EMA Ratio \n\nRequired parameters:\n\n - optInTimePeriod\n\n### medprice\n\nThe median price indicator calculates the mean of the high and low for a bar. Despite the name, it does not calculate an actual median value.\n\n    medprice(t) = (high(t) + low(t)) / 2\n\nThis indicator does not require any parameters.\n\n### mfi\n\nMore information about the [MFI](https://www.tradingview.com/wiki/Money_Flow_(MFI))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### msw\n\nThe Maximum Entropy Spectrum Analysis indicator is a unique way to accurately measure short-term cycles in a market. It utilizes two sine plots to illustrate if the market is in a cycle mode or in a trend mode. When the two plots resemble a sine wave the market is in cycling mode. When the plots start to wander the market is in a trend mode. \nThe MESA Sine Wave indicator is a leading indicator that will anticipate cycle mode turning points rather than waiting for confirmation as is seen with most other oscillators. The indicator has the additional advantage that trend mode whipsaw signals are minimized.\n\nRequired parameters:\n\n - optIn\n\n### natr\n\nThe Normalized Average True Range is a measure of volatility.\nIt is calculated as follows:\n\n    natr = (atr(t) / close(t)) * 100\n\nRequired parameters:\n\n - optInTimePeriod\n\n### nvi\n\nMore information about the [NVI](https://en.wikipedia.org/wiki/Negative_volume_index)\n\nThis indicator does not require any parameters.\n\n### obv\n\nMore information about the [OBV](https://www.tradingview.com/wiki/On_Balance_Volume_(OBV))\n\nThis indicator does not require any parameters.\n\n### ppo\n\nMore information about the [PPO](https://www.tradingview.com/wiki/Price_Oscillator_(PPO))\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### psar\n\nMore information about the [Parabolic SAR](https://www.tradingview.com/wiki/Parabolic_SAR_(SAR))\n\nRequired parameters:\n\n - optInAcceleration\n - optInMaximum\n\n### pvi\n\nMore information about the [PVI](https://en.wikipedia.org/wiki/Negative_volume_index)\n\nThis indicator does not require any parameters.\n\n### qstick\n\nThe Qstick Indicator identifies trends on a chart. It is calculated by taking an 'n' period moving average of the difference between the open and closing prices. A Qstick value greater than zero means that the majority of the last 'n' days have been up, indicating that buying pressure has been increasing. In summary, the measure provides an approximation for a security’s  EMA, opening price, closing price, and their difference, as well as these values SMA.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### roc\n\nMore information about the [Rate of Change](https://www.tradingview.com/wiki/Rate_of_Change_(ROC))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rocr\n\nRate Of Change Ratio calculates the change between the current price and the price n bars ago.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### rsi\n\nMore information about the [RSI](https://www.tradingview.com/wiki/Relative_Strength_Index_(RSI))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### sma\n\nMore information about the [SMA](https://www.tradingview.com/wiki/Moving_Average)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### stoch\n\nMore information about the [STOCH](https://www.tradingview.com/wiki/Stochastic_(STOCH))\n\nRequired parameters:\n\n - optInFastKPeriod\n - optInSlowKPeriod\n - optInSlowDPeriod\n\n### sum\n\nThe Sum Over Period indicator simply returns the sum of the last n bars.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### tema\n\nThe Triple Exponential Moving Average is similar to the Exponential Moving Average or the Double Exponential Moving Average, but provides even less lag. Triple Exponential Moving Average is probably best viewed as an extension of Double Exponential Moving Average.\n\nIt can be expressed in terms of the Exponential Moving Average as follows:\n\n    tema = 3 * ema(in) - 3 * ema(ema(in)) + ema(ema(ema(in)))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### tr\n\nTrue range is a measure of volatility. It represents how much a security changed price on a given day.\n\nTrue range for each day is the greatest of:\n\n - Day's high minus day's low\n - The absolute value of the day's high minus the previous day's close\n - The absolute value of the day's low minus the previous day's close\n\nThis indicator does not require any parameters.\n\n### trima\n\nThe Triangular Moving Average is similar to the Simple Moving Average but instead places more weight on middle portion of the smoothing period and less weight on the newest and oldest bars in the period.\nIt is calculated for each bar as the weighted arithmetic mean of the previous n bars. For example, the weights w for an n of 4 are: 1, 2, 2, 1. The weights w for a n of 7 are: 1, 2, 3, 4, 3, 2, 1. It's easy to see why it's called the Triangular Moving Average.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### trix\n\nMore information about the [TRIX](https://www.tradingview.com/wiki/TRIX)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### tsf\n\nThe Time Series Forecast indicator displays the statistical trend of a security's price over a specified time period. The trend is based on linear regression analysis. Rather than plotting a straight linear regression trendline, the Time Series Forecast plots the last point of multiple linear regression trendlines. The resulting TSF indicator is sometimes referred to as the \"moving linear regression\" indicator or the \"regression oscillator.\"\n\nRequired parameters:\n\n - optInTimePeriod\n\n### typprice\n\nThe Typical Price calculates the arithmetic mean of the high, low, and close of a bar.\n\nThis indicator does not require any parameters.\n\n### ultosc\n\nMore information about the [UO](https://www.tradingview.com/wiki/Ultimate_Oscillator_(UO))\n\nRequired parameters:\n\n - optInTimePeriod1\n - optInTimePeriod2\n - optInTimePeriod3\n\n### vhf\n\nThe Vertical Horizontal Filter determines whether prices are in a trending phase or a congestion phase. It is used to dertermine which other indicators are to be used in the current market trend. For example if the VHF suggests the market is in a range then a [mesa] could be used if the VHF suggests the market is in a range then one could use a [psar] to determine entry and exit points.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### vidya\n\nThe Variable Index Dynamic Average indicator modifies the Exponential Moving Average by varying the smoothness based on recent volatility.\n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n - optInAlpha\n\n### volatility\n\nThe Annualized Historical Volatility indicator calculates the volatility over a moving window.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### vosc\n\nThe Volume Oscillator identifies trends in volume using two moving averages of volume, one fast and one slow. The fast volume moving average is then subtracted from the slow moving average. \n\nRequired parameters:\n\n - optInFastPeriod\n - optInSlowPeriod\n\n### vwma\n\nThe Volume Weighted Moving Average is simalair to a Simple Moving Average, but it weights each bar by its volume.\n\nRequired parameters:\n\n - optInTimePeriod\n\n### wad\n\nWilliams AD is a running sum of positive accumulation values (buying pressure) and negative distribution values (selling pressure), as determined by price's location within a given day's true range. The day's accumulation/distribution is then calculated by comparing today's closing price to yesterday's closing price.\nTo calculate the Williams' Accumulation/Distribution indicator, determine:\n\n    True Range High (TRH) = Yesterday's close or today's high whichever is greater\n    True Range Low (TRL) = Yesterday's close or today's low whichever is less\n    \nThe Williams' Accumulation/Distribution indicator is a cumulative total of the daily values:\n\n - Williams A/D = Today's A/D + Yesterday's Williams A/D\n\nThis indicator does not require any parameters.\n\n### wcprice\n\nThe weighted close price indicator calculates the mean of the high, low, and close of a bar, but the close price is weighted to count for double.\n\nThis indicator does not require any parameters.\n\n### wilders\n\nThe Welles Wilder Smoothing indicator is basically the same as an [EMA](#ema) and can be used in the same manner. \nIt uses a different calculation but can be easily calculated by simply converting EMA values as follows:\n\n    wilders = (ema + 1) / 2\n\nRequired parameters:\n\n - optInTimePeriod\n\n### willr\n\nMore information about the [Williams R](https://www.tradingview.com/wiki/Williams_%25R_(%25R))\n\nRequired parameters:\n\n - optInTimePeriod\n\n### wma\n\nMore information about the [WMA](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average)\n\nRequired parameters:\n\n - optInTimePeriod\n\n### zlema\n\nZero-Lag Exponential Moving Average modifies a Exponential Moving Average to greatly reduce lag.\n\nRequired parameters:\n\n - optInTimePeriod\n"
  },
  {
    "path": "exchange/.npmignore",
    "content": "nusadua"
  },
  {
    "path": "exchange/README.md",
    "content": "# Gekko Broker\n\nsee [the docs](https://gekko.wizb.it/docs/gekko-broker/introduction.html)."
  },
  {
    "path": "exchange/dependencyCheck.js",
    "content": "const deps = require('./package.json').dependencies;\n\nconst missing = [];\n\nObject.keys(deps).forEach(dep => {\n  try {\n    require(dep);\n  } catch(e) {\n    if(e.code === 'MODULE_NOT_FOUND') {\n      missing.push(dep);\n    }\n  }\n});\n\nif(missing.length) {\n  console.error(\n    '\\nThe following Gekko Broker dependencies are not installed: [',\n    missing.join(', '),\n    '].\\n\\nYou need to install them first, read here how:',\n    'https://gekko.wizb.it/docs/installation/installing_gekko.html#Installing-Gekko-39-s-dependencies\\n'\n  );\n  process.exit(1);\n}\n"
  },
  {
    "path": "exchange/exchangeChecker.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst moment = require('moment');\nconst errors = require('./exchangeErrors');\n\nconst Checker = function() {\n  _.bindAll(this);\n}\n\nChecker.prototype.getExchangeCapabilities = function(slug) {\n  if(!fs.existsSync(__dirname + '/wrappers/' + slug + '.js'))\n    throw new errors.ExchangeError(`Gekko does not know the exchange \"${slug}\"`);\n\n  return require('./wrappers/' + slug).getCapabilities();\n}\n\n// check if the exchange is configured correctly for monitoring\nChecker.prototype.cantMonitor = function(conf) {\n  var slug = conf.exchange.toLowerCase();\n  var exchange = this.getExchangeCapabilities(slug);\n\n  if(!exchange)\n    return 'Gekko does not support the exchange ' + slug;\n\n  var name = exchange.name;\n\n  if('monitorError' in exchange)\n    return 'At this moment Gekko can\\'t monitor ' + name +  ', find out more info here:\\n\\n' + exchange.monitorError;\n\n  var name = exchange.name;\n\n  if(!_.includes(exchange.currencies, conf.currency))\n    return 'Gekko only supports the currencies [ ' + exchange.currencies.join(', ') + ' ] at ' + name + ' (not ' + conf.currency + ')';\n\n  if(!_.includes(exchange.assets, conf.asset))\n    return 'Gekko only supports the assets [ ' + exchange.assets.join(', ') + ' ]  at ' + name + ' (not ' + conf.asset + ')';\n\n  var pair = _.find(exchange.markets, function(p) {\n    return p.pair[0] === conf.currency && p.pair[1] === conf.asset;\n  });\n\n  if(!pair)\n    return 'Gekko does not support this currency/assets pair at ' + name;\n\n  // everything is okay\n  return false;\n}\n\n// check if the exchange is configured correctly for fetching\n// full history\nChecker.prototype.cantFetchFullHistory = function(conf) {\n  var slug = conf.exchange.toLowerCase();\n  var exchange = this.getExchangeCapabilities(slug);\n\n  if(this.cantMonitor(conf))\n    return this.cantMonitor(conf);\n\n  var name = exchange.name;\n\n  if(!exchange.providesFullHistory)\n    return 'The exchange ' + name + ' does not provide full history (or Gekko doesn\\'t support importing it)';\n\n  if (\"exchangeMaxHistoryAge\" in exchange) {\n    if (moment(config.importer.daterange.from) < moment().subtract(exchange.exchangeMaxHistoryAge, \"days\")) {\n      return 'Unsupported date from! ' + exchange.name + ' supports history of max ' + exchange.exchangeMaxHistoryAge + ' days..';\n    }\n  }\n}\n\n// check if the exchange if configured correctly for real trading\nChecker.prototype.cantTrade = function(conf) {\n  var cantMonitor = this.cantMonitor(conf);\n  if(cantMonitor)\n    return cantMonitor;\n\n  var slug = conf.exchange.toLowerCase();\n  var exchange = this.getExchangeCapabilities(slug);\n  var name = exchange.name;\n\n  if(!exchange.tradable)\n    return 'At this moment Gekko can\\'t trade at ' + name + '.';\n\n  if(conf.key === 'your-key')\n    return '\"your-key\" is not a valid API key';\n\n  if(conf.secret === 'your-secret')\n    return '\"your-secret\" is not a valid API secret';\n\n  var error = false;\n  _.each(exchange.requires, function(req) {\n    if(!conf[req])\n      error = name + ' requires \"' + req + '\" to be set in the config';\n  }, this);\n\n  return error;\n}\n\nChecker.prototype.settings = function(conf) {\n  var slug = conf.exchange.toLowerCase();\n  return this.getExchangeCapabilities(slug);\n\n}\n\nmodule.exports = new Checker();\n"
  },
  {
    "path": "exchange/exchangeErrors.js",
    "content": "const _ = require('lodash');\n\nconst ExchangeError = function(message) {\n  _.bindAll(this);\n\n  this.name = \"ExchangeError\";\n  this.message = message;\n}\nExchangeError.prototype = new Error();\n\nconst ExchangeAuthenticationError = function(message) {\n  _.bindAll(this);\n\n  this.name = \"ExchangeAuthenticationError\";\n  this.message = message;\n}\nExchangeAuthenticationError.prototype = new Error();\n\nconst RetryError = function(message) {\n  _.bindAll(this);\n\n  this.name = \"RetryError\";\n  this.retry = 5;\n  this.message = message;\n}\nRetryError.prototype = new Error();\n\nconst AbortError = function(message) {\n  _.bindAll(this);\n\n  this.name = \"AbortError\";\n  this.message = message;\n}\nAbortError.prototype = new Error();\n\nmodule.exports = {\n  ExchangeError,\n  ExchangeAuthenticationError,\n  RetryError,\n  AbortError\n};\n\n"
  },
  {
    "path": "exchange/exchangeUtils.js",
    "content": "// generic low level reusuable utils for interacting with exchanges.\n\nconst retry = require('retry');\nconst errors = require('./exchangeErrors');\nconst _ = require('lodash');\n\nconst retryInstance = (options, checkFn, callback, e) => {\n  if(!options) {\n    options = {\n      retries: 100,\n      factor: 1.2,\n      minTimeout: 1 * 1000,\n      maxTimeout: 4 * 1000\n    };\n  }\n\n  let attempt = 0;\n\n  const operation = retry.operation(options);\n  operation.attempt(function(currentAttempt) {\n    checkFn((err, result) => {\n\n      if(!err) {\n        return callback(undefined, result);\n      }\n\n      console.log(new Date, err.message);\n\n      let maxAttempts = err.retry;\n      if(maxAttempts === true)\n        maxAttempts = 10;\n\n      if(err.retry && attempt++ < maxAttempts) {\n        return operation.retry(err);\n      }\n\n      if(err.notFatal) {\n        if(err.backoffDelay) {\n          return setTimeout(() => operation.retry(err), err.backoffDelay);\n        }\n\n        return operation.retry(err);\n      }\n\n      callback(err, result);\n    });\n  });\n}\n\n// es6 bind all: https://github.com/posrix/es6-class-bind-all/blob/master/lib/es6ClassBindAll.js\nconst allMethods = targetClass => {\n  const propertys = Object.getOwnPropertyNames(Object.getPrototypeOf(targetClass))\n  propertys.splice(propertys.indexOf('constructor'), 1)\n  return propertys\n}\n\nconst bindAll = (targetClass, methodNames = []) => {\n  for (const name of !methodNames.length ? allMethods(targetClass) : methodNames) {\n    targetClass[name] = targetClass[name].bind(targetClass)\n  }\n}\n\nconst isValidOrder = ({api, market, amount, price}) => {\n  let reason = false;\n\n  // Check amount\n  if(amount < market.minimalOrder.amount) {\n    reason = 'Amount is too small';\n  }\n\n  // Some exchanges have restrictions on prices\n  if(\n    _.isFunction(api.isValidPrice) &&\n    !api.isValidPrice(price)\n  ) {\n    reason = 'Price is not valid';\n  }\n\n  if(\n    _.isFunction(api.isValidLot) &&\n    !api.isValidLot(price, amount)\n  ) {\n    reason = 'Lot size is too small';\n  }\n\n  return {\n    reason,\n    valid: !reason\n  }\n}\n\n\n// https://gist.github.com/jiggzson/b5f489af9ad931e3d186\nconst scientificToDecimal = num => {\n  if(/\\d+\\.?\\d*e[\\+\\-]*\\d+/i.test(num)) {\n    const zero = '0';\n    const parts = String(num).toLowerCase().split('e'); // split into coeff and exponent\n    const e = parts.pop(); // store the exponential part\n    const l = Math.abs(e); // get the number of zeros\n    const sign = e/l;\n    const coeff_array = parts[0].split('.');\n    if(sign === -1) {\n      num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');\n    } else {\n      const dec = coeff_array[1];\n      if(dec) {\n        l = l - dec.length;\n      }\n      num = coeff_array.join('') + new Array(l+1).join(zero);\n    }\n  } else {\n    // make sure we always cast to string\n    num = num + '';\n  }\n\n  return num;\n}\n\n// TEMP until we have proper scheduling\nconst cacheFn = (fn, timeout) => {\n  let nextCall = false;\n  let cache = false;\n  let inflight = false;\n  let callbackQueue = [];\n\n  return next => {\n    if(inflight) {\n      return callbackQueue.push(next);\n    }\n\n    const now = +new Date;\n    if(cache && now >= nextCall) {\n      return next(res.error, res.result);\n    }\n\n    inflight = true;\n    fn((error, result) => {\n      cache = {error, result};\n      nextCall = now + timeout;\n      next(error, result);\n      callbackQueue.forEach(cb => cb(error, result));\n      callbackQueue = [];\n      inflight = false;\n    })\n  }\n}\n\nmodule.exports = {\n  retry: retryInstance,\n  bindAll,\n  isValidOrder,\n  scientificToDecimal,\n  cacheFn\n}"
  },
  {
    "path": "exchange/gekkoBroker.js",
    "content": "/*\n  The broker manages all communicatinn with the exchange, delegating:\n\n  - the management of the portfolio to the portfolioManager\n  - the management of actual trades to \"orders\".\n*/\n\nconst _ = require('lodash');\nconst async = require('async');\nconst events = require('events');\nconst moment = require('moment');\nconst checker = require('./exchangeChecker');\nconst errors = require('./exchangeErrors');\nconst Portfolio = require('./portfolioManager');\n// const Market = require('./market');\nconst orders = require('./orders');\nconst Trigger = require('./trigger');\nconst exchangeUtils = require('./exchangeUtils');\nconst bindAll = exchangeUtils.bindAll;\nconst isValidOrder = exchangeUtils.isValidOrder;\n\n\n\nclass Broker {\n  constructor(config) {\n    this.config = config;\n\n    if(config.private) {\n      if(this.cantTrade()) {\n        throw new Error(this.cantTrade());\n      }\n    } else {\n      if(this.cantMonitor()) {\n        throw new Error(this.cantMonitor());\n      }\n    }\n\n    this.orders = {\n      // contains current open orders\n      open: [],\n      // contains all closed orders\n      closed: []\n    }\n\n    const slug = config.exchange.toLowerCase();\n\n    const API = require('./wrappers/' + slug);\n\n    this.api = new API(config);\n\n    this.capabilities = API.getCapabilities();\n\n    this.marketConfig = _.find(this.capabilities.markets, (p) => {\n      return _.first(p.pair) === config.currency.toUpperCase() &&\n        _.last(p.pair) === config.asset.toUpperCase();\n    });\n\n    if(config.customInterval) {\n      this.interval = config.customInterval;\n      this.api.interval = config.customInterval;\n      console.log(new Date, '[GB] setting custom interval to', config.customInterval);\n    } else {\n      this.interval = this.api.interval || 1500;\n    }\n\n    this.market = config.currency.toUpperCase() + config.asset.toUpperCase();\n\n    if(config.private) {\n      this.portfolio = new Portfolio(config, this.api);\n    }\n\n    bindAll(this);\n  }\n\n  cantTrade() {\n    return checker.cantTrade(this.config);\n  }\n\n  cantMonitor() {\n    return checker.cantMonitor(this.config);\n  }\n\n  sync(callback) {\n    if(!this.private) {\n      this.setTicker();\n      return;\n    }\n\n    if(this.cantTrade()) {\n      throw new errors.ExchangeError(this.cantTrade());\n    }\n\n    this.syncPrivateData();\n  }\n\n  syncPrivateData(callback) {\n    async.series([\n      this.setTicker,\n      next => setTimeout(next, this.interval),\n      this.portfolio.setFee.bind(this.portfolio),\n      next => setTimeout(next, this.interval),\n      this.portfolio.setBalances.bind(this.portfolio),\n      next => setTimeout(next, this.interval)\n    ], callback);\n  }\n\n  setTicker(callback) {\n    this.api.getTicker((err, ticker) => {\n\n      if(err) {\n        if(err.message) {\n          console.log(this.api.name, err.message);\n          throw err;\n        } else {\n          console.log('err not wrapped in error:', err);\n          throw new errors.ExchangeError(err);\n        }\n      }\n\n      this.ticker = ticker;\n\n      if(_.isFunction(callback))\n        callback();\n    });\n  }\n\n  isValidOrder(amount, price) {\n    return isValidOrder({\n      market: this.marketConfig,\n      api: this.api,\n      amount,\n      price\n    });\n  }\n\n  createOrder(type, side, amount, parameters, handler) {\n    if(!this.config.private)\n      throw new Error('Client not authenticated');\n\n    if(side !== 'buy' && side !== 'sell')\n      throw new Error('Unknown side ' + side);\n\n    if(!orders[type])\n      throw new Error('Unknown order type');\n\n    const order = new orders[type]({\n      api: this.api,\n      marketConfig: this.marketConfig,\n      capabilities: this.capabilities\n    });\n\n    // todo: figure out a smarter generic way\n    this.syncPrivateData(() => {\n      order.setData({\n        balances: this.portfolio.balances,\n        ticker: this.ticker,\n      });\n\n      order.create(side, amount, parameters);\n    });\n\n    order.on('completed', summary => {\n      _.remove(this.orders.open, order);\n      this.orders.closed.push(summary);\n    });\n\n    return order;\n  }\n\n  createTrigger({type, onTrigger, props}) {\n    return new Trigger({\n      api: this.api,\n      type,\n      onTrigger,\n      props\n    });\n  }\n}\n\nmodule.exports = Broker;"
  },
  {
    "path": "exchange/orders/index.js",
    "content": "const sticky = require('./sticky');\n\nmodule.exports = {\n  sticky\n}"
  },
  {
    "path": "exchange/orders/limit.js",
    "content": "// NOTE: this is currently broken, see\n// @link https://github.com/askmike/gekko/issues/2398\n\nthrow ':(';\n\n/*\n  The limit order is a simple order:\n    - It is created at the specified price\n    - If it were to cross it will throw instead (only if postOnly is specified)\n    - It can be moved\n\n*/\n\nconst _ = require('lodash');\nconst async = require('async');\nconst events = require('events');\nconst moment = require('moment');\nconst errors = require('../exchangeErrors');\nconst BaseOrder = require('./order');\nconst states = require('./states');\n\nclass LimitOrder extends BaseOrder {\n  constructor(api) {\n    super(api);\n  }\n\n  create(side, amount, params) {\n    this.side = side;\n\n    this.postOnly = params.postOnly;\n\n    this.status = states.SUBMITTED;\n    this.emitStatus();\n\n    this.createOrder(price, amount);\n  }\n\n  createOrder(price, amount) {\n    this.amount = this.api.roundAmount(amount);\n    this.price = this.api.roundPrice(price);\n\n    // note: this assumes ticker data to be up to date\n    if(this.postOnly) {\n      if(side === 'buy' && this.price > this.data.ticker.ask)\n        throw new Error('Order crosses the book');\n      else if(side === 'sell' && this.price < this.data.ticker.bid)\n        throw new Error('Order crosses the book');\n    }\n\n    this.submit({\n      side: this.side,\n      amount: this.api.roundAmount(this.amount - alreadyFilled),\n      price: this.price,\n      alreadyFilled: this.filled\n    });\n  }\n\n  handleCreate(err, id) {\n    if(err)\n      throw err;\n\n    this.status = states.OPEN;\n    this.emitStatus();\n\n    this.id = id;\n\n    if(this.cancelling)\n      return this.cancel();\n\n    if(this.movingAmount)\n      return this.moveAmount();\n\n    if(this.movingPrice)\n      return this.movePrice();\n\n    this.timeout = setTimeout(this.checkOrder, this.checkInterval)\n  }\n\n  checkOrder() {\n    this.checking = true;\n    this.api.checkOrder(this.id, this.handleCheck);\n  }\n\n  handleCheck(err, result) {\n    if(this.cancelling || this.status === states.CANCELLED)\n      return;\n\n    this.checking = false;\n\n    if(err)\n      throw err;\n\n    if(result.open) {\n      if(result.filledAmount !== this.filledAmount) {\n        this.filledAmount = result.filledAmount;\n\n        // note: doc event API\n        this.emit('fill', this.filledAmount);\n      }\n\n      if(this.cancelling)\n        return this.cancel();\n\n      if(this.movingAmount)\n        return this.moveAmount();\n\n      if(this.movingPrice)\n        return this.movePrice();\n\n      this.timeout = setTimeout(this.checkOrder, this.checkInterval);\n      return;\n    }\n\n    if(!result.executed) {\n      // not open and not executed means it never hit the book\n      this.rejected();\n      return;\n    }\n\n    this.filled(this.price);\n  }\n\n  movePrice(price) {\n    if(this.completed)\n      return;\n\n    if(!price)\n      price = this.movePriceTo;\n\n    if(this.price === this.api.roundPrice(price))\n      // effectively nothing changed\n      return;\n\n    if(\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.checking\n    ) {\n      this.movePriceTo = price;\n      this.movingPrice = true;\n      return;\n    }\n\n    this.movingPrice = false;\n\n    this.price = this.api.roundPrice(price);\n\n    clearTimeout(this.timeout);\n\n    this.status = states.MOVING;\n\n    this.api.cancelOrder(this.id, (err, filled) => {\n      if(err)\n        throw err;\n\n      if(filled)\n        return this.filled(this.price);\n\n      this.submit({\n        side: this.side,\n        amount: this.amount,\n        price: this.price,\n        alreadyFilled: this.filled\n      });\n    });\n  }\n\n  moveAmount(amount) {\n    if(this.completed)\n      return;\n\n    if(!amount)\n      amount = this.moveAmountTo;\n\n    if(this.amount === this.api.roundAmount(amount))\n      // effectively nothing changed\n      return;\n\n    if(\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.checking\n    ) {\n      this.moveAmountTo = amount;\n      this.movingAmount = true;\n      return;\n    }\n\n    this.movingAmount = false;\n    this.amount = this.api.roundAmount(amount);\n\n    clearTimeout(this.timeout);\n\n    this.status = states.MOVING;\n    this.emitStatus();\n\n    this.api.cancelOrder(this.id, (err, filled) => {\n      if(err)\n        throw err;\n\n      if(filled)\n        return this.filled(this.price);\n\n      this.submit({\n        side: this.side,\n        amount: this.amount,\n        price: this.price,\n        alreadyFilled: this.filled\n      });\n    });\n  }\n\n  cancel() {\n    if(this.completed)\n      return;\n\n    if(\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.checking\n    ) {\n      this.cancelling = true;\n      return;\n    }\n\n    clearTimeout(this.timeout);\n\n    this.api.cancelOrder(this.id, (err, filled) => {\n      if(err)\n        throw err;\n\n      this.cancelling = false;\n\n      if(filled)\n        return this.filled(this.price);\n\n      this.status = states.CANCELLED;\n      this.emitStatus();\n      this.finish(false);\n    });\n  }\n}\n\nmodule.exports = LimitOrder;"
  },
  {
    "path": "exchange/orders/order.js",
    "content": "const EventEmitter = require('events');\nconst _ = require('lodash');\n\nconst exchangeUtils = require('../exchangeUtils');\nconst bindAll = exchangeUtils.bindAll;\nconst isValidOrder = exchangeUtils.isValidOrder;\nconst states = require('./states');\n\n// base order\n\nclass BaseOrder extends EventEmitter {\n  constructor(api) {\n    super();\n\n    this.api = api;\n\n    this.checkInterval = api.interval || 1500;\n    this.status = states.INITIALIZING;\n\n    this.completed = false;\n    this.completing = false;\n\n    bindAll(this);\n  }\n\n  submit({side, amount, price, alreadyFilled}) {\n    const check = isValidOrder({\n      market: this.market,\n      api: this.api,\n      amount,\n      price\n    });\n\n    if(!check.valid) {\n      if(alreadyFilled) {\n        // partially filled, but the remainder is too\n        // small.\n        return this.filled();\n      }\n\n      this.emit('invalidOrder', check.reason);\n      this.rejected(check.reason);\n    }\n\n    this.api[this.side](amount, this.price, this.handleCreate);\n  }\n\n  setData(data) {\n    this.data = data;\n  }\n\n  emitStatus() {\n    this.emit('statusChange', this.status);\n  }\n\n  cancelled() {\n    this.status = states.CANCELLED;\n    this.emitStatus();\n    this.completed = true;\n    this.finish();\n  }\n\n  rejected(reason) {\n    this.rejectedReason = reason;\n    this.status = states.REJECTED;\n    this.emitStatus();\n    console.log(new Date, 'sticky rejected', reason)\n    this.finish();\n  }\n\n  filled(price) {\n    this.status = states.FILLED;\n    this.emitStatus();\n    this.completed = true;\n    console.log(new Date, 'sticky filled')\n    this.finish(true);\n  }\n\n  finish(filled) {\n    this.completed = true;\n    this.emit('completed', {\n      status: this.status,\n      filled\n    })\n  }\n}\n\nmodule.exports = BaseOrder;"
  },
  {
    "path": "exchange/orders/states.js",
    "content": "const states = {\n  // Not created\n  INITIALIZING: 'INITIALIZING',\n\n  // Created and send to the exchange, but no acknowledgement received yet\n  SUBMITTED: 'SUBMITTED',\n\n  // In the process of moving the order\n  MOVING: 'MOVING',\n\n  // Order is open on the exchange\n  OPEN: 'OPEN',\n\n\n  CHECKING: 'CHECKING',\n\n  CHECKED: 'CHECKED',\n\n  // the orders below indicate a fully completed order\n\n\n  // Order is completely filled\n  FILLED: 'FILLED',\n\n  // Order was succesfully cancelled\n  CANCELLED: 'CANCELLED',\n\n  // Order was rejected by the exchange\n  REJECTED: 'REJECTED',\n\n  ERROR: 'ERROR'\n}\n\nmodule.exports = states;"
  },
  {
    "path": "exchange/orders/sticky.js",
    "content": "/*\n  The sticky order is an advanced order:\n    - It is created at a limit price of X\n      - if limit is not specified always at bbo.\n      - if limit is specified the price is either limit or the bbo (whichever is more favorable)\n    - it will readjust the order:\n      - if outbid is true it will outbid the current bbo (on supported exchanges)\n      - if outbid is false it will stick to current bbo when this moves\n    - If the price moves away from the order it will \"stick to\" the top\n\n  TODO:\n    - native move\n*/\n\nconst _ = require('lodash');\nconst async = require('async');\nconst events = require('events');\nconst moment = require('moment');\nconst errors = require('../exchangeErrors');\nconst BaseOrder = require('./order');\nconst states = require('./states');\n\nclass StickyOrder extends BaseOrder {\n  constructor({api, marketConfig, capabilities}) {\n    super(api);\n\n    this.market = marketConfig;\n    this.capabilities = capabilities;\n\n    // global async lock\n    this.sticking = false;\n\n    // bound helpers\n    this.roundPrice = this.api.roundPrice.bind(this.api);\n    this.roundAmount = this.api.roundAmount.bind(this.api);\n    if(_.isFunction(this.api.outbidPrice)) {\n      this.outbidPrice = this.api.outbidPrice.bind(this.api);\n    }\n\n    this.debug = this.api.name === 'Deribit2';\n    this.log = m => this.debug && console.log(new Date, m);\n  }\n\n  create(side, rawAmount, params = {}) {\n    if(this.completed || this.completing) {\n      return false;\n    }\n\n    console.log(new Date, 'sticky create', side);\n\n    this.side = side;\n\n    this.amount = this.roundAmount(rawAmount);\n\n    this.initialLimit = params.initialLimit;\n\n    if(side === 'buy') {\n      if(params.limit) {\n        this.limit = this.roundPrice(params.limit);\n      } else {\n        this.noLimit = true;\n        this.limit = Infinity;\n      }\n    } else {\n      if(params.limit) {\n        this.limit = this.roundPrice(params.limit);\n      } else {\n        this.noLimit = true;\n        this.limit = -Infinity;\n      }\n    }\n\n    this.status = states.SUBMITTED;\n    this.emitStatus();\n\n    this.orders = {};\n\n    this.outbid = params.outbid && _.isFunction(this.outbidPrice);\n\n    if(this.data && this.data.ticker) {\n      this.price = this.calculatePrice(this.data.ticker);\n      this.createOrder();\n    } else {\n      this.api.getTicker((err, ticker) => {\n        if(this.handleError(err)) {\n          console.log(new Date, 'error get ticker');\n          return;\n        }\n\n        this.price = this.calculatePrice(ticker);\n        this.createOrder();\n      });\n    }\n\n    return this;\n  }\n\n  calculatePrice(ticker) {\n\n    const r = this.roundPrice;\n\n    if(this.initialLimit && !this.id) {\n      console.log('passing initial limit of:', this.limit);\n      return r(this.limit);\n    }\n\n    if(this.side === 'buy') {\n\n      if(!this.noLimit && ticker.bid >= this.limit) {\n        return r(this.limit);\n      }\n\n      if(!this.outbid) {\n        return r(ticker.bid);\n      }\n\n      const outbidPrice = this.outbidPrice(ticker.bid, true);\n\n      if(outbidPrice <= this.limit && outbidPrice < ticker.ask) {\n        return r(outbidPrice);\n      } else {\n        return r(this.limit);\n      }\n\n    } else if(this.side === 'sell') {\n\n      if(!this.noLimit && ticker.ask <= this.limit) {\n        return r(this.limit);\n      }\n\n      if(!this.outbid) {\n        return r(ticker.ask);\n      }\n\n      const outbidPrice = this.outbidPrice(ticker.ask, false);\n\n      if(outbidPrice >= this.limit && outbidPrice > ticker.bid) {\n        return r(outbidPrice);\n      } else {\n        return r(this.limit);\n      }\n    }\n  }\n\n  createOrder() {\n    if(this.completed || this.completing) {\n      return false;\n    }\n\n    const alreadyFilled = this.calculateFilled();\n\n    this.submit({\n      side: this.side,\n      amount: this.roundAmount(this.amount - alreadyFilled),\n      price: this.price,\n      alreadyFilled\n    });\n  }\n\n  // check if the last order was partially filled\n  // on an exchange that does not pass fill data on cancel\n  // see https://github.com/askmike/gekko/pull/2450\n  handleInsufficientFundsError(err) {\n    if(\n      !err ||\n      err.type !== 'insufficientFunds' ||\n      !this.capabilities.limitedCancelConfirmation ||\n      !this.id\n    ) {\n      return false;\n    }\n\n    const id = this.id;\n\n    setTimeout(\n      () => {\n        this.api.getOrder(id, (innerError, res) => {\n          if(this.handleError(innerError)) {\n            return;\n          }\n\n          const amount = res.amount;\n\n          if(this.orders[id].filled === amount) {\n            // handle original error\n            return this.handleError(err);\n          }\n\n          this.orders[id].filled = amount;\n          this.emit('fill', this.calculateFilled());\n          if(this.calculateFilled() >= this.amount) {\n            return this.filled(this.price);\n          }\n\n          setTimeout(this.createOrder, this.checkInterval);\n        });\n      },\n      this.checkInterval\n    );\n\n    return true;\n  }\n\n  handleCreate(err, id) {\n\n    if(this.handleInsufficientFundsError(err)) {\n      return;\n    }\n\n    if(this.handleError(err)) {\n      console.log(new Date, 'handleCreate error');\n      return;\n    }\n\n    if(!id) {\n      console.log('BLUP! no id...');\n    }\n\n    // potentailly clean up old order\n    if(\n      this.id &&\n      this.orders[this.id] &&\n      this.orders[this.id].filled === 0\n    )\n      delete this.orders[this.id];\n\n    // register new order\n    this.log(`${this.side} old id: ${this.id} new id: ${id}`);\n    this.id = id;\n\n    this.orders[id] = {\n      price: this.price,\n      filled: 0\n    }\n\n    this.emit('new order', this.id);\n    this.emit('movelimit handled', new Date);\n\n    this.status = states.OPEN;\n    this.emitStatus();\n\n    this.scheduleNextCheck();\n  }\n\n  initiateDefferedAction() {\n    // check whether we had an action pending\n    if(this.cancelling) {\n      this.cancel();\n      return true;\n    }\n\n    if(this.movingLimit && this.moveLimit()) {\n      return true;\n    }\n\n    if(this.movingAmount) {\n      this.moveAmount();\n      return true;\n    }\n\n    return false;\n  }\n\n  scheduleNextCheck() {\n\n    // remove lock\n    this.sticking = false;\n\n    if(this.initiateDefferedAction()) {\n      return;\n    }\n\n    // register check\n    this.timeout = setTimeout(this.checkOrder, this.checkInterval);\n\n  }\n\n  checkOrder() {\n\n    if(this.completed || this.completing) {\n      return console.log(new Date, this.side, 'checkOrder called on completed/completing order..', this.completed, this.completing);\n    }\n\n    if(this.status === states.MOVING) {\n      return console.log(new Date, this.side, 'refusing to check, in the middle of move');\n    }\n\n    if(this.initiateDefferedAction()) {\n      console.log(new Date, this.side, 'skipping check logic, better things to do - 0');\n      return;\n    }\n\n    this.sticking = true;\n    const checkId = this.id;\n\n    this.api.checkOrder(this.id, (err, result) => {\n\n      if(!this.debug) {\n        if(this.ignoreCheckResult) {\n          this.log(this.side + ' debug ignoring check result');\n          this.ignoreCheckResult = false;\n          return;\n        }\n      }\n\n      if(this.status === states.MOVING) {\n        this.log(`${this.side} ${this.id} debug ignoring check result - in the middle of move`);\n        this.ignoreCheckResult = false;\n        return;\n      }\n\n      if(checkId !== this.id) {\n        this.log(this.side + ' debug got check on old id ' + checkId + ', ' + this.id);\n        this.ignoreCheckResult = false;\n        return;\n      }\n\n      this.status = states.CHECKED;\n      this.emitStatus();\n\n      if(this.handleError(err)) {\n        console.log(new Date, 'checkOrder error');\n        return;\n      }\n\n      if(result.open) {\n        if(result.filledAmount !== this.orders[this.id].filled) {\n          this.orders[this.id].filled = result.filledAmount;\n          this.emit('fill', this.calculateFilled());\n        }\n\n        // if we are already at limit we dont care where the top is\n        // note: might be string VS float\n        if(this.price == this.limit) {\n          this.scheduleNextCheck();\n          return;\n        }\n\n        if(this.initiateDefferedAction()) {\n          console.log(new Date, this.side, 'skipping check ticker logic, better things to do 1');\n          return;\n        }\n\n        this.api.getTicker((err, ticker) => {\n          if(this.handleError(err)) {\n            console.log(new Date, 'getTicker error');\n            return;\n          }\n\n          if(this.initiateDefferedAction()) {\n            console.log(new Date, this.side, 'skipping check ticker logic, better things to do 2');\n            return;\n          }\n\n          if(this.status === states.MOVING) {\n            this.log(`${this.side} ${this.id} debug ignoring check result - in the middle of move     ---- 2`);\n            this.ignoreCheckResult = false;\n            return;\n          }\n\n          this.ticker = ticker;\n          this.emit('ticker', ticker);\n\n          const bookSide = this.side === 'buy' ? 'bid' : 'ask';\n          // note: might be string VS float\n          if(ticker[bookSide] != this.price) {\n            return this.move(this.calculatePrice(ticker));\n          } else {\n            this.scheduleNextCheck();\n          }\n        });\n\n        return;\n      }\n\n      // it's not open right now\n      // meaning we are done\n      this.sticking = false;\n\n      if(!result.executed) {\n        // not open and not executed means it never hit the book\n        console.log(this.side, this.status, this.id, 'not open not executed!', result);\n        this.rejected();\n        throw 'a';\n        return;\n      }\n\n      // order got filled!\n      this.orders[this.id].filled = this.amount;\n      this.emit('fill', this.amount);\n      this.filled(this.price);\n    });\n\n\n    this.status = states.CHECKING;\n    this.emitStatus();\n  }\n\n  // global error handler\n  handleError(error) {\n    if(!error) {\n      return false;\n    }\n\n    console.log(new Date, '[sticky order] FATAL ERROR', error.message);\n    console.log(new Date, error);\n    this.status = states.ERROR;\n    this.emitStatus();\n    this.error = error;\n\n    this.emit('error', error);\n    return true;\n  }\n\n  // returns true if the order was fully filled\n  // handles partial fills on cancels calls\n  // on exchanges that support it.\n  handleCancel(filled, data) {\n    // it got filled before we could cancel\n    if(filled) {\n      this.orders[this.id].filled = this.amount;\n      this.emit('fill', this.amount);\n      this.filled(this.price);\n      return;\n    }\n\n    // if we have data on partial fills\n    // check whether we had a partial fill\n    if(_.isObject(data)) {\n      let amountFilled = data.filled;\n\n      if(!amountFilled && data.remaining) {\n        const alreadyFilled = this.calculateFilled();\n        const orderAmount = this.roundAmount(this.amount - alreadyFilled);\n        amountFilled = this.roundAmount(orderAmount - data.remaining);\n      }\n\n      if(amountFilled > this.orders[this.id].filled) {\n        this.orders[this.id].filled = amountFilled;\n        this.emit('fill', this.calculateFilled());\n      }\n    }\n\n    return;\n  }\n\n  move(price) {\n    if(this.completed || this.completing) {\n      return false;\n    }\n\n    this.status = states.MOVING;\n    this.emitStatus();\n\n    this.log(`${this.side} ${this.id} this.move 1`);\n\n    const cancelId = this.id;\n\n    this.api.cancelOrder(cancelId, (err, filled, data) => {\n      this.log(`${this.side} ${this.id} this.move 2`);\n\n      if(this.handleError(err)) {\n        console.log(new Date, 'error move');\n        return;\n      }\n\n      // it got filled before we could cancel\n      if(cancelId === this.id && this.handleCancel(filled, data)) {\n        return;\n      }\n\n      // update to new price\n      this.price = this.roundPrice(price);\n\n      this.createOrder();\n    });\n\n    return true;\n  }\n\n  calculateFilled() {\n    let totalFilled = 0;\n    _.each(this.orders, (order, id) => totalFilled += order.filled);\n\n    return totalFilled;\n  }\n\n  moveLimit(limit) {\n    if(this.completed || this.completing) {\n      return false;\n    }\n\n    if(!limit) {\n      limit = this.moveLimitTo;\n      // console.log(new Date, this.side, 'debug resuming move!');\n    } else {\n      this.limitRequested = new Date;\n      this.log(this.side + ' received move limit');\n    }\n\n    if(this.limit === this.roundPrice(limit)) {\n      // effectively nothing changed\n      return false;\n    }\n\n    if(this.cancelling) {\n      return false;\n    }\n\n    this.emit('movelimit', new Date);\n\n    if(\n      this.status === states.INITIALIZING ||\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.status === states.CHECKING ||\n      this.sticking\n    ) {\n\n      if(\n        !this.api.fillDataOnCancel ||\n        this.status === states.MOVING ||\n        this.status === states.SUBMITTED\n      ) {\n        // console.log(new Date, '[sticky]', this.side, 'skipping because:', this.status);\n        this.moveLimitTo = limit;\n        this.movingLimit = true;\n        return false;\n      }\n    }\n\n    this.limit = this.roundPrice(limit);\n    this.movingLimit = false;\n\n    const moveBuy = this.side === 'buy' && this.limit < this.price;\n    const moveSell = this.side === 'sell' && this.limit > this.price;\n\n    if(moveBuy || moveSell) {\n      this.sticking = true;\n      clearTimeout(this.timeout);\n\n      if(this.api.fillDataOnCancel && this.status === states.CHECKING) {\n        this.log(this.side + 'debug move overwrites running check ' + this.status + ' ' + this.id);\n        this.ignoreCheckResult = true;\n      }\n\n      this.log(this.side + ' moving ' + this.id);\n\n      const timeToMove = new Date - this.limitRequested;\n      if(timeToMove > 300) {\n        console.log(new Date, this.side, 'long time to move:', timeToMove);\n      }\n      this.move(this.limit);\n\n      return true;\n    }\n\n    this.emit('movelimit handled', new Date);\n    return false;\n  }\n\n  moveAmount(amount) {\n    if(this.completed || this.completing)\n      return false;\n\n    if(!amount)\n      amount = this.moveAmountTo;\n\n    if(this.amount === this.roundAmount(amount))\n      // effectively nothing changed\n      return true;\n\n    if(this.calculateFilled() > this.roundAmount(amount)) {\n      // the amount is now below how much we have\n      // already filled.\n      this.filled();\n      return false;\n    }\n\n    if(\n      this.status === states.INITIALIZING ||\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.sticking\n    ) {\n      this.moveAmountTo = amount;\n      this.movingAmount = true;\n      return;\n    }\n\n    this.amount = this.roundAmount(amount - this.calculateFilled());\n\n    if(this.amount < this.market.minimalOrder.amount) {\n      if(this.calculateFilled()) {\n        // we already filled enough of the order!\n        this.filled();\n        return false;\n      } else {\n        this.handleError(new Error(\"The amount \" + this.amount + \" is too small.\"));\n      }\n    }\n\n    clearTimeout(this.timeout);\n\n    this.movingAmount = false;\n    this.sticking = true;\n\n    this.api.cancelOrder(this.id, (err, filled, data) => {\n      if(this.handleError(err)) {\n        console.log(new Date, 'error cancel');\n        return;\n      }\n\n      // it got filled before we could cancel\n      if(this.handleCancel(filled, data)) {\n        return;\n      }\n\n      this.createOrder();\n    });\n\n    return true;\n  }\n\n  cancel() {\n    if(this.completed)\n      return;\n\n    if(\n      this.status === states.SUBMITTED ||\n      this.status === states.MOVING ||\n      this.sticking\n    ) {\n      this.cancelling = true;\n      return;\n    }\n\n    this.completing = true;\n    clearTimeout(this.timeout);\n\n    this.api.cancelOrder(this.id, (err, filled, data) => {\n      if(this.handleError(err)) {\n        console.log(new Date, 'error cancel');\n        return;\n      }\n\n      this.cancelling = false;\n\n      // it got filled before we could cancel\n      if(this.handleCancel(filled, data)) {\n        return;\n      }\n\n      this.status = states.CANCELLED;\n      this.emitStatus();\n\n      this.finish(false);\n    })\n  }\n\n  createSummary(next) {\n    if(!this.completed)\n      console.log(new Date, 'createSummary BUT ORDER NOT COMPLETED!');\n\n    if(!next)\n      next = _.noop;\n\n    const checkOrders = _.keys(this.orders)\n      .map(id => next => {\n\n        if(!this.orders[id].filled) {\n          return next();\n        }\n\n        setTimeout(() => this.api.getOrder(id, next), this.checkInterval);\n      });\n\n    async.series(checkOrders, (err, trades) => {\n      // note this is a standalone function after the order is\n      // completed, as such we do not use the handleError flow.\n      if(err) {\n        console.log(new Date, 'error createSummary (checkOrder)')\n        return next(err);\n      }\n\n      let price = 0;\n      let amount = 0;\n      let date = moment(0);\n\n      _.each(trades, trade => {\n        if(!trade) {\n          return;\n        }\n\n        // last fill counts\n        date = moment(trade.date);\n        price = ((price * amount) + (+trade.price * trade.amount)) / (+trade.amount + amount);\n        amount += +trade.amount;\n      });\n\n      const summary = {\n        price,\n        amount,\n        date,\n        side: this.side,\n        orders: trades.length\n      }\n\n      const first = _.first(trades);\n\n      if(first && first.fees) {\n        summary.fees = {};\n\n        _.each(trades, trade => {\n          if(!trade) {\n            return;\n          }\n\n          _.each(trade.fees, (amount, currency) => {\n            if(!_.isNumber(summary.fees[currency])) {\n              summary.fees[currency] = amount;\n            } else {\n              summary.fees[currency] += amount;\n            }\n          });\n        });\n      }\n\n      if(first && !_.isUndefined(first.feePercent)) {\n        summary.feePercent = 0;\n        let amount = 0;\n\n        _.each(trades, trade => {\n          if(!trade || _.isUndefined(trade.feePercent)) {\n            return;\n          }\n\n          if(trade.feePercent === 0) {\n            return;\n          }\n\n          summary.feePercent = ((summary.feePercent * amount) + (+trade.feePercent * trade.amount)) / (+trade.amount + amount);\n          amount += +trade.amount;\n        });\n      }\n\n      this.emit('summary', summary);\n      next(undefined, summary);\n    });\n  }\n \n}\n\nmodule.exports = StickyOrder;"
  },
  {
    "path": "exchange/package.json",
    "content": "{\n  \"name\": \"gekko-broker\",\n  \"version\": \"0.6.8\",\n  \"description\": \"Gekko's order execution library for bitcoin & crypto exchanges\",\n  \"main\": \"gekkoBroker.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"github.com/askmike/gekko\"\n  },\n  \"keywords\": [\n    \"crypto\",\n    \"bitcoin\",\n    \"exchange\",\n    \"execution\",\n    \"trade\"\n  ],\n  \"author\": \"Mike van Rossum <mike@mvr.me>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"async\": \"^2.6.0\",\n    \"binance\": \"^1.3.3\",\n    \"bitfinex-api-node\": \"^2.0.0-beta\",\n    \"bitx\": \"^1.5.0\",\n    \"bluebird\": \"^3.5.1\",\n    \"coinfalcon\": \"^1.0.3\",\n    \"crypto-js\": \"^3.1.9-1\",\n    \"gdax\": \"^0.7.0\",\n    \"gekko-bittrex\": \"^0.8.5\",\n    \"gekko-broker-poloniex\": \"^0.0.12\",\n    \"kraken-api\": \"askmike/npm-kraken-api#a69dfb3eb296b9c795cfa48dd31edcdc1b3d5398\",\n    \"lodash\": \"^4.17.5\",\n    \"moment\": \"^2.22.1\",\n    \"request-promise\": \"^4.2.2\",\n    \"retry\": \"^0.12.0\",\n    \"therocktrading\": \"^0.9.0\"\n  }\n}\n"
  },
  {
    "path": "exchange/portfolioManager.js",
    "content": "/*\n  The Portfolio class holds data about the portfolio\n*/\n\nconst _ = require('lodash');\nconst async = require('async');\nconst errors = require('./exchangeErrors');\n// const EventEmitter = require('events');\n\nclass Portfolio {\n  constructor(config, api) {\n    _.bindAll(this);\n    this.config = config;\n    this.api = api;\n    this.balances = {};\n    this.fee = null;\n  }\n\n  getBalance(fund) {\n    return this.getFund(fund).amount;\n  }\n\n  // return the [fund] based on the data we have in memory\n  getFund(fund) {\n    return _.find(this.balances, function(f) { return f.name === fund});\n  }\n\n  // convert into the portfolio expected by the performanceAnalyzer\n  convertBalances(asset,currency) { // rename?\n    var asset = _.find(this.balances, a => a.name === this.config.asset).amount;\n    var currency = _.find(this.balances, a => a.name === this.config.currency).amount;\n\n    return {\n      currency,\n      asset,\n      balance: currency + (asset * this.ticker.bid)\n    }\n  }\n\n  setBalances(callback) {\n    let set = (err, fullPortfolio) => {\n      if(err) {\n        console.log(err);\n        throw new errors.ExchangeError(err);\n      }\n\n      // only include the currency/asset of this market\n      const balances = [ this.config.currency, this.config.asset ]\n        .map(name => {\n          let item = _.find(fullPortfolio, {name});\n\n          if(!item) {\n            // assume we have 0\n            item = { name, amount: 0 };\n          }\n\n          return item;\n        });\n\n      this.balances = balances;\n\n      if(_.isFunction(callback))\n        callback();\n    }\n\n    this.api.getPortfolio(set);\n  }\n  \n  setFee(callback) {\n    this.api.getFee((err, fee) => {\n      if(err)\n        throw new errors.ExchangeError(err);\n\n      this.fee = fee;\n\n      if(_.isFunction(callback))\n        callback();\n    });\n  }\n\n  setTicker(ticker) {\n    this.ticker = ticker;\n  }\n\n}\n\nmodule.exports = Portfolio"
  },
  {
    "path": "exchange/trigger.js",
    "content": "// wraps around a low level trigger and feeds\n// it live market data.\n\nconst _ = require('lodash');\n\nconst exchangeUtils = require('./exchangeUtils');\nconst bindAll = exchangeUtils.bindAll;\n\nconst triggers = require('./triggers');\n\n// @param api: a gekko broker wrapper instance\n// @param type: type of trigger to wrap\n// @param props: properties to feed to trigger\nclass Trigger {\n  constructor({api, type, props, onTrigger}) {\n    this.onTrigger = onTrigger;\n    this.api = api;\n\n    this.isLive = true;\n\n    // note: we stay on the safe side and trigger\n    // as soon as the bid goes below trail.\n    this.tickerProp = 'bid';\n\n    if(!_.has(triggers, type)) {\n      throw new Error('Gekko Broker does not know trigger ' + type);\n    }\n\n    this.CHECK_INTERVAL = this.api.interval * 10;\n\n    bindAll(this);\n    this.trigger = new triggers[type]({\n      onTrigger: this.propogateTrigger,\n      ...props\n    })\n\n    this.scheduleFetch();\n  }\n\n  scheduleFetch() {\n    this.timout = setTimeout(this.fetch, this.CHECK_INTERVAL);\n  }\n\n  fetch() {\n    if(!this.isLive) {\n      return;\n    }\n    this.api.getTicker(this.processTicker)\n  }\n\n  processTicker(err, ticker) {\n    if(!this.isLive) {\n      return;\n    }\n    \n    if(err) {\n      return console.log('[GB/trigger] failed to fetch ticker:', err);\n    }\n\n    this.price = ticker[this.tickerProp];\n\n    this.trigger.updatePrice(this.price);\n    this.scheduleFetch();\n  }\n\n  cancel() {\n    this.isLive = false;\n    clearTimeout(this.timout);\n  }\n\n  propogateTrigger(payload) {\n    if(!this.isLive) {\n      return;\n    }\n    this.isLive = false;\n    this.onTrigger(payload);\n  }\n}\n\nmodule.exports = Trigger;"
  },
  {
    "path": "exchange/triggers/index.js",
    "content": "const trailingStop = require('./trailingStop');\n\nmodule.exports = { trailingStop };"
  },
  {
    "path": "exchange/triggers/trailingStop.js",
    "content": "const EventEmitter = require('events');\n\n// Note: as of now only supports trailing the price going up (after \n// a buy), on trigger (when the price moves down) you should sell.\n\n\n// @param initialPrice: initial price, preferably buy price\n// @param trail: fixed offset from the price\n// @param onTrigger: fn to call when the stop triggers\nclass TrailingStop extends EventEmitter {\n  constructor({trail, initialPrice, onTrigger}) {\n    super();\n\n    this.trail = trail;\n    this.isLive = true;\n    this.onTrigger = onTrigger;\n\n    this.previousPrice = initialPrice;\n    this.trailingPoint = initialPrice - this.trail;\n  }\n\n  updatePrice(price) {\n    if(!this.isLive) {\n      return;\n    }\n\n    if(price > this.trailingPoint + this.trail) {\n      this.trailingPoint = price - this.trail;\n    }\n\n    this.previousPrice = price;\n\n    if(price <= this.trailingPoint) {\n      this.trigger();\n    }\n  }\n\n  updateTrail(trail) {\n    if(!this.isLive) {\n      return;\n    }\n\n    this.trail = trail;\n    this.trailingPoint = this.previousPrice - this.trail;\n    // recheck whether moving the trail triggered.\n    this.updatePrice(this.previousPrice);\n  }\n\n  trigger() {\n    if(!this.isLive) {\n      return;\n    }\n\n    this.isLive = false;\n    if(this.onTrigger) {\n      this.onTrigger(this.previousPrice);\n    }\n    this.emit('trigger', this.previousPrice);\n  }\n}\n\nmodule.exports = TrailingStop;"
  },
  {
    "path": "exchange/util/genMarketFiles/update-binance.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst request = require('request-promise');\nconst Promise = require('bluebird');\n\n\nlet getOrderMinSize = currency => {\n  if (currency === 'BTC') return 0.001;\n  else if (currency === 'ETH') return 0.01;\n  else if (currency === 'USDT') return 10;\n  else return 1;\n};\n\nconst options = {\n  url: 'https://www.binance.com/exchange/public/product',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n};\n\nrequest(options)\n  .then(body => {\n    if (!body && !body.data) {\n      throw new Error('Unable to fetch product list, response was empty');\n    }\n\n    let assets = _.uniqBy(_.map(body.data, market => market.baseAsset));\n    let currencies = _.uniqBy(_.map(body.data, market => market.quoteAsset));\n    let pairs = _.map(body.data, market => {\n      return {\n        pair: [market.quoteAsset, market.baseAsset],\n        minimalOrder: {\n          amount: parseFloat(market.minTrade),\n          price: parseFloat(market.tickSize),\n          order: getOrderMinSize(market.quoteAsset),\n        },\n      };\n    });\n\n    return { assets: assets, currencies: currencies, markets: pairs };\n  })\n  .then(markets => {\n    fs.writeFileSync('../../wrappers/binance-markets.json', JSON.stringify(markets, null, 2));\n    console.log(`Done writing Binance market data`);\n  })\n  .catch(err => {\n    console.log(`Couldn't import products from Binance`);\n    console.log(err);\n  });\n"
  },
  {
    "path": "exchange/util/genMarketFiles/update-bitfinex.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst request = require('request-promise');\nconst Promise = require('bluebird');\n\nrequest({\n  url: 'https://api.bitfinex.com/v1/symbols_details',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n})\n.then(body => {\n  if (!body) {\n    throw new Error('Unable to fetch list of assets, response was empty');\n  }\n\n  return body;\n})\n.then(results => {\n  let assets = _.uniq(_.map(results, market => {\n    return market.pair.substring(0, 3).toUpperCase();\n  }));\n\n  let currencies = _.uniq(_.map(results, market => {\n    return market.pair.substring(3, 6).toUpperCase();\n  }));\n\n  let markets = _.map(results, market => {\n    return {\n      pair: [\n        market.pair.substring(3, 6).toUpperCase(),\n        market.pair.substring(0, 3).toUpperCase()\n      ],\n      minimalOrder: {\n        amount: market.minimum_order_size,\n        unit: 'asset',\n      },\n    };\n  });\n\n  return { assets: assets, currencies: currencies, markets: markets };\n})\n.then(markets => {\n  fs.writeFileSync('../../wrappers/bitfinex-markets.json', JSON.stringify(markets, null, 2));\n  console.log(`Done writing Bitfinex market data`);\n})\n.catch(err => {\n  console.log(`Couldn't import products from Bitfinex`);\n  console.log(err);\n});\n\n  \n"
  },
  {
    "path": "exchange/util/genMarketFiles/update-coinbase.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst request = require('request-promise');\nconst Promise = require('bluebird');\n\nrequest({\n  url: 'https://api.pro.coinbase.com/products',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n})\n.then(body => {\n  if (!body) {\n    throw new Error('Unable to fetch list of assets, response was empty');\n  }\n\n  return body;\n})\n.then(results => {\n  let assets = _.uniq(_.map(results, market => {\n    return market.base_currency.toUpperCase();\n  }));\n\n  let currencies = _.uniq(_.map(results, market => {\n    return market.quote_currency.toUpperCase();\n  }));\n\n  let markets = _.map(results, market => {\n    return {\n      pair: [\n        market.quote_currency.toUpperCase(),\n        market.base_currency.toUpperCase()\n      ],\n      minimalOrder: {\n        amount: market.base_min_size,\n        unit: 'asset',\n      },\n    };\n  });\n\n  return { assets: assets, currencies: currencies, markets: markets };\n})\n.then(markets => {\n  fs.writeFileSync('../../wrappers/coinbase-markets.json', JSON.stringify(markets, null, 2));\n  console.log(`Done writing Coinbase market data`);\n})\n.catch(err => {\n  console.log(`Couldn't import products from Coinbase`);\n  console.log(err);\n});\n\n  \n"
  },
  {
    "path": "exchange/util/genMarketFiles/update-coinfalcon.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst request = require('request-promise');\nconst Promise = require('bluebird');\n\nconst options = {\n  url: 'https://coinfalcon.com/api/v1/markets',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n};\n\nrequest(options)\n  .then(body => {\n    if (!body && !body.data) {\n      throw new Error('Unable to fetch product list, response was empty');\n    }\n\n    let assets = _.uniq(_.map(body.data, market => market.name.split('-')[0]));\n    let currencies = _.uniq(_.map(body.data, market => market.name.split('-')[1]));\n    let pairs = _.map(body.data, market => {\n      var currency = market.name.split('-')[1];\n      var asset = market.name.split('-')[0];\n      return {\n        pair: [currency, asset],\n        minimalOrder: {\n          amount: parseFloat(market.min_volume),\n          price: parseFloat(market.min_price),\n          order: 0.0\n        },\n      };\n    });\n\n    return { assets: assets, currencies: currencies, markets: pairs };\n  })\n  .then(markets => {\n    fs.writeFileSync('../../wrappers/coinfalcon-markets.json', JSON.stringify(markets, null, 2));\n    console.log(`Done writing CoinFalcon market data`);\n  })\n  .catch(err => {\n    console.log(`Couldn't import products from CoinFalcon`);\n    console.log(err);\n  });\n"
  },
  {
    "path": "exchange/util/genMarketFiles/update-kraken.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst request = require('request-promise');\nconst Promise = require('bluebird');\n\n// Minimum amounts are not queryable, get them here \n// https://support.kraken.com/hc/en-us/articles/205893708-What-is-the-minimum-order-size-\n\nlet getMinTradeSize = asset => {\n  let minTradeSize = 0.01;\n  switch (asset) {\n  case 'XREP':\n    minTradeSize = '0.3'\n    break;\n  case 'XXBT':\n    minTradeSize = '0.002'\n    break;\n  case 'BCH':\n    minTradeSize = '0.002'\n    break;\n  case 'ADA':\n    minTradeSize = '1'\n    break;\n  case 'DASH':\n    minTradeSize = '0.03'\n    break;\n  case 'XXDG':\n    minTradeSize = '3000'\n    break;\n  case 'EOS':\n    minTradeSize = '3.0'\n    break;\n  case 'XETH':\n    minTradeSize = '0.02'\n    break;\n  case 'XETC':\n    minTradeSize = '0.3'\n    break;\n  case 'GNO':\n    minTradeSize = '0.03'\n    break;\n  case 'XICN':\n    minTradeSize = '2'\n    break;\n  case 'XLTC':\n    minTradeSize = '0.1'\n    break;\n  case 'XMLN':\n    minTradeSize = '0.1'\n    break;\n  case 'XXMR':\n    minTradeSize = '0.1'\n    break;\n  case 'QTUM':\n    minTradeSize = '0.1'\n    break;\n  case 'XXRP':\n    minTradeSize = '30'\n    break;\n  case 'XXLM':\n    minTradeSize = '30'\n    break;\n  case 'USDT':\n    minTradeSize = '5'\n    break;\n  case 'XTZ':\n    minTradeSize = '1'\n    break;\n  case 'XZEC':\n    minTradeSize = '0.03'\n    break;\n  default:\n    break;\n  }\n\n  return minTradeSize;\n}\n\nlet assetPromise = request({\n  url: 'https://api.kraken.com/0/public/Assets',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n}).then(body => {\n  if (!body || !body.result) {\n    throw new Error('Unable to fetch list of assets, response was empty')\n  } else if (!_.isEmpty(body.error)) {\n    throw new Error(`Unable to fetch list of assets: ${body.error}`);\n  }\n\n  return body.result;\n});\n\nlet assetPairsPromise = request({\n  url: 'https://api.kraken.com/0/public/AssetPairs',\n  headers: {\n    Connection: 'keep-alive',\n    'User-Agent': 'Request-Promise',\n  },\n  json: true,\n}).then(body => {\n  if (!body || !body.result) {\n    throw new Error('Unable to fetch list of assets, response was empty')\n  } else if (!_.isEmpty(body.error)) {\n    throw new Error(`Unable to fetch list of assets: ${body.error}`);\n  }\n\n  return body.result;\n});\n\nPromise.all([assetPromise, assetPairsPromise])\n  .then(results => {\n    let assets = _.uniq(_.map(results[1], market => {\n      return results[0][market.base].altname;\n    }));\n\n    let currencies = _.uniq(_.map(results[1], market => {\n      return results[0][market.quote].altname;\n    }));\n\n    let marketKeys = _.filter(_.keys(results[1]), k => { return !k.endsWith('.d'); });\n    let markets = _.map(marketKeys, k => {\n      let market = results[1][k];\n      let asset = results[0][market.base];\n      let currency = results[0][market.quote];\n      return {\n        pair: [currency.altname, asset.altname],\n        prefixed: [market.quote, market.base],\n        book: k,\n        minimalOrder: {\n          amount: getMinTradeSize(market.base),\n          unit: 'asset',\n        },\n        pricePrecision: market.pair_decimals,\n        amountPrecision: market.lot_decimals\n      };\n    });\n\n    return { assets: assets, currencies: currencies, markets: markets };\n  })\n  .then(markets => {\n    fs.writeFileSync('../../wrappers/kraken-markets.json', JSON.stringify(markets, null, 2));\n    console.log(`Done writing Kraken market data`);\n  })\n  .catch(err => {\n    console.log(`Couldn't import products from Kraken`);\n    console.log(err);\n  });\n\n  \n"
  },
  {
    "path": "exchange/wrappers/DEBUG_exchange-simulator.js",
    "content": "// Fake exchanges: used to test purposes to develop Gekko (works without internet).\n\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst TREND_DURATION = 1000;\n\nconst Trader = function() {\n  this.name = 'Exchange Simulator';\n  this.at = moment().subtract(30, 'minutes');\n\n\n  // fake data\n  this.price = 100;\n  this.trend = 'up';\n  this.tid = 0;\n}\n\nTrader.prototype.getTrades = function(since, cb) {\n  const amount = moment().diff(this.at, 'seconds');\n\n  const trades = _.range(amount).map(() => {\n\n    this.tid++;\n\n    if(this.tid % TREND_DURATION === 0) {\n      if(this.trend === 'up')\n        this.trend = 'down';\n      else\n        this.trend = 'up';\n    }\n\n    if(this.trend === 'up')\n      this.price += Math.random();\n    else\n      this.price -= Math.random();\n\n    return {\n      date: this.at.add(1, 'seconds').unix(),\n      price: this.price,\n      amount: Math.random() * 100,\n      tid: this.tid\n    }\n  });\n\n  console.log(\n    `[EXCHANGE SIMULATOR] emitted ${amount} fake trades, up until ${this.at.format('YYYY-MM-DD HH:mm:ss')}.`\n  );\n\n  cb(null, trades);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Exchange Simulator',\n    slug: 'DEBUG_exchange-simulator',\n    currencies: ['USD'],\n    assets: ['BTC', 'BTC'],\n    maxTradesAge: 60,\n    maxHistoryFetch: null,\n    markets: [\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 5, unit: 'currency' } },\n    ],\n    requires: ['key', 'secret', 'username'],\n    fetchTimespan: 60,\n    tid: 'tid',\n    tradable: false\n  };\n}\n\nmodule.exports = Trader;\n\n"
  },
  {
    "path": "exchange/wrappers/binance-markets.json",
    "content": "{\n  \"assets\": [\n    \"NULS\",\n    \"BNB\",\n    \"NEO\",\n    \"LINK\",\n    \"SALT\",\n    \"IOTA\",\n    \"ETC\",\n    \"AST\",\n    \"KNC\",\n    \"WTC\",\n    \"SNGLS\",\n    \"EOS\",\n    \"SNT\",\n    \"MCO\",\n    \"BTC\",\n    \"OAX\",\n    \"OMG\",\n    \"GAS\",\n    \"BQX\",\n    \"QTUM\",\n    \"BNT\",\n    \"DNT\",\n    \"SNM\",\n    \"STRAT\",\n    \"ZRX\",\n    \"FUN\",\n    \"LTC\",\n    \"ETH\",\n    \"XVG\",\n    \"ADA\",\n    \"ADX\",\n    \"AE\",\n    \"AGI\",\n    \"AION\",\n    \"AMB\",\n    \"APPC\",\n    \"ARDR\",\n    \"ARK\",\n    \"ARN\",\n    \"BAT\",\n    \"BCD\",\n    \"BCHABC\",\n    \"BCHSV\",\n    \"BCPT\",\n    \"BLZ\",\n    \"BRD\",\n    \"BTG\",\n    \"BTS\",\n    \"CDT\",\n    \"CLOAK\",\n    \"CMT\",\n    \"CND\",\n    \"CVC\",\n    \"DASH\",\n    \"DATA\",\n    \"DCR\",\n    \"DENT\",\n    \"DGD\",\n    \"DLT\",\n    \"DOCK\",\n    \"EDO\",\n    \"ELF\",\n    \"ENG\",\n    \"ENJ\",\n    \"EVX\",\n    \"FUEL\",\n    \"GNT\",\n    \"GO\",\n    \"GRS\",\n    \"GTO\",\n    \"GVT\",\n    \"GXS\",\n    \"HC\",\n    \"HOT\",\n    \"ICX\",\n    \"INS\",\n    \"IOST\",\n    \"IOTX\",\n    \"KEY\",\n    \"KMD\",\n    \"LEND\",\n    \"LOOM\",\n    \"LRC\",\n    \"LSK\",\n    \"LUN\",\n    \"MANA\",\n    \"MDA\",\n    \"MFT\",\n    \"MITH\",\n    \"MOD\",\n    \"MTH\",\n    \"MTL\",\n    \"NANO\",\n    \"NAS\",\n    \"NAV\",\n    \"NCASH\",\n    \"NEBL\",\n    \"NPXS\",\n    \"NXS\",\n    \"ONT\",\n    \"OST\",\n    \"PAX\",\n    \"PHX\",\n    \"PIVX\",\n    \"POA\",\n    \"POE\",\n    \"POLY\",\n    \"POWR\",\n    \"PPT\",\n    \"QKC\",\n    \"QLC\",\n    \"QSP\",\n    \"RCN\",\n    \"RDN\",\n    \"REN\",\n    \"REP\",\n    \"REQ\",\n    \"RLC\",\n    \"RVN\",\n    \"SC\",\n    \"SKY\",\n    \"STEEM\",\n    \"STORJ\",\n    \"STORM\",\n    \"SUB\",\n    \"SYS\",\n    \"THETA\",\n    \"TNB\",\n    \"TNT\",\n    \"TRX\",\n    \"TUSD\",\n    \"USDC\",\n    \"VET\",\n    \"VIA\",\n    \"VIB\",\n    \"VIBE\",\n    \"WABI\",\n    \"WAN\",\n    \"WAVES\",\n    \"WINGS\",\n    \"WPR\",\n    \"XEM\",\n    \"XLM\",\n    \"XMR\",\n    \"XRP\",\n    \"XZC\",\n    \"YOYO\",\n    \"ZEC\",\n    \"ZEN\",\n    \"ZIL\"\n  ],\n  \"currencies\": [\n    \"BNB\",\n    \"BTC\",\n    \"ETH\",\n    \"USDT\",\n    \"TUSD\",\n    \"PAX\",\n    \"USDC\",\n    \"XRP\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NULS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NULS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NULS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LINK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SALT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"KNC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SNGLS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MCO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.000001,\n        \"price\": 0.01,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"OAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"OMG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GAS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BQX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QTUM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SNM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SNM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SNGLS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BQX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"KNC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"STRAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QTUM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"FUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LINK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STRAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"IOTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"OMG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MCO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SALT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ADX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ADX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ADX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"AE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"AION\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AION\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AION\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"AMB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AMB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AMB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"APPC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"APPC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"APPC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ARDR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ARDR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ARDR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ARK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ARK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ARN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ARN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BCD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCHABC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"BCHABC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCHSV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"BCHSV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"BCPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BCPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"BLZ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BLZ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BLZ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"BNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"BNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"BRD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BRD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BRD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.000001,\n        \"price\": 0.01,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.000001,\n        \"price\": 0.01,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BTG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BTG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"BTS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BTS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BTS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CDT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CDT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CLOAK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CLOAK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"CMT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CMT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CMT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"CVC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CVC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CVC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DASH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DASH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DATA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DATA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"DCR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DCR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DENT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DENT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DGD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DGD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"DLT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DLT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DLT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DOCK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DOCK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"EDO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EDO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ELF\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ELF\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ENG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ENG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ENJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ENJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ENJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"EVX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EVX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"FUEL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"FUEL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"FUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"GO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GRS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GRS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"GTO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GTO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GTO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GVT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GVT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"HC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"HC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"HOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"HOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ICX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ICX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ICX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"ICX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"INS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"INS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"IOST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"IOTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"IOTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"IOTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"KEY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"KEY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"KMD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"KMD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LEND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LEND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"LOOM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LOOM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LOOM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LRC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LRC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"LSK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LSK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LSK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MANA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MANA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"MCO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MDA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MDA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"MFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"MITH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MITH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MOD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MOD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MTH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MTH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MTL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MTL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NANO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NANO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NANO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NAS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NAS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NAS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NAV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NAV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NAV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NCASH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NCASH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NCASH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NEBL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NEBL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NEBL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NPXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NPXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"NULS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"NXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NXS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"OAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ONT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ONT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ONT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"ONT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"OST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"OST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"OST\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"PAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"PHX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"PHX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"PHX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"PIVX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"PIVX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"PIVX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"POE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"POLY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POLY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"POWR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POWR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"POWR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"PPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"PPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QKC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QKC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"QLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"QSP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QSP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QSP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"QTUM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"QTUM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"REN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"REN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"REQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"REQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"RVN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RVN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"SC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"SKY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SKY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SKY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"STEEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STEEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"STEEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STORJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"STORJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"STORM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STORM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"STORM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SUB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SUB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"SYS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SYS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SYS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"THETA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"THETA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"THETA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"XRP\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"TUSD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TUSD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TUSD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"TUSD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"USDC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"VIA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VIA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VIA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VIB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VIBE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VIBE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VIB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"WABI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WABI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WABI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"WAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"WAVES\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WAVES\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-7,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WAVES\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WINGS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WINGS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-7,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WPR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WPR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"WTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"XEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XEM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XMR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XMR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"PAX\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"TUSD\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDC\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.1,\n        \"price\": 0.00001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"XZC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XZC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XZC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.000001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"XRP\",\n        \"XZC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"YOYO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"YOYO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"YOYO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ZEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.000001,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 0.00001,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"BNB\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 0.000001,\n        \"order\": 1\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.001\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0.01\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"BNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.0001,\n        \"order\": 10\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.01,\n        \"order\": 10\n      }\n    }\n  ]\n}"
  },
  {
    "path": "exchange/wrappers/binance.js",
    "content": "const moment = require('moment');\nconst _ = require('lodash');\n\nconst Errors = require('../exchangeErrors');\nconst marketData = require('./binance-markets.json');\nconst exchangeUtils = require('../exchangeUtils');\nconst retry = exchangeUtils.retry;\nconst scientificToDecimal = exchangeUtils.scientificToDecimal;\n\nconst Binance = require('binance');\n\nconst Trader = function(config) {\n  _.bindAll(this, [\n    'roundAmount',\n    'roundPrice',\n    'isValidPrice',\n    'isValidLot'\n  ]);\n\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency.toUpperCase();\n    this.asset = config.asset.toUpperCase();\n  }\n\n  let recvWindow = 6000;\n  if(config.optimizedConnection) {\n    // there is a bug in binance's API\n    // where some requests randomly take\n    // over a second, this tells binance\n    // to bail out after 500ms.\n    //\n    // As discussed in binance API\n    // telegram. TODO add link.\n    recvWindow = 500;\n  }\n\n  this.pair = this.asset + this.currency;\n  this.name = 'binance';\n\n  this.market = _.find(Trader.getCapabilities().markets, (market) => {\n    return market.pair[0] === this.currency && market.pair[1] === this.asset\n  });\n\n  this.binance = new Binance.BinanceRest({\n    key: this.key,\n    secret: this.secret,\n    timeout: 15000,\n    recvWindow,\n    disableBeautification: false,\n    handleDrift: true,\n  });\n\n  if(config.key && config.secret) {\n    // Note non standard func:\n    //\n    // On binance we might pay fees in BNB\n    // if we do we CANNOT calculate feePercent\n    // since we don't track BNB price (when we\n    // are not trading on a BNB market).\n    //\n    // Though we can deduce feePercent based\n    // on user fee tracked through `this.getFee`.\n    // Set default here, overwrite in getFee.\n    this.fee = 0.001;\n    // Set the proper fee asap.\n    this.getFee(_.noop);\n\n    this.oldOrder = false;\n  }\n};\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  'Error -1021',\n  'Response code 429',\n  'Response code 5',\n  'Response code 403',\n  'ETIMEDOUT',\n  'EHOSTUNREACH',\n  // getaddrinfo EAI_AGAIN api.binance.com api.binance.com:443\n  'EAI_AGAIN',\n  'ENETUNREACH'\n];\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.handleResponse = function(funcName, callback) {\n  return (error, body) => {\n    if (body && body.code) {\n      error = new Error(`Error ${body.code}: ${body.msg}`);\n    }\n\n    if(error) {\n      if(_.isString(error)) {\n        error = new Error(error);\n      }\n\n      if(includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n      }\n\n      if(funcName === 'cancelOrder' && error.message.includes('UNKNOWN_ORDER')) {\n        console.log(new Date, 'cancelOrder', 'UNKNOWN_ORDER');\n        // order got filled in full before it could be\n        // cancelled, meaning it was NOT cancelled.\n        return callback(false, {filled: true});\n      }\n\n      if(funcName === 'checkOrder' && error.message.includes('Order does not exist.')) {\n        console.log(new Date, 'Binance doesnt know this order, retrying up to 10 times..');\n        error.retry = 10;\n      }\n\n      if(funcName === 'addOrder' && error.message.includes('Account has insufficient balance')) {\n        console.log(new Date, 'insufficientFunds');\n        error.type = 'insufficientFunds';\n      }\n\n      return callback(error);\n    }\n\n    return callback(undefined, body);\n  }\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const processResults = (err, data) => {\n    if (err) return callback(err);\n\n    var parsedTrades = [];\n    _.each(\n      data,\n      function(trade) {\n        parsedTrades.push({\n          tid: trade.aggTradeId,\n          date: moment(trade.timestamp).unix(),\n          price: parseFloat(trade.price),\n          amount: parseFloat(trade.quantity),\n        });\n      },\n      this\n    );\n\n    if (descending) callback(null, parsedTrades.reverse());\n    else callback(undefined, parsedTrades);\n  };\n\n  var reqData = {\n    symbol: this.pair,\n  };\n\n  if (since) {\n    var endTs = moment(since)\n      .add(1, 'h')\n      .valueOf();\n    var nowTs = moment().valueOf();\n\n    reqData.startTime = moment(since).valueOf();\n    reqData.endTime = endTs > nowTs ? nowTs : endTs;\n  }\n\n  const fetch = cb => this.binance.aggTrades(reqData, this.handleResponse('getTrades', cb));\n  retry(undefined, fetch, processResults);\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const setBalance = (err, data) => {\n    if (err) return callback(err);\n\n    const findAsset = item => item.asset === this.asset;\n    const assetAmount = parseFloat(_.find(data.balances, findAsset).free);\n\n    const findCurrency = item => item.asset === this.currency;\n    const currencyAmount = parseFloat(_.find(data.balances, findCurrency).free);\n\n    if (!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      assetAmount = 0;\n    }\n\n    if (!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      currencyAmount = 0;\n    }\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount },\n    ];\n\n    return callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.binance.account({}, this.handleResponse('getPortfolio', cb));\n  retry(undefined, fetch, setBalance);\n};\n\nTrader.prototype.getFee = function(callback) {\n\n  // binance does NOT tell us whether the user is using BNB to pay\n  // for fees, which means a discount (effectively lower fees)\n  const handle = (err, data) => {\n    if(err)  {\n      return callback(err);\n    }\n    const basepoints = data.makerCommission;\n\n    /** Binance raw response\n    { makerCommission: 10,\n      takerCommission: 10,\n      buyerCommission: 0,\n      sellerCommission: 0,\n      canTrade: true,\n      canWithdraw: true,\n      canDeposit: true,\n      So to get decimal representation of fee we actually need to divide by 10000\n    */\n    // note non standard func, see constructor\n    this.fee = basepoints / 10000;\n\n    callback(undefined, this.fee);\n  }\n\n  const fetch = cb => this.binance.account({}, this.handleResponse('getFee', cb));\n  retry(undefined, fetch, handle);\n};\n\nTrader.prototype.getTicker = function(callback) {\n  const setTicker = (err, data) => {\n    if (err)\n      return callback(err);\n\n    var result = _.find(data, ticker => ticker.symbol === this.pair);\n\n    if(!result)\n      return callback(new Error(`Market ${this.pair} not found on Binance`));\n\n    var ticker = {\n      ask: parseFloat(result.askPrice),\n      bid: parseFloat(result.bidPrice),\n    };\n\n    callback(undefined, ticker);\n  };\n\n  const handler = cb => this.binance._makeRequest({}, this.handleResponse('getTicker', cb), 'api/v1/ticker/allBookTickers');\n  retry(undefined, handler, setTicker);\n};\n\n// Effectively counts the number of decimal places, so 0.001 or 0.234 results in 3\nTrader.prototype.getPrecision = function(tickSize) {\n  if (!isFinite(tickSize)) return 0;\n  var e = 1, p = 0;\n  while (Math.round(tickSize * e) / e !== tickSize) { e *= 10; p++; }\n  return p;\n};\n\nTrader.prototype.round = function(amount, tickSize) {\n  var precision = 100000000;\n  var t = this.getPrecision(tickSize);\n\n  if(Number.isInteger(t))\n    precision = Math.pow(10, t);\n\n  amount *= precision;\n  amount = Math.floor(amount);\n  amount /= precision;\n\n  // https://gist.github.com/jiggzson/b5f489af9ad931e3d186\n  amount = scientificToDecimal(amount);\n\n  return amount;\n};\n\nTrader.prototype.roundAmount = function(amount) {\n  return this.round(amount, this.market.minimalOrder.amount);\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return this.round(price, this.market.minimalOrder.price);\n}\n\nTrader.prototype.isValidPrice = function(price) {\n  return price >= this.market.minimalOrder.price;\n}\n\nTrader.prototype.isValidLot = function(price, amount) {\n  return amount * price >= this.market.minimalOrder.order;\n}\n\nTrader.prototype.outbidPrice = function(price, isUp) {\n  let newPrice;\n\n  if(isUp) {\n    newPrice = price + this.market.minimalOrder.price;\n  } else {\n    newPrice = price - this.market.minimalOrder.price;\n  }\n\n  return this.roundPrice(newPrice);\n}\n\nTrader.prototype.addOrder = function(tradeType, amount, price, callback) {\n  const setOrder = (err, data) => {\n    if (err) return callback(err);\n\n    const txid = data.orderId;\n\n    callback(undefined, txid);\n  };\n\n  const reqData = {\n    symbol: this.pair,\n    side: tradeType.toUpperCase(),\n    type: 'LIMIT',\n    timeInForce: 'GTC',\n    quantity: amount,\n    price: price,\n    timestamp: new Date().getTime()\n  };\n\n  const handler = cb => this.binance.newOrder(reqData, this.handleResponse('addOrder', cb));\n  retry(undefined, handler, setOrder);\n};\n\nTrader.prototype.getOpenOrders = function(callback) {\n\n  const get = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    callback(null, data.map(o => o.orderId));\n  }\n\n  const reqData = {\n    symbol: this.pair\n  }\n\n  const handler = cb => this.binance.openOrders(reqData, this.handleResponse('getOpenOrders', cb));\n  retry(undefined, handler, get);\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n  const get = (err, data) => {\n    if (err) return callback(err);\n\n    let price = 0;\n    let amount = 0;\n    let date = moment(0);\n\n    const fees = {};\n\n    if(!data.length) {\n      return callback(new Error('Binance did not return any trades'));\n    }\n\n    const trades = _.filter(data, t => {\n      // note: the API returns a string after creating\n      return t.orderId == order;\n    });\n\n    if(!trades.length) {\n      console.log('cannot find trades!', { order, list: data.map(t => t.orderId).reverse() });\n\n      const reqData = {\n        symbol: this.pair,\n        orderId: order,\n      };\n\n      this.binance.queryOrder(reqData, (err, resp) => {\n        console.log('couldnt find any trade for order, here is order:', {err, resp});\n\n         callback(new Error('Trades not found'));\n      });\n\n      return;\n    }\n\n    _.each(trades, trade => {\n      date = moment(trade.time);\n      price = ((price * amount) + (+trade.price * trade.qty)) / (+trade.qty + amount);\n      amount += +trade.qty;\n\n      if(fees[trade.commissionAsset])\n        fees[trade.commissionAsset] += (+trade.commission);\n      else\n        fees[trade.commissionAsset] = (+trade.commission);\n    });\n\n    let feePercent;\n    if(_.keys(fees).length === 1) {\n      if(fees.BNB && this.asset !== 'BNB' && this.currency !== 'BNB') {\n        // we paid fees in BNB, right now that means the fee is always 75%\n        // of base fee. We cannot calculate since we do not have the BNB rate.\n        feePercent = this.fee * 0.75;\n      } else {\n        if(fees[this.asset]) {\n          feePercent = fees[this.asset] / amount * 100;\n        } else if(fees.currency) {\n          feePercent = fees[this.currency] / price / amount * 100;\n        } else {\n          // use user fee of 10 basepoints\n          feePercent = this.fee;\n        }\n      }\n    } else {\n      // we paid fees in multiple currencies?\n      // assume user fee\n      feePercent = this.fee;\n    }\n\n    callback(undefined, { price, amount, date, fees, feePercent });\n  }\n\n  const reqData = {\n    symbol: this.pair,\n    // if this order was not part of the last 500 trades we won't find it..\n    limit: 1000,\n  };\n\n  const handler = cb => this.binance.myTrades(reqData, this.handleResponse('getOrder', cb));\n  retry(undefined, handler, get);\n};\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.addOrder('buy', amount, price, callback);\n};\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.addOrder('sell', amount, price, callback);\n};\n\nTrader.prototype.checkOrder = function(order, callback) {\n\n  const check = (err, data) => {\n    if (err) {\n      return callback(err);\n    }\n\n    if(data.filled === true) {\n      // binance responsed with order not found\n      return callback(undefined, { executed: true, open: false });\n    }\n\n    const status = data.status;\n\n    if(\n      status === 'CANCELED' ||\n      status === 'REJECTED' ||\n      // for good measure: GB does not\n      // submit orders that can expire yet\n      status === 'EXPIRED'\n    ) {\n      return callback(undefined, { executed: false, open: false });\n    } else if(\n      status === 'NEW' ||\n      status === 'PARTIALLY_FILLED'\n    ) {\n      return callback(undefined, { executed: false, open: true, filledAmount: +data.executedQty });\n    } else if(status === 'FILLED') {\n      return callback(undefined, { executed: true, open: false })\n    }\n\n    console.log('what status?', status);\n    throw status;\n  };\n\n  const reqData = {\n    symbol: this.pair,\n    orderId: order,\n  };\n\n  const fetcher = cb => this.binance.queryOrder(reqData, this.handleResponse('checkOrder', cb));\n  retry(undefined, fetcher, check);\n};\n\nTrader.prototype.cancelOrder = function(order, callback) {\n\n  const cancel = (err, data) => {\n\n    this.oldOrder = order;\n\n    if(err) {\n      return callback(err);\n    }\n\n    if(data && data.filled) {\n      return callback(undefined, true);\n    }\n\n    return callback(undefined, false);\n  };\n\n  let reqData = {\n    symbol: this.pair,\n    orderId: order,\n  };\n\n  const fetcher = cb => this.binance.cancelOrder(reqData, this.handleResponse('cancelOrder', cb));\n  retry(undefined, fetcher, cancel);\n};\n\nTrader.getCapabilities = function() {\n  return {\n    name: 'Binance',\n    slug: 'binance',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    tid: 'tid',\n    tradable: true,\n    gekkoBroker: 0.6,\n    limitedCancelConfirmation: true\n  };\n};\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/bitcoin-co-id.js.old",
    "content": "var Bitcoincoid = require('bitcoin-co-id-update'),\r\n   _ = require('lodash'),\r\n   moment = require('moment'),\r\n   log = require('../core/log');\r\n\r\nvar Trader = function(config) {\r\n  _.bindAll(this);\r\n  if(_.isObject(config)) {\r\n    this.key = config.key;\r\n    this.secret = config.secret;\r\n    this.clientID = config.username;\r\n    this.currency = config.currency.toLowerCase();\r\n    this.asset = config.asset.toLowerCase();\r\n    this.pair = this.asset + '_' + this.currency;\r\n  }\r\n  this.name = 'Bitcoin-co-id';\r\n  this.bitcoincoid = new Bitcoincoid(this.key, this.secret);\r\n}\r\n\r\nTrader.prototype.roundAmount = function(amount) {\r\n  var priceDivider = 100000000; // one hundred million;\r\n  amount *= priceDivider;\r\n  amount = Math.floor(amount);\r\n  amount /= priceDivider;\r\n  return amount;\r\n};\r\n\r\n// if the exchange errors we try the same call again after\r\n// waiting 10 seconds\r\nTrader.prototype.retry = function(method, args) {\r\n  var wait = +moment.duration(10, 'seconds');\r\n  log.debug(this.name, 'returned an error, retrying..');\r\n\r\n  var self = this;\r\n\r\n  // make sure the callback (and any other fn)\r\n  // is bound to Trader\r\n  _.each(args, function(arg, i) {\r\n    if(_.isFunction(arg))\r\n      args[i] = _.bind(arg, self);\r\n  });\r\n\r\n  // run the failed method again with the same\r\n  // arguments after wait\r\n  setTimeout(\r\n    function() { method.apply(self, args); },\r\n    wait\r\n  );\r\n}\r\n\r\nTrader.prototype.getTicker = function(callback) {\r\n  var args = _.toArray(arguments),\r\n  set = function(err, data) {\r\n    if(err)\r\n      return this.retry(this.getTicker, args);\r\n    var ticker = {\r\n      ask: this.roundAmount(data.ticker.buy),\r\n      bid: this.roundAmount(data.ticker.sell),\r\n    };\r\n    callback(err, ticker);\r\n  }.bind(this);\r\n  this.bitcoincoid.getTicker(this.pair, set);\r\n}\r\n\r\nTrader.prototype.getPortfolio = function(callback) {\r\n  var functionName = 'Trader.getPortfolio()',\r\n  args = _.toArray(arguments);\r\n  set = function(err, data) {\r\n    if(err)\r\n      return this.retry(this.getPortfolio, args);\r\n    var assetAmount = this.roundAmount( data.return.balance[this.asset] ),\r\n    currencyAmount = this.roundAmount( data.return.balance[this.currency] ),\r\n    assetHold = this.roundAmount( data.return.balance_hold[this.asset] ),\r\n    currencyHold = this.roundAmount( data.return.balance_hold[this.currency] );\r\n\r\n    if(\r\n      !_.isNumber(assetAmount) || _.isNaN(assetAmount) ||\r\n      !_.isNumber(currencyAmount) || _.isNaN(currencyAmount)\r\n    ) {\r\n      return log.error('account balance error: Gekko is unable to trade with ',this.currency.toUpperCase(),':',currencyAmount,' or ',this.asset.toUpperCase(),':',assetAmount);\r\n    }\r\n    var portfolio = [\r\n      { name: this.currency.toUpperCase(), amount: currencyAmount - currencyHold},\r\n      { name: this.asset.toUpperCase(), amount: assetAmount - assetHold }\r\n    ];\r\n    callback(err, portfolio);\r\n  }.bind(this);\r\n  this.bitcoincoid.getAccountBalances(set);\r\n}\r\n\r\nTrader.prototype.getTrades = function(since, callback, descending) {\r\n  var args = _.toArray(arguments);\r\n\r\n  if(since)\r\n    since = 150; // ???\r\n\r\n  var process = function(err, data) {\r\n    if(err)\r\n      return this.retry(this.getTrades, args);\r\n\r\n    var trades = _.map(data, function(trade) {\r\n      return {\r\n        price: +trade.price,\r\n        amount: +trade.amount,\r\n        tid: +trade.tid,\r\n        date: trade.date\r\n      };\r\n    });\r\n    callback(null, data.reverse());\r\n  }.bind(this);\r\n\r\n  this.bitcoincoid.getTrades(this.pair, process);\r\n}\r\n\r\n// bitcoin.co.id: Maker 0% - Taker 0.3%\r\n// Note: trading fee: 0.3% for IDR pairs and 0% for BTC pairs\r\nTrader.prototype.getFee = function(callback) {\r\n  var fee = 0;\r\n  if (this.currency.toUpperCase() === 'IDR')\r\n    {\r\n      fee = 0.003;\r\n    }\r\n    else if (this.currency.toUpperCase() === 'BTC')\r\n    {\r\n      fee = 0.000;\r\n    }\r\n\r\n  callback(false, fee);\r\n};\r\n\r\nTrader.prototype.buy = function(amount, price, callback) {\r\n  this.type = 'buy';\r\n\r\n  // decrease purchase amount by 1% to avoid trying to buy more than balance\r\n  amount -= amount / 100;\r\n  amount = this.roundAmount(amount);\r\n\r\n  // decrease purchase price by 1% less than asking price\r\n  // price -= price / 100;\r\n  amount *= price;\r\n\r\n  var set = function(err, data) {\r\n    if(!err && _.isEmpty(data))\r\n      err = 'no data';\r\n    else if(!err && !_.isEmpty(data.errorMessage))\r\n      err = data.errorMessage;\r\n    if(err)\r\n      return log.error('unable to buy', err);\r\n  callback(null, data.return.order_id);\r\n  }.bind(this);\r\n  this.bitcoincoid.createOrders(\r\n    this.pair + '',\r\n    this.type,\r\n    price,\r\n    amount,\r\n    set\r\n  );\r\n}\r\n\r\nTrader.prototype.sell = function(amount, price, callback) {\r\n  this.type = 'sell';\r\n\r\n  // increase selling price by 1% more than bidding price\r\n  // price += price / 100;\r\n\r\n  amount = this.roundAmount(amount);\r\n  var set = function(err, data) {\r\n    if(!err && _.isEmpty(data))\r\n      err = 'no data';\r\n    else if(!err && !_.isEmpty(data.errorMessage))\r\n      err = data.errorMessage;\r\n    if(err)\r\n      return log.error('unable to sell', err);\r\n    callback(null, data.return.order_id);\r\n  }.bind(this);\r\n  this.bitcoincoid.createOrders(\r\n    this.pair + '',\r\n    this.type,\r\n    price,\r\n    amount,\r\n    set\r\n  );\r\n}\r\n\r\nTrader.prototype.checkOrder = function(order, callback) {\r\n  var args = _.toArray(arguments);\r\n  if (order === null) {\r\n    return callback('no order_id', false);\r\n  }\r\n  var check = function(err, data) {\r\n    if(err){\r\n      return this.retry(this.checkOrder, arguments);\r\n    }\r\n    var status = data.return.order.status;\r\n      if (status === 'filled') {\r\n        return callback(err, true);\r\n      } else if (status === 'open') {\r\n        return callback(err, false);\r\n      }\r\n    callback(err, false);\r\n    }.bind(this);\r\n\r\n  this.bitcoincoid.getOrderDetails(this.pair, order, check);\r\n}\r\n\r\nTrader.prototype.getOrder = function(order, callback) {\r\n  var args = _.toArray(arguments);\r\n  if (order === null) {\r\n    return callback('no order_id', false);\r\n  }\r\n  var get = function(data, err) {\r\n    if(err)\r\n      return callback(err);\r\n\r\n    var price = 0;\r\n    var amount = 0;\r\n    var date = moment(0);\r\n\r\n    if(!data.success)\r\n      return callback(null, {price, amount, date});\r\n\r\n    var result = data.return.order;\r\n    var orderAmount = result.order+'_'+this.asset;\r\n    price = result.Price;\r\n    amount = result.orderAmount;\r\n\r\n    if(result.status === 'open') {\r\n      date = moment(result.submit_time);\r\n    } else {\r\n      date = moment(result.finish_time);\r\n    }\r\n    callback(err, {price, amount, date});\r\n  }.bind(this);\r\n\r\n   this.bitcoincoid.getOrderDetails(this.pair, order, get);\r\n}\r\n\r\nTrader.prototype.cancelOrder = function(order, callback) {\r\n  var args = _.toArray(arguments);\r\n  var cancel = function(err, data) {\r\n    if(err) {\r\n      return log.error('unable to cancel order: ', order, '(', err, '), retrying...');\r\n      this.retry(this.cancelOrder, args);\r\n    }\r\n    callback();\r\n  };\r\n  this.bitcoincoid.cancelOrder(this.pair, order, this.type, cancel);\r\n}\r\n\r\nTrader.getCapabilities = function () {\r\n  return {\r\n    name: 'Bitcoin.co.id',\r\n    slug: 'bitcoin-co-id',\r\n    currencies: ['IDR', 'BTC'],\r\n    assets: [\r\n      \"BTC\", \"BCH\", \"BTG\", \"ETH\", \"ETC\", \"LTC\", \"NXT\", \"WAVES\", \"STR\", \"XRP\", \"XZC\", \"BTS\", \"DRK\", \"DOGE\", \"NEM\", \"XZR\", \"DASH\", \"XLM\", \"XEM\"\r\n    ],\r\n    markets: [\r\n\r\n      // IDR <-> XXXX\r\n\r\n      { pair: ['IDR', 'BTC'], minimalOrder: { amount: 0.0001, unit: 'asset' } },\r\n      { pair: ['IDR', 'BCH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\r\n      { pair: ['IDR', 'BTG'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['IDR', 'ETH'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['IDR', 'ETC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\r\n      { pair: ['IDR', 'LTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['IDR', 'NXT'], minimalOrder: { amount: 5, unit: 'asset' } },\r\n      { pair: ['IDR', 'WAVES'], minimalOrder: { amount: 0.1, unit: 'asset' } },\r\n      { pair: ['IDR', 'STR'], minimalOrder: { amount: 20, unit: 'asset' } }, // Listed as XLM\r\n      { pair: ['IDR', 'XRP'], minimalOrder: { amount: 10, unit: 'asset' } },\r\n      { pair: ['IDR', 'XZC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\r\n\r\n\r\n      // BTC <-> XXXX\r\n\r\n      { pair: ['BTC', 'BTS'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['BTC', 'DRK'], minimalOrder: { amount: 0.01, unit: 'asset' } }, // Listed as DASH\r\n      { pair: ['BTC', 'DOGE'], minimalOrder: { amount: 1, unit: 'asset' } },\r\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\r\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['BTC', 'NXT'], minimalOrder: { amount: 0.01, unit: 'asset' } },\r\n      { pair: ['BTC', 'STR'], minimalOrder: { amount: 0.01, unit: 'asset' } }, // Listed as XLM\r\n      { pair: ['BTC', 'NEM'], minimalOrder: { amount: 1, unit: 'asset' } }, // Listed as XEM\r\n      { pair: ['BTC', 'XRP'], minimalOrder: { amount: 0.01, unit: 'asset' } }\r\n\r\n    ],\r\n    requires: ['key', 'secret'],\r\n    tid: 'tid',\r\n    providesHistory: true,\r\n    providesFullHistory: false,\r\n    tradable: true\r\n  };\r\n}\r\n\r\nmodule.exports = Trader;\r\n"
  },
  {
    "path": "exchange/wrappers/bitfinex-markets.json",
    "content": "{\n  \"assets\": [\n    \"BTC\",\n    \"LTC\",\n    \"ETH\",\n    \"ETC\",\n    \"RRT\",\n    \"ZEC\",\n    \"XMR\",\n    \"DSH\",\n    \"XRP\",\n    \"IOT\",\n    \"EOS\",\n    \"SAN\",\n    \"OMG\",\n    \"NEO\",\n    \"ETP\",\n    \"QTM\",\n    \"AVT\",\n    \"EDO\",\n    \"BTG\",\n    \"DAT\",\n    \"QSH\",\n    \"YYW\",\n    \"GNT\",\n    \"SNT\",\n    \"BAT\",\n    \"MNA\",\n    \"FUN\",\n    \"ZRX\",\n    \"TNB\",\n    \"SPK\",\n    \"TRX\",\n    \"RCN\",\n    \"RLC\",\n    \"AID\",\n    \"SNG\",\n    \"REP\",\n    \"ELF\",\n    \"IOS\",\n    \"AIO\",\n    \"REQ\",\n    \"RDN\",\n    \"LRC\",\n    \"WAX\",\n    \"DAI\",\n    \"CFI\",\n    \"AGI\",\n    \"BFT\",\n    \"MTN\",\n    \"ODE\",\n    \"ANT\",\n    \"DTH\",\n    \"MIT\",\n    \"STJ\",\n    \"XLM\",\n    \"XVG\",\n    \"BCI\",\n    \"MKR\",\n    \"KNC\",\n    \"POA\",\n    \"LYM\",\n    \"UTK\",\n    \"VEE\",\n    \"DAD\",\n    \"ORS\",\n    \"AUC\",\n    \"POY\",\n    \"FSN\",\n    \"CBT\",\n    \"ZCN\",\n    \"SEN\",\n    \"NCA\",\n    \"CND\",\n    \"CTX\",\n    \"PAI\",\n    \"SEE\",\n    \"ESS\",\n    \"ATM\",\n    \"HOT\",\n    \"DTA\",\n    \"IQX\",\n    \"WPR\",\n    \"ZIL\",\n    \"BNT\",\n    \"ABS\",\n    \"XRA\",\n    \"MAN\",\n    \"BBN\",\n    \"NIO\",\n    \"DGX\",\n    \"VET\",\n    \"UTN\",\n    \"TKN\",\n    \"GOT\",\n    \"XTZ\",\n    \"CNN\",\n    \"BOX\",\n    \"MGO\",\n    \"RTE\",\n    \"YGG\",\n    \"MLN\",\n    \"WTC\",\n    \"CSX\",\n    \"OMN\",\n    \"INT\",\n    \"DRN\",\n    \"PNK\",\n    \"DGB\",\n    \"BSV\",\n    \"BAB\"\n  ],\n  \"currencies\": [\n    \"USD\",\n    \"BTC\",\n    \"EUR\",\n    \"JPY\",\n    \"ETH\",\n    \"GBP\",\n    \"EOS\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"USD\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.06\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.06\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"RRT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"294.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RRT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"294.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XMR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XMR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DSH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.08\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DSH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.08\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"38.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"38.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"OMG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"OMG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"OMG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"8.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"8.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ETP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"8.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"QTM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QTM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QTM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"AVT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AVT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AVT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"EDO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"16.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"EDO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"16.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EDO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"16.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BTG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.6\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BTG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.6\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"352.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"352.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"352.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"QSH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"68.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"QSH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"68.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QSH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"68.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"YYW\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"510.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"YYW\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"510.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"YYW\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"510.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"82.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"82.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"82.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"334.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"334.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"334.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BAT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MNA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"164.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MNA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"164.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MNA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"164.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"FUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1196.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"FUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1196.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"FUN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1196.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"TNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1418.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1418.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TNB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1418.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SPK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"320.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SPK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"320.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SPK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"320.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"548.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"548.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"548.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"518.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"518.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"518.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"AID\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"236.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AID\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"236.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AID\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"236.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SNG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"562.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SNG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"562.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SNG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"562.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"REP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ELF\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"46.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ELF\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"46.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ELF\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"46.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.06\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.06\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.06\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"NEO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.8\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"24.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"IOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1170.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1170.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"IOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1170.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"AIO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"34.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AIO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"34.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AIO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"34.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"REQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"302.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"REQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"302.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"REQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"302.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RDN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"LRC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"144.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LRC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"144.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LRC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"144.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"WAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"166.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"166.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WAX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"166.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DAI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DAI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DAI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CFI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"566.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CFI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"566.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CFI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"566.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"268.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"268.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AGI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"268.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"272.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"272.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BFT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"272.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MTN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MTN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MTN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ODE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"86.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ODE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"86.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ODE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"86.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ANT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"22.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ANT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"22.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ANT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"22.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DTH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"958.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DTH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"958.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DTH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"958.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MIT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MIT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MIT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"STJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"STJ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"44.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XLM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XVG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1024.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BCI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"16.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"16.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MKR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.04\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"MKR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.04\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MKR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.04\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"KNC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"KNC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"KNC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"36.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"184.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"184.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"POA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"184.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"LYM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"874.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LYM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"874.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"LYM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"874.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"UTK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"426.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"UTK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"426.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"UTK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"426.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"VEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1430.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1430.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1430.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DAD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"140.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DAD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"140.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DAD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"140.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ORS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"476.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ORS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"476.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ORS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"476.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"AUC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"304.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"AUC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"304.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"AUC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"304.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"POY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"POY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"POY\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"70.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"FSN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"14.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"FSN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"14.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"FSN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"14.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CBT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1228.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CBT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1228.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CBT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1228.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"90.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"90.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZCN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"90.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3840.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3840.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SEN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3840.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"NCA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NCA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NCA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CND\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"606.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"48.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"48.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"48.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"PAI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"82.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"PAI\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"82.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"SEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"12382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"SEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"12382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"SEE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"12382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ESS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3054.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ESS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3054.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ESS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"3054.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ATM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1842.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ATM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1842.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ATM\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1842.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"HOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1408.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"HOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1408.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"HOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1408.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"5572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"5572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DTA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"5572.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"IQX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1798.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IQX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1798.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EOS\",\n        \"IQX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1798.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"WPR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"590.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"WPR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"590.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WPR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"590.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ZIL\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"382.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BNT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"10.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ABS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1136.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ABS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1136.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XRA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"296.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XRA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"296.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MAN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"56.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BBN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1782.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BBN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1782.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"NIO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"676.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"NIO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"676.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DGX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DGX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.2\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1286.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1286.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"VET\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1286.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"UTN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2698.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"UTN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2698.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"TKN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"TKN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"32.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"GOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"GOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"20.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XTZ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"8.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XTZ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"8.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CNN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"34370.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CNN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"34370.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BOX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1252.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"BOX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1252.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"526.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"526.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"526.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MGO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"30.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MGO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"30.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"RTE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2950.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"RTE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2950.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"YGG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"11104.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"YGG\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"11104.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"MLN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MLN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"WTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"WTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"4.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"CSX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"72.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"CSX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"72.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"OMN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"OMN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"2.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"INT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"352.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"INT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"352.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DRN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"62.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DRN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"62.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"PNK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1394.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"PNK\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1394.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DGB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"566.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DGB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"566.0\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BSV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BSV\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BAB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.04\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BAB\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.04\",\n        \"unit\": \"asset\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "exchange/wrappers/bitfinex.js",
    "content": "\nconst Bitfinex = require(\"bitfinex-api-node\");\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst Errors = require('../exchangeErrors');\nconst retry = require('../exchangeUtils').retry;\n\nconst marketData = require('./bitfinex-markets.json');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n  }\n  this.name = 'Bitfinex';\n  this.balance;\n  this.price;\n  this.asset = config.asset;\n  this.currency = config.currency;\n  this.pair = this.asset + this.currency;\n  this.bitfinex = new Bitfinex.RESTv1({apiKey: this.key, apiSecret: this.secret, transform: true});\n\n  this.interval = 4000;\n}\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'ESOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  '443',\n  '504',\n  '503',\n  '502',\n  'Empty response',\n  'Nonce is too small'\n];\n\nTrader.prototype.handleResponse = function(funcName, callback) {\n  return (error, data) => {\n\n    if(!error && _.isEmpty(data)) {\n      error = new Error('Empty response');\n    }\n\n    if(error) {\n      const message = error.message;\n\n      console.log('handleResponse', funcName, message);\n\n      // in case we just cancelled our balances might not have\n      // settled yet, retry.\n      if(\n        funcName === 'submitOrder' &&\n        message.includes('not enough exchange balance')\n      ) {\n        error.retry = 20;\n        return callback(error);\n      }\n\n      // most likely problem with v1 api\n      if(\n        funcName === 'submitOrder' &&\n        message.includes('Cannot evaluate your available balance, please try again')\n      ) {\n        error.retry = 10;\n        return callback(error);\n      }\n\n      // in some situations bfx returns 404 on\n      // orders created recently\n      if(\n        funcName === 'checkOrder' &&\n        message.includes('Not Found')\n      ) {\n        error.retry = 5;\n        return callback(error);\n      }\n\n      if(includes(message, recoverableErrors)) {\n        error.notFatal = true;\n        return callback(error);\n      }\n\n      if(includes(message, 'Too Many Requests')) {\n        error.notFatal = true;\n        error.backoffDelay = 5000;\n      }\n    }\n\n    return callback(error, data);\n  }\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    // We are only interested in funds in the \"exchange\" wallet\n    data = data.filter(c => c.type === 'exchange');\n\n    const asset = _.find(data, c => c.currency.toUpperCase() === this.asset);\n    const currency = _.find(data, c => c.currency.toUpperCase() === this.currency);\n\n    let assetAmount, currencyAmount;\n\n    if(_.isObject(asset) && _.isNumber(+asset.available) && !_.isNaN(+asset.available))\n      assetAmount = +asset.available;\n    else {\n      assetAmount = 0;\n    }\n\n    if(_.isObject(currency) && _.isNumber(+currency.available) && !_.isNaN(+currency.available))\n      currencyAmount = +currency.available;\n    else {\n      currencyAmount = 0;\n    }\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount },\n    ];\n\n    callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.bitfinex.wallet_balances(this.handleResponse('getPortfolio', cb));\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  const processResponse = (err, data) => {\n    if (err)\n      return callback(err);\n\n    callback(undefined, {bid: +data.bid, ask: +data.ask});\n  };\n\n  const fetch = cb => this.bitfinex.ticker(this.pair, this.handleResponse('getTicker', cb));\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getFee = function(callback) {\n  const makerFee = 0.1;\n  // const takerFee = 0.2;\n  callback(undefined, makerFee / 100);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  return Math.floor(amount*100000000)/100000000;\n}\n\nTrader.prototype.roundPrice = function(price) {\n  // todo: calc significant digits\n  return price;\n}\n\nTrader.prototype.submitOrder = function(type, amount, price, callback) {\n  const processResponse = (err, data) => {\n    if (err)\n      return callback(err);\n\n    callback(null, data.order_id);\n  }\n\n  const fetch = cb => this.bitfinex.new_order(this.pair,\n    amount + '',\n    price + '',\n    this.name.toLowerCase(),\n    type,\n    'exchange limit',\n    this.handleResponse('submitOrder', cb)\n  );\n\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.submitOrder('buy', amount, price, callback);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.submitOrder('sell', amount, price, callback);\n}\n\nTrader.prototype.checkOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) {\n      console.log('this is after we have retried fetching it');\n      // this is after we have retried fetching it\n      // in this.handleResponse.\n      if(err.message.includes('Not Found')) {\n        return callback(undefined, {\n          open: false,\n          executed: true\n        });\n      }\n\n      return callback(err);\n    }\n\n    return callback(undefined, {\n      open: data.is_live,\n      executed: data.original_amount === data.executed_amount,\n      filledAmount: +data.executed_amount\n    });\n  }\n\n  const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('checkOrder', cb));\n  retry(null, fetcher, processResponse);\n}\n\n\nTrader.prototype.getOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    var price = parseFloat(data.avg_execution_price);\n    var amount = parseFloat(data.executed_amount);\n    var date = moment.unix(data.timestamp);\n\n    console.log('getOrder', data);\n\n    // TEMP: Thu May 31 14:49:34 CEST 2018\n    // the `past_trades` call is not returning\n    // any data.\n    return callback(undefined, {price, amount, date});\n\n    const processPastTrade = (err, data) => {\n      if (err) return callback(err);\n\n      console.log('processPastTrade', data);\n      const trade = _.first(data);\n\n      const fees = {\n        [trade.fee_currency]: trade.fee_amount\n      }\n\n      callback(undefined, {price, amount, date, fees});\n    }\n\n    // we need another API call to fetch the fees\n    const feeFetcher = cb => this.bitfinex.past_trades(this.currency, {since: data.timestamp}, this.handleResponse('pastTrades', cb));\n    retry(null, feeFetcher, processPastTrade);\n\n    callback(undefined, {price, amount, date});\n  };\n\n  const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('getOrder', cb));\n  retry(null, fetcher, processResponse);\n}\n\n\nTrader.prototype.cancelOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) {\n      return callback(err);\n    }\n\n    return callback(undefined, false);\n  }\n\n  const handler = cb => this.bitfinex.cancel_order(order_id, this.handleResponse('cancelOrder', cb));\n  retry(null, handler, processResponse);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const processResponse = (err, data) => {  \n    if (err) return callback(err);\n\n    var trades = _.map(data, function(trade) {\n      return {\n        tid: trade.tid, \n        date:  trade.timestamp, \n        price: +trade.price, \n        amount: +trade.amount\n      }\n    });\n\n    callback(undefined, descending ? trades : trades.reverse());\n  };\n\n  var path = this.pair; \n  if(since) \n    path += '?limit_trades=2000'; \n\n  const handler = cb => this.bitfinex.trades(path, this.handleResponse('getTrades', cb));\n  retry(null, handler, processResponse);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Bitfinex',\n    slug: 'bitfinex',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    providesFullHistory: true,\n    providesHistory: 'date',\n    tradable: true,\n    forceReorderDelay: true,\n    gekkoBroker: 0.6\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/bitfinex_v2.js.prep",
    "content": "// NOT USED, see: https://github.com/bitfinexcom/bitfinex-api-node/issues/321\n\nconst Bitfinex = require(\"bitfinex-api-node\");\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst Errors = require('../exchangeErrors');\nconst retry = require('../exchangeUtils').retry;\n\nconst marketData = require('./bitfinex-markets.json');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n  }\n  this.name = 'Bitfinex';\n  this.balance;\n  this.price;\n  this.asset = config.asset;\n  this.currency = config.currency;\n  this.pair = 't' + this.asset + this.currency;\n  this.bitfinex = new Bitfinex.RESTv2({apiKey: this.key, apiSecret: this.secret, transform: true});\n}\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\n// Probably we need to update these string\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  '429',\n  '443',\n  '504',\n  '503',\n  '500',\n  '502',\n  'Empty response'\n];\n\nTrader.prototype.handleResponse = function(funcName, callback) {\n  return (error, data) => {\n    if(!error && _.isEmpty(data)) {\n      error = new Error('Empty response');\n    }\n\n    if(error) {\n      const message = error.message || error;\n\n      if(!includes(message, recoverableErrors)) {\n        const error = new Error(message);\n        error.notFatal = true;\n        return callback(error);\n      }\n    }\n\n    return callback(error, data);\n  }\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const processResponse = (err, data) => {\n    console.log('processResponse', {err, data});\n    if (err) return callback(err);\n\n    // We are only interested in funds in the \"exchange\" wallet\n    data = data.filter(c => c.type === 'exchange');\n\n    const asset = _.find(data, c => c.currency.toUpperCase() === this.asset);\n    const currency = _.find(data, c => c.currency.toUpperCase() === this.currency);\n\n    console.log(currency.balance);\n\n    let assetAmount, currencyAmount;\n\n    if(_.isObject(asset) && _.isNumber(+asset.balanceAvailable) && !_.isNaN(+asset.balanceAvailable))\n      assetAmount = +asset.balanceAvailable;\n    else {\n      assetAmount = 0;\n    }\n\n    if(_.isObject(currency) && _.isNumber(+currency.balanceAvailable) && !_.isNaN(+currency.balanceAvailable))\n      currencyAmount = +currency.balanceAvailable;\n    else {\n      currencyAmount = 0;\n    }\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount },\n    ];\n\n    callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.bitfinex.wallets(this.handleResponse('getPortfolio', cb));\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  const processResponse = (err, data) => {\n    if (err)\n      return callback(err);\n\n    callback(undefined, {bid: +data.bid, ask: +data.ask});\n  };\n\n  const fetch = cb => this.bitfinex.ticker(this.pair, this.handleResponse('getTicker', cb));\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getFee = function(callback) {\n    const makerFee = 0.1;\n    // const takerFee = 0.2;\n    callback(undefined, makerFee / 100);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  return Math.floor(amount*100000000)/100000000;\n}\n\nTrader.prototype.roundPrice = function(price) {\n  // todo: calc significant digits\n  return price;\n}\n\nTrader.prototype.submit_order = function(type, amount, price, callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    callback(err, data.order_id);\n  }\n\n  const fetcher = cb => this.bitfinex.new_order(this.pair,\n    amount + '',\n    price + '',\n    this.name.toLowerCase(),\n    type,\n    'exchange limit',\n    this.handleResponse('submitOrder', cb)\n  );\n\n  retry(retryCritical, fetcher, processResponse);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.submit_order('buy', amount, price, callback);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.submit_order('sell', amount, price, callback);\n}\n\nTrader.prototype.checkOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    return callback(undefined, {\n      open: data.is_live,\n      executed: data.original_amount === data.executed_amount,\n      filled: +data.executed_amount\n    });\n  }\n\n  const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('checkOrder', cb));\n  retry(retryCritical, fetcher, processResponse);\n}\n\n\nTrader.prototype.getOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    var price = parseFloat(data.avg_execution_price);\n    var amount = parseFloat(data.executed_amount);\n    var date = moment.unix(data.timestamp);\n\n    callback(undefined, {price, amount, date});\n  };\n\n  const fetcher = cb => this.bitfinex.order_status(order_id, this.handleResponse('getOrder', cb));\n  retry(retryCritical, fetcher, processResponse);\n}\n\n\nTrader.prototype.cancelOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    return callback(undefined);\n  }\n\n  const handler = cb => this.bitfinex.cancel_order(order_id, this.handleResponse('cancelOrder', cb));\n  retry(retryForever, handler, processResponse);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const processResponse = (err, data) => {  \n    if (err) return callback(err);\n\n    var trades = _.map(data, function(trade) {\n      return {\n        tid: trade.tid, \n        date:  trade.timestamp, \n        price: +trade.price, \n        amount: +trade.amount\n      }\n    });\n\n    callback(undefined, descending ? trades : trades.reverse());\n  };\n\n  var path = this.pair; \n  if(since) \n    path += '?limit_trades=2000'; \n\n  const handler = cb => this.bitfinex.trades(path, this.handleResponse('getTrades', cb));\n  retry(retryForever, handler, processResponse);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Bitfinex',\n    slug: 'bitfinex',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    providesFullHistory: true,\n    providesHistory: 'date',\n    tradable: true,\n    forceReorderDelay: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/bitstamp.js.old",
    "content": "var Bitstamp = require(\"bitstamp\");\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\nvar util = require('../core/util');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n    this.asset = config.asset.toLowerCase();\n    this.currency = config.currency.toLowerCase();\n    this.market = this.asset + this.currency;\n  }\n  this.name = 'Bitstamp';\n\n  this.bitstamp = new Bitstamp(this.key, this.secret, this.clientID);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, data) {\n\n    if(data && data.error) {\n      err = data.error;\n    }\n\n    if(err) {\n      if(err.meta && err.meta.reason === 'API key not found')\n        util.die('Bitstamp says this API keys is invalid..');\n\n      log.error('BITSTAMP API ERROR:', err);\n      return this.retry(this.getPortfolio, args);\n    }\n\n    var portfolio = [];\n    _.each(data, function(amount, asset) {\n      if(asset.indexOf('available') !== -1) {\n        asset = asset.substr(0, 3).toUpperCase();\n        portfolio.push({name: asset, amount: parseFloat(amount)});\n      }\n    });\n    callback(err, portfolio);\n  }.bind(this);\n\n  this.bitstamp.balance(this.market, set);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  this.bitstamp.ticker(this.market, callback);\n}\n\nTrader.prototype.getFee = function(callback) {\n  var set = function(err, data) {\n    if(err)\n      callback(err);\n\n    callback(false, data.fee / 100);\n  }.bind(this);\n\n  this.bitstamp.balance(this.market, set);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  var findMarket = function(pair) {\n    return pair.pair[0].toLowerCase() === this.currency && pair.pair[1].toLowerCase() === this.asset\n  }\n  var args = _.toArray(arguments);\n  var set = function(err, result) {\n    if(err || result.status === \"error\") {\n      log.error('unable to buy:', err, result.reason, 'retrying...');\n      return this.retry(this.buy, args);\n    }\n\n    callback(null, result.id);\n  }.bind(this);\n\n  //Decrease amount by 1% to avoid trying to buy more than balance allows.\n  amount = Number(amount * 0.99).toFixed(8);\n\n  // Use proper precision by currency pair\n  var pair = _.find(Trader.getCapabilities().markets, _.bind(findMarket, this));\n  price = Number(Number.parseFloat(price).toFixed(pair.precision));\n\n  this.bitstamp.buy(this.market, amount, price, undefined, set);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  var findMarket = function(pair) {\n    return pair.pair[0].toLowerCase() === this.currency && pair.pair[1].toLowerCase() === this.asset\n  }\n  var args = _.toArray(arguments);\n  var set = function(err, result) {\n    if(err || result.status === \"error\") {\n      log.error('unable to sell:', err, result.reason, 'retrying...');\n      return this.retry(this.sell, args);\n    }\n\n    callback(null, result.id);\n  }.bind(this);\n\n  // prevent:\n  // 'Ensure that there are no more than 8 decimal places.'\n  amount = Number(Number.parseFloat(amount)).toFixed(8);\n\n  // Use proper precision by currency pair\n  var pair = _.find(Trader.getCapabilities().markets, _.bind(findMarket, this));\n  price = Number(Number.parseFloat(price).toFixed(pair.precision));\n\n  this.bitstamp.sell(this.market, amount, price, undefined, set);\n}\n\n\nTrader.prototype.getOrder = function(id, callback) {\n  var args = _.toArray(arguments);\n  var get = function(err, data) {\n    if(!err && _.isEmpty(data) && _.isEmpty(data.result))\n      err = 'no data';\n\n    else if(!err && !_.isEmpty(data.error))\n      err = data.error;\n\n    if(err) {\n      log.error('Unable to get order', order, JSON.stringify(err));\n      return this.retry(this.getOrder, args);\n    }\n\n    var order = _.find(data, o => o.order_id === +id);\n\n    if(!order) {\n      // if the order was cancelled we are unable\n      // to retrieve it, assume that this is what\n      // is happening.\n      return callback(err, {\n        price: 0,\n        amount: 0,\n        date: moment(0)\n      });\n    }\n\n    var price = parseFloat( order[`${this.asset}_${this.currency}`] );\n    var amount = Math.abs(parseFloat( order[this.asset] ));\n    var date = moment( order.datetime );\n\n    callback(err, {price, amount, date});\n  }.bind(this);\n\n  this.bitstamp.user_transactions(this.market, {}, get);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var check = function(err, result) {\n    var stillThere = _.find(result, function(o) { return o.id === order });\n    callback(err, !stillThere);\n  }.bind(this);\n\n  this.bitstamp.open_orders(this.market, check);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var cancel = function(err, result) {\n    if(err || !result) {\n      log.error('unable to cancel order', order, '(', err, result, ')');\n      return this.retry(this.cancelOrder, args);\n    }\n\n    callback();\n  }.bind(this);\n\n  this.bitstamp.cancel_order(order, cancel);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, trades) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    var result = _.map(trades, t => {\n      return {\n        date: t.date,\n        tid: +t.tid,\n        price: +t.price,\n        amount: +t.amount\n      }\n    })\n\n    callback(null, result.reverse());\n  }.bind(this);\n\n  // NOTE: temporary disabled, see https://github.com/askmike/gekko/issues/794\n  // if(since)\n  //   this.bitstamp.transactions(this.market, {time: 'day'}, process);\n  // else\n  this.bitstamp.transactions(this.market, process);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Bitstamp',\n    slug: 'bitstamp',\n    currencies: ['USD', 'EUR', 'BTC'],\n    assets: ['BTC', 'BCH', 'EUR', 'LTC', 'ETH', 'XRP'],\n    maxTradesAge: 60,\n    maxHistoryFetch: null,\n    markets: [\n      { pair: ['USD', 'EUR'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['EUR', 'BTC'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n\n      { pair: ['USD', 'BCH'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['EUR', 'BCH'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['BTC', 'BCH'], minimalOrder: { amount: 0.001, unit: 'currency'}, precision: 8  },\n\n      { pair: ['USD', 'XRP'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 5 },\n      { pair: ['EUR', 'XRP'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 5 },\n      { pair: ['BTC', 'XRP'], minimalOrder: { amount: 0.001, unit: 'currency'}, precision: 8  },\n\n      { pair: ['USD', 'LTC'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['EUR', 'LTC'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.001, unit: 'currency'}, precision: 8  },\n\n      { pair: ['USD', 'ETH'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['EUR', 'ETH'], minimalOrder: { amount: 5, unit: 'currency' }, precision: 2 },\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.001, unit: 'currency'}, precision: 8  },\n    ],\n    requires: ['key', 'secret', 'username'],\n    fetchTimespan: 60,\n    tid: 'tid',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/bittrex.js",
    "content": "const Bittrex = require('node.bittrex.api');\nconst _ = require('lodash');\nconst moment = require('moment');\nconst retry = require('../exchangeUtils').retry;\n\n// Helper methods\nfunction joinCurrencies(currencyA, currencyB){\n    return currencyA + '-' + currencyB;\n}\n\nvar Trader = function(config) {\n  this.currency = config.currency;\n  this.asset = config.asset;\n\n  if(!config.key) {\n    // no api key defined -> we need to set a\n    // dummy key, otherwise the Bittrex module\n    // will not work even for public requests.\n    this.key = 'dummyApiKey';\n    this.secret = 'dummyApiKey';\n  } else {\n    this.key = config.key;\n    this.secret = config.secret;\n  }\n\n  this.name = 'Bittrex';\n  this.balance;\n  this.price;\n\n  this.pair = [this.currency, this.asset].join('-');\n\n  Bittrex.options({\n    apikey:  this.key,\n    apisecret: this.secret,\n    stream: false,\n    verbose: false,\n    cleartext: false,\n    inverse_callback_arguments: true\n  });\n\n  this.bittrexApi = Bittrex;\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n];\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.processResponse = function(callback) {\n  return (err, response) => {\n\n    if(err) {\n      if(!_.isError(err)) {\n        err = new Error(err.message);\n      }\n\n      if(err.message === 'APIKEY_INVALID') {\n        console.log('APIKEY_INVALID');\n        err.retry = 10;\n      }\n\n      if(includes(err.message, recoverableErrors)) {\n        err.notFatal = true;\n      }\n\n      return callback(err);\n    }\n\n    callback(undefined, response);\n  }\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    data = data.result;\n\n    let assetEntry = _.find(data, i => i.Currency == this.asset);\n    let currencyEntry = _.find(data, i => i.Currency == this.currency);\n\n    if(_.isUndefined(assetEntry)) {\n      assetEntry = {\n        Available: 0.0,\n        Currency: this.asset\n      }\n    }\n\n    if(_.isUndefined(currencyEntry)) {\n      currencyEntry = {\n        Available: 0.0,\n        Currency: this.currency\n      }\n    }\n\n    const assetAmount = parseFloat( assetEntry.Available );\n    const currencyAmount = parseFloat( currencyEntry.Available );\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n\n    callback(undefined, portfolio);\n  }\n\n  const fetch = next => this.bittrexApi.getbalances(this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return _.round(price, 8);\n}\n\nTrader.prototype.roundAmount = function(price) {\n  return _.floor(price, 8);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    const tick = data.result;\n\n    callback(null, {\n      bid: parseFloat(tick.Bid),\n      ask: parseFloat(tick.Ask),\n    })\n  }\n\n  const fetch = next => this.bittrexApi.getticker({market: this.pair}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getFee = function(callback) {\n  callback(false, 0.00025);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  const handle = (err, result) => {\n    console.log('[bittrex buy]', err, result);\n\n    if(err) {\n      return callback(err);\n    }\n\n    const id = _.get(result, 'result.uuid');\n    if(!id) {\n      console.log('[bittrex buy error]', result);\n      return callback(new Error('Bad response'));\n    }\n\n    callback(undefined, id);\n  }\n\n  const fetch = next => this.bittrexApi.buylimit({market: this.pair, quantity: amount, rate: price}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  const handle = (err, result) => {\n    console.log('[bittrex sell]', err, result);\n\n    if(err) {\n      return callback(err);\n    }\n\n    const id = _.get(result, 'result.uuid');\n    if(!id) {\n      console.log('[bittrex sell error]', result);\n      return callback(new Error('Bad response'));\n    }\n\n    callback(undefined, id);\n  }\n\n  const fetch = next => this.bittrexApi.selllimit({market: this.pair, quantity: amount, rate: price}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  const handle = (err, result) => {\n\n    if(err) {\n      return callback(err);\n    }\n\n    console.log('checkOrder', result);\n    throw 'a';\n  }\n\n  const fetch = next => this.bittrexApi.getopenorders({market: this.pair}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n\n  const handle = (err, result) => {\n    console.log('getOrder', result);\n\n    if(err)\n      return callback(err);\n\n    let price = 0;\n    let amount = 0;\n    let date = moment(0);\n\n    if(!result.success) {\n      return callback(null, {price, amount, date});\n    }\n\n    const resultOrder = result.result;\n\n    price = resultOrder.Price;\n    amount = resultOrder.Quantity;\n\n    if(resultOrder.IsOpen) {\n       date = moment(resultOrder.Opened);\n    } else {\n       date = moment(resultOrder.Closed);\n    }\n\n    callback(err, {price, amount, date});\n  }\n\n  const fetch = next => this.bittrexApi.getorder({uuid: order}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  const handle = (err, result) => {\n    console.log('cancelOrder', err, result);\n    if(err) {\n      return callback(err);\n    }\n\n    throw 'a';\n\n    // if(!result.success && result.message === 'ORDER_NOT_OPEN') {\n    //   log.debug('getOrder', 'ORDER_NOT_OPEN: assuming already closed or executed');\n    // }\n\n    callback(undefined, true);\n  }\n\n  const fetch = next => this.bittrexApi.cancel({uuid: order}, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {;\n  var firstFetch = !!since;\n\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    var result = data.result;\n\n    // Edge case, see here:\n    // @link https://github.com/askmike/gekko/issues/479\n    if(firstFetch && _.size(result) === 50000)\n      util.die(\n        [\n          'Bittrex did not provide enough data. Read this:',\n          'https://github.com/askmike/gekko/issues/479'\n        ].join('\\n\\n')\n      );\n\n      result = _.map(result, function(trade) {\n        var mr = {\n            tid: trade.Id,\n            amount: +trade.Quantity,\n            date: moment.utc(trade.TimeStamp).unix(),\n            timeStamp: trade.TimeStamp,\n            price: +trade.Price\n        };\n      return mr;\n    });\n\n    callback(null, result.reverse());\n  }\n\n  var params = {\n    currencyPair: joinCurrencies(this.currency, this.asset)\n  }\n\n  if(since) {\n    params.start = since.unix();\n  }\n\n  const fetch = next => this.bittrexApi.getmarkethistory({ market: params.currencyPair }, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.getCapabilities = function() {\n  return {\n    name: 'bittrex',\n    slug: 'bittrex',\n    currencies: ['BITCNY', 'BTC', 'ETH', 'USDT'],\n    assets: [\n      '1ST', '2GIVE', '8BIT', 'ABY', 'ADC', 'ADT', 'ADX', 'AEON', 'AGRS', 'AM',\n      'AMP', 'AMS', 'ANS', 'ANT', 'APEX', 'APX', 'ARB', 'ARCH', 'ARDR', 'ARK',\n      'AUR', 'BAT', 'BAY', 'BCC', 'BCY', 'BITB', 'BITCNY', 'BITS', 'BITZ', 'BLC',\n      'BLITZ', 'BLK', 'BLOCK', 'BNT', 'BOB', 'BRK', 'BRX', 'BSD', 'BSTY', 'BTA',\n      'BTC', 'BTCD', 'BTS', 'BURST', 'BYC', 'CANN', 'CCN', 'CFI', 'CLAM',\n      'CLOAK', 'CLUB', 'COVAL', 'CPC', 'CRB', 'CRBIT', 'CRW', 'CRYPT', 'CURE',\n      'CVC', 'DAR', 'DASH', 'DCR', 'DCT', 'DGB', 'DGC', 'DGD', 'DMD', 'DOGE',\n      'DOPE', 'DRACO', 'DTB', 'DTC', 'DYN', 'EBST', 'EDG', 'EFL', 'EGC', 'EMC',\n      'EMC2', 'ENRG', 'ERC', 'ETC', 'ETH', 'EXCL', 'EXP', 'FAIR', 'FC2', 'FCT',\n      'FLDC', 'FLO', 'FRK', 'FSC2', 'FTC', 'FUN', 'GAM', 'GAME', 'GBG', 'GBYTE',\n      'GCR', 'GEMZ', 'GEO', 'GHC', 'GLD', 'GNO', 'GNT', 'GOLOS', 'GP', 'GRC',\n      'GRS', 'GRT', 'GUP', 'HKG', 'HMQ', 'HYPER', 'HZ', 'INCNT', 'INFX', 'IOC',\n      'ION', 'IOP', 'J', 'JWL', 'KMD', 'KORE', 'KR', 'LBC', 'LGD', 'LMC', 'LSK',\n      'LTC', 'LUN', 'LXC', 'MAID', 'MAX', 'MCO', 'MEC', 'MEME', 'METAL', 'MLN',\n      'MND', 'MONA', 'MTL', 'MTR', 'MUE', 'MUSIC', 'MYR', 'MYST', 'MZC', 'NAUT',\n      'NAV', 'NBT', 'NEO', 'NET', 'NEU', 'NLG', 'NMR', 'NTRN', 'NXC', 'NXS',\n      'NXT', 'OC', 'OK', 'OMG', 'OMNI', 'ORB', 'PART', 'PAY', 'PDC', 'PINK',\n      'PIVX', 'PKB', 'POT', 'PPC', 'PRIME', 'PTC', 'PTOY', 'PXI', 'QRL', 'QTL',\n      'QTUM', 'QWARK', 'RADS', 'RBY', 'RDD', 'REP', 'RISE', 'RLC', 'ROOT',\n      'SBD', 'SC', 'SCOT', 'SCRT', 'SDC', 'SEC', 'SEQ', 'SFR', 'SHIFT', 'SIB',\n      'SLG', 'SLING', 'SLR', 'SLS', 'SNGLS', 'SNRG', 'SNT', 'SOON', 'SPHR',\n      'SPR', 'SPRTS', 'SSD', 'START', 'STEEM', 'STEPS', 'STORJ', 'STRAT', 'STV',\n      'SWIFT', 'SWING', 'SWT', 'SYNX', 'SYS', 'TES', 'THC', 'TIME', 'TIT',\n      'TKN', 'TKS', 'TRI', 'TRIG', 'TRK', 'TROLL', 'TRST', 'TRUST', 'TX', 'U',\n      'UBQ', 'UFO', 'UNB', 'UNIQ', 'UNIT', 'UNO', 'USDT', 'UTC', 'VIA', 'VIOR',\n      'VIRAL', 'VOX', 'VPN', 'VRC', 'VRM', 'VTC', 'VTR', 'WARP', 'WAVES', 'WBB',\n      'WINGS', 'XAUR', 'XBB', 'XC', 'XCO', 'XCP', 'XDN', 'XDQ', 'XEL', 'XEM',\n      'XLM', 'XMG', 'XMR', 'XPY', 'XQN', 'XRP', 'XSEED', 'XST', 'XTC', 'XVC',\n      'XVG', 'XWC', 'XZC', 'YBC', 'ZCL', 'ZEC', 'ZEN','BTG','OMG','ADA'\n    ],\n    markets: [\n\n      // *** BTCNY <-> XXX\n      { pair: ['BITCNY','BTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n\n      // *** BTC <-> XXX\n      { pair: ['BTC','1ST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','2GIVE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ABY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ADT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ADX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','AEON'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','AGRS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','AMP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ANT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','APX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ARDR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ARK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','AUR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BAT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BAY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BCC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BCY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BITB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BLITZ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BLK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BLOCK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BRK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BRX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BSD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BTA'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BTCD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BTS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BURST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','BYC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CANN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CFI'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CLAM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CLOAK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CLUB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','COVAL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CPC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CRB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CRW'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CURE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','CVC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DAR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DASH'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DCR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DCT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DGB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DGD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DMD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DOGE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DOPE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DRACO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DTB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','DYN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EBST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EDG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EFL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EGC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EMC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EMC2'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ENRG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ERC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ETC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ETH'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EXCL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','EXP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FAIR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FCT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FLDC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FLO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','FUN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GAM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GAME'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GBG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GBYTE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GCR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GEO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GLD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GNO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GOLOS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GRC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GRS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','GUP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','HKG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','HMQ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','INCNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','INFX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','IOC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ION'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','IOP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','KMD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','KORE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LBC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LGD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LMC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LSK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','LUN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MAID'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MCO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MEME'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MLN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MONA'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MTL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MUE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MUSIC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','MYST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NAUT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NAV'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NBT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NEO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NLG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NMR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NXC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NXS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','NXT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','OK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','OMG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','OMNI'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PART'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PAY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PDC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PINK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PIVX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PKB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','POT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PPC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','PTOY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','QRL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','QTUM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','QWARK'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','RADS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','RBY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','RDD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','REP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','RISE'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','RLC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SAFEX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SBD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SEQ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SHIFT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SIB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SLR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SLS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SNGLS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SNRG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SPHR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SPR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','START'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','STEEM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','STORJ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','STRAT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SWIFT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SWT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SYNX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','SYS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','THC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TIME'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TKN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TKS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TRIG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TRST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TRUST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','TX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','UBQ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','UNB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','UNO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VIA'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VOX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VRC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VRM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','VTR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','WAVES'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','WINGS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XAUR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XBB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XCP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XDN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XEL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XEM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XLM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XMG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XMR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XMY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XRP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XVC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XVG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XWC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','XZC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ZCL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ZEC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['BTC','ZEN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n\n      // *** ETH <-> XXX\n      { pair: ['ETH','1ST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','ADT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','ADX'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','ANT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','BAT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','BCC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','BNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','BTS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','CFI'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','CRB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','CVC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','DASH'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','DGB'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','DGD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','ETC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','FCT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','FUN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','GNO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','GNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','GUP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','HMQ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','LGD'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','LTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','LUN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','MCO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','MTL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','MYST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','NEO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','NMR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','OMG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','PAY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','PTOY'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','QRL'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','QTUM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','REP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','RLC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','SC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','SNGLS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','SNT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','STORJ'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','STRAT'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','TIME'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','TKN'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','TRST'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','WAVES'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','WINGS'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','XEM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','XLM'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','XMR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','XRP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['ETH','ZEC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n\n      // *** USDT <-> XXX\n      { pair: ['USDT','BCC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','BTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','DASH'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','ETC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','ETH'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','LTC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','NEO'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','XMR'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','XRP'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','ZEC'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','BTG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','OMG'], minimalOrder: { amount: 0.00000001, unit: 'asset' }},\n      { pair: ['USDT','ADA'], minimalOrder: { amount: 0.00000001, unit: 'asset' }}\n\n    ],\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    providesHistory: 'date',\n    providesFullHistory: false,\n    tradable: false,\n    forceReorderDelay: true,\n    gekkoBroker: '0.6.0'\n  };\n};\n\n\n\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/btc-markets.js.old",
    "content": "var BTCMarkets = require('btc-markets');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n    this.currency = config.currency;\n    this.asset = config.asset;\n  }\n  this.name = 'BTC Markets';\n  this.priceDivider = 100000000; // one hundred million\n  this.btcmakets = new BTCMarkets(this.key, this.secret);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var set = function(err, data) {\n\n    if(!_.isEmpty(data.errorMessage))\n      return callback('BTC-MARKET API ERROR: ' + data.errorMessage);\n\n    var portfolio = _.map(data, function(balance) {\n      return {\n        name: balance.currency,\n        amount: balance.balance / this.priceDivider\n      }\n    }, this);\n\n    callback(err, portfolio);\n  }.bind(this);\n\n  this.btcmakets.getAccountBalances(set);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, result) {\n    if(err)\n      return this.retry(this.getTicker, args);\n\n    callback(null, {\n      bid: result.bestBid,\n      ask: result.bestAsk\n    });\n  }.bind(this);\n  this.btcmakets.getTick(this.asset, this.currency, set);\n}\n\nTrader.prototype.getFee = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, data) {\n\n    if(!err && _.isEmpty(data))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err){\n      log.error('unable to retrieve fee', err, ' retrying...');\n      return this.retry(this.getFee, args);\n    }\n    data.tradingFeeRate /= this.priceDivider;\n    callback(false, data.tradingFeeRate);\n  }.bind(this);\n  this.btcmakets.getTradingFee(this.asset, this.currency, set);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n\n  price *= this.priceDivider;  \n  amount = Math.floor(amount * this.priceDivider);\n  var id = Math.random() + '';\n  var set = function(err, data) {\n    if(!err && _.isEmpty(data))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err)\n      return log.error('unable to buy', err);\n    callback(null, data.id);\n  }.bind(this);\n  this.btcmakets.createOrder(\n    this.asset,\n    this.currency,\n    price,\n    amount,\n    'Bid',\n    'Limit',\n    id,\n    set\n  );\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  price *= this.priceDivider;\n  amount = Math.floor(amount * this.priceDivider);\n  var id = Math.random() + ''\n  var set = function(err, data) {\n    if(!err && _.isEmpty(data))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err)\n      return log.error('unable to sell', err)\n    callback(null, data.id);\n  }.bind(this);\n  this.btcmakets.createOrder(\n    this.asset,\n    this.currency,\n    price,\n    amount,\n    'Ask',\n    'Limit',\n    id,\n    set\n  );\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n\n  if (order == null) {\n    return callback(null, true);\n  }\n\n  var check = function(err, data) {\n    if(!err && _.isEmpty(data.orders))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err){\n      return log.error('unable to check order: ', order, '(', err ,'), retrying...');\n       this.retry(this.checkOrder, args);\n    }\n    var placed = !_.isEmpty(data.orders)\n    callback(err, !placed);\n  }.bind(this);\n\n  this.btcmakets.getOpenOrders(this.asset, this.currency, 10, null, check);\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var get = function(err, data) {\n\n    if(!err && _.isEmpty(data.orders))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err){\n      return log.error('unable to get order detail: ', order, '(', err ,'), retrying...');\n      this.retry(this.getOrder, args);\n    }\n    var price = parseFloat(data.orders[0].price);\n    var amount = parseFloat(data.orders[0].volumn);\n    var date = moment.unix(data.orders[0].creationDate);\n\n    callback(undefined, {price, amount, date});\n  }.bind(this);\n\n  this.btcmakets.getOrderDetail([order], callback);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var get = function(err, data) {\n\n    if(!err && _.isEmpty(data))\n      err = 'no data';\n    else if(!err && !_.isEmpty(data.errorMessage))\n      err = data.errorMessage;\n    if(err){\n       return log.error('unable to cancel order: ',order, '(', err, '), retrying...');\n       this.retry(this.cancelOrder, args);\n    }\n    callback();\n  };\n  this.btcmakets.cancelOrders([order], callback);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    callback(null, result.reverse());\n  }.bind(this);\n\n  // supports `since` based on trade ID, Gekko can't work this atm..\n  this.btcmakets.getTrades(this.asset, this.currency, process);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'BTC Markets',\n    slug: 'btc-markets',\n    currencies: ['AUD', 'BTC'],\n    assets: [\n      'BTC', 'LTC', 'ETH', 'ETC', 'BCH', 'XRP'\n    ],\n    markets: [\n      { pair: ['AUD', 'BTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['AUD', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['AUD', 'ETH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['AUD', 'ETC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['AUD', 'BCH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['AUD', 'XRP'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'ETC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'BCH'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'XRP'], minimalOrder: { amount: 0.001, unit: 'asset' } }\n    ],\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    providesHistory: 'scan',\n    providesFullHistory: false,\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/btcc.js.old",
    "content": "var BTCChina = require('btc-china-fork');\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n  }\n  this.name = 'BTCC';\n\n  this.pair = (config.asset + config.currency).toUpperCase();\n\n  this.btcc = new BTCChina(this.key, this.secret, this.clientID);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getTicker = function(callback) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTicker, args);\n\n    callback(null, {\n      bid: result.bids[0][0],\n      ask: result.asks[0][0]\n    });\n\n  }.bind(this);\n\n  this.btcc.getOrderBook(process, this.pair, 1);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    if(descending)\n      callback(null, result.reverse());\n    else\n      callback(null, result);\n  }.bind(this);\n\n\n  if(!since)\n    since = 500;\n  else\n    since = 5000;\n\n  this.btcc.getHistoryData(process, {limit: since});\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, data) {\n    if(err)\n      return this.retry(this.getPortfolio, args);\n\n    var portfolio = [];\n    _.each(data.result.balance, function(obj) {\n        portfolio.push({name: obj.currency, amount: parseFloat(obj.amount)});\n    });\n    callback(err, portfolio);\n  }.bind(this);\n\n  this.btcc.getAccountInfo(set, 'ALL');\n}\n\nTrader.prototype.getFee = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, data) {\n    if(err)\n      this.retry(this.getFee, args);\n\n    callback(false, data.result.profile.trade_fee / 100);\n  }.bind(this);\n\n  this.btcc.getAccountInfo(set, 'ALL');\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  // TODO: do somewhere better..\n  amount = Math.floor(amount * 10000) / 10000;\n\n  var set = function(err, result) {\n    if(err)\n      return log.error('unable to buy:', err, result);\n\n    callback(null, result.result);\n  }.bind(this);\n\n  this.btcc.createOrder2(set, 'buy', price, amount, this.pair);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  // TODO: do somewhere better..\n  amount = Math.round(amount * 10000) / 10000;\n\n  var set = function(err, result) {\n    if(err)\n      return log.error('unable to sell:', err, result);\n\n    callback(null, result.result);\n  }.bind(this);\n\n  this.btcc.createOrder2(set, 'sell', price, amount, this.pair);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var check = function(err, result) {\n    if(err)\n      this.retry(this.checkOrder, args);\n\n    var done = result.result.order.status === 'closed';\n    callback(err, done);\n  };\n\n  this.btcc.getOrder(check, order, this.pair, true);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var cancel = function(err, result) {\n    if(err)\n      log.error('unable to cancel order', order, '(', err, result, ')');\n  }.bind(this);\n\n  this.btcc.cancelOrder(cancel, order, this.pair);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'BTCC',\n    slug: 'btcc',\n    currencies: ['BTC', 'CNY'],\n    assets: ['BTC', 'LTC'],\n    markets: [\n      { pair: ['CNY', 'BTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['CNY', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } }\n    ],\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    providesFullHistory: true,\n  };\n}\n\nmodule.exports = Trader;"
  },
  {
    "path": "exchange/wrappers/bx.in.th.js.old",
    "content": "var BitexthaiAPI = require('bitexthai');\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n  }\n  this.name = 'BX.in.th';\n\n  this.pair = 1; // todo\n\n  this.bitexthai = new BitexthaiAPI(this.key, this.secret, this.clientID);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    var parsedTrades = [];\n    _.each(result.trades, function(trade) {\n      // We get trade time in local time, which is GMT+7\n      var date = moment(trade.trade_date).subtract(7, 'hours').unix();\n\n      parsedTrades.push({\n        date: date,\n        price: parseFloat(trade.rate),\n        amount: parseFloat(trade.amount),\n        tid: trade.trade_id\n      });\n    }, this);\n\n    if(descending)\n      callback(null, parsedTrades.reverse());\n    else\n      callback(null, parsedTrades);\n  }.bind(this);\n\n  this.bitexthai.trades(this.pair, process);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'BX.in.th',\n    slug: 'bx.in.th',\n    currencies: ['THB'],\n    assets: ['BTC'],\n    markets: [\n      {\n        pair: ['THB', 'BTC'], minimalOrder: { amount: 0.0001, unit: 'asset' },\n      }\n    ],\n    requires: ['key', 'secret'],\n    tradeError: 'NOT IMPLEMENTED YET',\n    providesHistory: false\n  };\n}\n\nmodule.exports = Trader;"
  },
  {
    "path": "exchange/wrappers/cexio.js.old",
    "content": "var CEXio = require('cexio'),\n   moment = require('moment'),\n    async = require('async'),\n        _ = require('lodash'),\n     util = require('../core/util'),\n      log = require('../core/log');\n\nvar Trader = function(config) {\n  this.user = config.username;\n  this.key = config.key;\n  this.secret = config.secret;\n  this.currency = config.currency.toUpperCase();\n  this.asset = config.asset.toUpperCase();\n  this.pair = this.asset + '_' + this.currency;\n  this.name = 'cex.io';\n\n  this.cexio = new CEXio(\n    this.pair,\n    this.user,\n    this.key,\n    this.secret\n  );\n\n  _.bindAll(this);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, trades) {\n    if(err || !trades || trades.length === 0)\n      return this.retry(this.getTrades, args, err);\n\n    if(descending)\n      callback(null, trades);\n    else\n      callback(null, trades.reverse());\n  }\n\n  this.cexio.trades({}, _.bind(process, this));\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  // Prevent \"You incorrectly entered one of fields.\"\n  // because of more than 8 decimals.\n  amount *= 100000000;\n  amount = Math.floor(amount);\n  amount /= 100000000;\n\n  log.debug('BUY', amount, this.asset, '@', price, this.currency);\n\n  var set = function(err, data) {\n    if(err)\n      return log.error('unable to buy:', err);\n    if(data.error)\n      return log.error('unable to buy:', data.error);\n\n    log.debug('BUY order placed.  Order ID', data.id);\n    callback(null, data.id);\n  };\n\n  this.cexio.place_order('buy', amount, price, _.bind(set, this));\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  // Prevent \"You incorrectly entered one of fields.\"\n  // because of more than 8 decimals.\n  amount *= 100000000;\n  amount = Math.floor(amount);\n  amount /= 100000000;\n\n  // test placing orders which will not be filled\n  //price *= 10; price = price.toFixed(8);\n\n  log.debug('SELL', amount, this.asset, '@', price, this.currency);\n\n  var set = function(err, data) {\n    if(err)\n      return log.error('unable to sell:', err);\n    if(data.error)\n      return log.error('unable to sell:', data.error);\n\n    log.debug('SELL order placed.  Order ID', data.id);\n    callback(null, data.id);\n  };\n\n  this.cexio.place_order('sell', amount, price, _.bind(set, this));\n}\n\nTrader.prototype.retry = function(method, args, err) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..', err, 'waiting for', wait, 'ms');\n\n  if (!_.isFunction(method)) {\n    log.error(this.name, 'failed to retry, no method supplied.');\n    return;\n  }\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var calculate = function(err, data) {\n    if(err)\n      return this.retry(this.getPortfolio, args, err);\n\n    currency = parseFloat(data[this.currency].available)\n    if(parseFloat(data[this.currency].orders)){\n      currency -= parseFloat(data[this.currency].orders)\n    }\n    assets = parseFloat(data[this.asset].available);\n    if( parseFloat(data[this.asset].orders)){\n      assets -= parseFloat(data[this.asset].orders);\n    }\n\n    var portfolio = [];\n    portfolio.push({name: this.currency, amount: currency});\n    portfolio.push({name: this.asset, amount: assets});\n    callback(err, portfolio);\n  }\n  this.cexio.balance(calculate.bind(this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  var set = function(err, data) {\n    var ticker = {\n      ask: data.ask,\n      bid: data.bid\n    };\n    callback(err, ticker);\n  }\n  this.cexio.ticker(_.bind(set, this));\n}\n\nTrader.prototype.getFee = function(callback) {\n  // cexio does currently don't take a fee on trades\n  // TODO: isn't there an API call for this?\n  callback(false, 0.002);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var check = function(err, result) {\n\n    if(err)\n      return callback(false, true);\n    if(result.error)\n      return callback(false, true);\n\n    var exists = false;\n    _.each(result, function(entry) {\n      if(entry.id === order) {\n        exists = true;\n        return;\n      }\n    });\n    callback(err, !exists);\n  };\n\n  this.cexio.open_orders(_.bind(check, this));\n}\n\nTrader.prototype.cancelOrder = function(order) {\n  var check= function(err, result) {\n    if(err)\n      log.error('cancel order failed:', err);\n    if(typeof(result) !== 'undefined' && result.error)\n      log.error('cancel order failed:', result.error);\n  }\n  this.cexio.cancel_order(order, check);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'CEX.io',\n    slug: 'cexio',\n    currencies: ['BTC', 'USD', 'EUR', 'RUB'],\n    assets: ['GHS', 'BTC', 'ETH', 'LTC'],\n    markets: [\n      { pair: ['BTC', 'GHS'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['EUR', 'LTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['USD', 'LTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['RUB', 'BTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['EUR', 'BTC'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['USD', 'ETH'], minimalOrder: { amount: 0.000001, unit: 'currency' } },\n      { pair: ['EUR', 'ETH'], minimalOrder: { amount: 0.000001, unit: 'currency' } }\n    ],\n    requires: ['key', 'secret', 'username'],\n    providesHistory: false,\n    tid: 'tid'\n  };\n}\n\nmodule.exports = Trader;\n\n"
  },
  {
    "path": "exchange/wrappers/coinbase-markets.json",
    "content": "{\n  \"assets\": [\n    \"ETC\",\n    \"BTC\",\n    \"BCH\",\n    \"ETH\",\n    \"LTC\",\n    \"ZRX\"\n  ],\n  \"currencies\": [\n    \"EUR\",\n    \"USD\",\n    \"BTC\",\n    \"GBP\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.00100000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.00100000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.00100000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.00000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.00000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ZRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"1.00000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"ETC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.10000000\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01000000\",\n        \"unit\": \"asset\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "exchange/wrappers/coinfalcon-markets.json",
    "content": "{\n  \"assets\": [\n    \"IOT\",\n    \"ETH\",\n    \"LTC\",\n    \"BTC\",\n    \"NANO\",\n    \"BCH\",\n    \"KIN\",\n    \"TRX\",\n    \"CRPT\",\n    \"GRLC\",\n    \"ECA\",\n    \"XRP\",\n    \"ADA\",\n    \"DOGE\",\n    \"STQ\",\n    \"DASC\",\n    \"EOS\",\n    \"DTX\"\n  ],\n  \"currencies\": [\n    \"BTC\",\n    \"EUR\",\n    \"ETH\",\n    \"USDT\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"BTC\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 0.00001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 0.00001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"NANO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 0.00001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"KIN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-10,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"KIN\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"TRX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"CRPT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"GRLC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ECA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ECA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"XRP\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.000001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ADA\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.000001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DOGE\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"STQ\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"IOT\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.0001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DASC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"DASC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"DASC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.00001,\n        \"price\": 0.0001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"NANO\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.0001,\n        \"price\": 0.0001,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 1e-8,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"USDT\",\n        \"EOS\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.0001,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"DTX\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    }\n  ]\n}"
  },
  {
    "path": "exchange/wrappers/coinfalcon.js",
    "content": "const moment = require('moment');\nconst _ = require('lodash');\nconst marketData = require('./coinfalcon-markets.json');\n\nconst CoinFalcon = require('coinfalcon');\n\nvar Trader = function(config) {\n  _.bindAll(this, [\n    'roundAmount',\n    'roundPrice'\n  ]);\n\n  this.makerFee = 0;\n\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency.toUpperCase();\n    this.asset = config.asset.toUpperCase();\n  }\n\n  this.pair = this.asset + '-' + this.currency;\n  this.name = 'coinfalcon';\n\n  this.market = _.find(Trader.getCapabilities().markets, (market) => {\n    return market.pair[0] === this.currency && market.pair[1] === this.asset\n  });\n\n  this.coinfalcon = new CoinFalcon.Client(this.key, this.secret);\n\n  this.interval = 1500;\n};\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'ECONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  '429',\n  '522',\n  '429',\n  '504',\n  '503',\n  '500',\n  '502',\n  '408',\n  // \"The timestamp 1527996378 is invalid, current timestamp is 1527996441.\"\n  'is invalid, current timestamp is',\n  'EHOSTUNREACH',\n  // https://github.com/askmike/gekko/issues/2407\n  'We are fixing a few issues, be back shortly.',\n  'Client network socket disconnected before secure TLS connection was established',\n  'socket hang up',\n  // getaddrinfo EAI_AGAIN coinfalcon.com coinfalcon.com:443\n  'EAI_AGAIN'\n];\n\n// errors that might mean\n// the API call succeeded.\nconst unknownResultErrors = [\n  '524',\n]\n\nTrader.prototype.processResponse = function(method, args, next) {\n\n  const requestAt = moment();\n\n  const checkTime = () => {\n    const diff = moment().diff(requestAt, 's');\n    if(diff > 10) {\n      console.log(new Date,  '[CF] API CALL TOOK', diff, 'SECONDS!');\n      console.log(new Date,  '[CF]', {method, args, next});\n    }\n  }\n\n  const catcher = err => {\n    if(!err || !err.message) {\n      err = new Error(err || 'Empty error');\n    }\n\n    if(includes(err.message, recoverableErrors)) {\n      return this.retry(method, args);\n    }\n\n    console.log(new Date, '[cf] big error!', err.message, method);\n\n    return next(err);\n  }\n\n  return {\n    failure: catcher,\n    success: data => {\n      if(!data)\n        return catcher();\n\n      if(data.error)\n        return catcher(data.error);\n\n      if(includes(data, ['Please complete the security check to proceed.']))\n        return next(new Error(\n          'Your IP has been flagged by CloudFlare. ' +\n          'As such Gekko Broker cannot access Coinfalcon.'\n        ));\n\n      next(undefined, data);\n    }\n  }\n}\n\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(1, 'seconds');\n\n  // run the failed method again with the same arguments after wait\n  setTimeout(() => {\n    method.apply(this, args);\n  }, wait);\n};\n\nTrader.prototype.getTicker = function(callback) {\n  const handle = this.processResponse(this.getTicker, [callback], (err, res) => {\n    if(err)\n      return callback(err);\n\n    callback(null, {bid: +res.data.bids[0].price, ask: +res.data.asks[0].price})\n  });\n\n  var url = \"markets/\" + this.pair + \"/orders?level=1\"\n\n  this.coinfalcon.get(url).then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.getFee = function(callback) {\n  callback(false, this.makerFee / 100);\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const handle = this.processResponse(this.getPortfolio, [callback], (err, res) => {\n    if(err)\n      return callback(err);\n\n    var portfolio = res.data.map(account => ({\n      name: account.currency_code.toUpperCase(),\n      amount: parseFloat(account.available_balance)\n    }));\n\n    callback(null, portfolio);\n  });\n\n  this.coinfalcon.get('user/accounts').then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.getOpenOrders = function(callback) {\n  const handle = this.processResponse(this.getOpenOrders, [callback], (err, res) => {\n    if(err)\n      return callback(err);\n\n    console.log(new Date, 'CF getOpenOrders', res.data);\n\n    callback(null, res.data.map(o => o.id));\n  });\n\n  this.coinfalcon.get('user/orders').then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.addOrder = function(type, amount, price, callback) {\n  const args = _.toArray(arguments);\n\n  const handle = this.processResponse(this.addOrder, args, (err, res) => {\n    if(err)\n      return callback(err);\n\n    if(!res.data.id) {\n      console.log(new Date, 'CF ERROR! CREATED ORDER BUT NO ID', res);\n    }\n\n    callback(false, res.data.id);\n  });\n\n  const payload = {\n    order_type: type,\n    operation_type: 'limit_order',\n    market: this.pair,\n    size: amount + '',\n    price: price + ''\n  }\n\n  this.coinfalcon.post('user/orders', payload).then(handle.success).catch(handle.failure);\n};\n\n['buy', 'sell'].map(function(type) {\n  Trader.prototype[type] = function(amount, price, callback) {\n    this.addOrder(type, amount, price, callback);\n  };\n});\n\nconst round = function(number, precision) {\n  var factor = Math.pow(10, precision);\n  var tempNumber = number * factor;\n  var roundedTempNumber = Math.round(tempNumber);\n  return roundedTempNumber / factor;\n};\n\n// ticksize 0.01 will yield: 2\nTrader.prototype.getPrecision = function(tickSize) {\n  if (!isFinite(tickSize)) {\n    return 0;\n  }\n  var e = 1;\n  var p = 0;\n  while (Math.round(tickSize * e) / e !== tickSize) {\n    e *= 10; p++;\n  }\n  return p;\n};\n\nTrader.prototype.roundAmount = function(amount) {\n  return round(amount, this.getPrecision(this.market.minimalOrder.amount));\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return round(price, this.getPrecision(this.market.minimalOrder.price));\n}\n\nTrader.prototype.outbidPrice = function(price, isUp) {\n  let newPrice;\n\n  if(isUp) {\n    newPrice = price + this.market.minimalOrder.price;\n  } else {\n    newPrice = price - this.market.minimalOrder.price;\n  }\n\n  return this.roundPrice(newPrice);\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n  const args = _.toArray(arguments);\n  const handle = this.processResponse(this.getOrder, args, (err, res) => {\n    if(err)\n      return callback(err);\n\n    const price = parseFloat(res.data.price);\n    const amount = parseFloat(res.data.size_filled);\n    const date = moment(res.data.created_at);\n    const fees = {};\n    const feePercent = this.makerFee;\n    callback(false, { price, amount, date, fees, feePercent });\n  });\n\n  this.coinfalcon.get('user/orders/' + order).then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.checkOrder = function(order, callback) {\n  const args = _.toArray(arguments);\n\n  const handle = this.processResponse(this.checkOrder, args, (err, res) => {\n    if(err)\n      return callback(err);\n\n    // https://docs.coinfalcon.com/#list-orders\n    const status = res.data.status;\n\n    if(status === 'canceled') {\n      return callback(undefined, { executed: false, open: false });\n    } if(status === 'fulfilled') {\n      return callback(undefined, { executed: true, open: false });\n    } if(\n      status === 'pending' ||\n      status === 'partially_filled' ||\n      status === 'open'\n    ) {\n      return callback(undefined, { executed: false, open: true, filledAmount: +res.data.size_filled });\n    }\n\n    console.error(res.data);\n    callback(new Error('Unknown status ' + status));\n  });\n\n  this.coinfalcon.get('user/orders/' + order).then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  const args = _.toArray(arguments);\n\n  const handle = this.processResponse(this.cancelOrder, args, (err, res) => {\n\n    if(err) {\n      if(err.message.includes('has wrong status.')) {\n\n        // see https://github.com/askmike/gekko/issues/2440\n        return setTimeout(() => {\n          this.checkOrder(order, (err, res) => {\n\n            if(err) {\n              return callback(err);\n            }\n\n            if(!res.open) {\n              return callback(undefined, true);\n            }\n\n            return setTimeout(\n              () => this.cancelOrder(order, callback),\n              this.interval\n            );\n          });\n        }, this.interval);\n      }\n      return callback(err);\n    }\n\n    callback(undefined, false, {\n      filled: +res.data.size_filled\n    });\n  });\n\n  this.coinfalcon.delete('user/orders/' + order).then(handle.success).catch(handle.failure);\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n\n  var success = function(res) {\n    var parsedTrades = [];\n    _.each(\n      res.data,\n      function(trade) {\n        parsedTrades.push({\n          tid: trade.id,\n          date: moment(trade.created_at).unix(),\n          price: parseFloat(trade.price),\n          amount: parseFloat(trade.size),\n        });\n      },\n      this\n    );\n\n    if (descending) {\n      callback(null, parsedTrades);\n    } else {\n      callback(null, parsedTrades.reverse());\n    }\n  }.bind(this);\n\n  var failure = function (err) {\n    err = new Error(err);\n    return this.retry(this.getTrades, args, err);\n  }.bind(this);\n\n  var url = \"markets/\" + this.pair + \"/trades\"\n\n  if (since) {\n    url += '?since_time=' + (_.isString(since) ? since : since.format());\n  }\n\n  this.coinfalcon.get(url).then(success).catch(failure);\n};\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'CoinFalcon',\n    slug: 'coinfalcon',\n    assets: marketData.assets,\n    currencies: marketData.currencies,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    tid: 'tid',\n    tradable: true,\n    forceReorderDelay: false,\n    gekkoBroker: 0.6\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/coingi.js",
    "content": "var Coingi = require('coingi');\nvar moment = require('moment');\nvar _ = require('lodash');\n\nvar util = require('../core/util');\nvar Errors = require('../core/error');\nvar log = require('../core/log');\n\n\nvar Trader = function (config) {\n  _.bindAll(this);\n\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency.toUpperCase()\n    this.asset = config.asset.toUpperCase();\n  }\n\n  this.pair = this.asset + \"-\" + this.currency;\n  this.name = 'coingi';\n  this.since = null;\n\n  this.coingi = new Coingi(\n    this.key,\n    this.secret,\n    {timeout: +moment.duration(60, 'seconds')}\n  );\n}\n\nvar retryCritical = {\n  retries: 10,\n  factor: 1.2,\n  minTimeout: 1 * 1000,\n  maxTimeout: 30 * 1000\n};\n\nvar retryForever = {\n  forever: true,\n  factor: 1.2,\n  minTimeout: 10,\n  maxTimeout: 30\n};\n\nvar recoverableErrors = new RegExp(/(SOCKETTIMEDOUT|TIMEDOUT|CONNRESET|CONNREFUSED|NOTFOUND|API:Invalid nonce|Service:Unavailable|Request timed out|Response code 520|Response code 504|Response code 502)/)\n\nTrader.prototype.processError = function (funcName, error) {\n  if (!error)\n    return undefined;\n\n  if (!error.message.match(recoverableErrors)) {\n    log.error(`[coingi.js] (${funcName}) returned an irrecoverable error: ${error.message}`);\n    return new Errors.AbortError('[coingi.js] ' + error.message);\n  }\n\n  log.debug(`[coingi.js] (${funcName}) returned an error, retrying: ${error.message}`);\n  return new Errors.RetryError('[coingi.js] ' + error.message);\n};\n\nTrader.prototype.handleResponse = function (funcName, callback) {\n  return (error, body) => {\n    if (!error) {\n      if (_.isEmpty(body))\n        error = new Error('NO DATA WAS RETURNED');\n\n      else if (!_.isEmpty(body.error))\n        error = new Error(body.error);\n    }\n\n    return callback(this.processError(funcName, error), body);\n  }\n};\n\n\n\n\n/* PORTFOLIO MANAGER */\n\nTrader.prototype.getTicker = function (callback) {\n  var setTicker = function (err, data) {\n    if (err)\n      return callback(err);\n\n    var ticker = {\n      ask: data.asks[0].price,\n      bid: data.bids[0].price\n    };\n    callback(undefined, ticker);\n  };\n\n  let handler = (cb) => this.coingi.api('order-book', \"/\" + this.pair + \"/1/1/1\", this.handleResponse('getTicker', cb));\n  util.retryCustom(retryForever, _.bind(handler, this), _.bind(setTicker, this));\n};\n\n\nTrader.prototype.getTrades = function (since, callback, ascending) {\n  var startTs = since ? moment(since).valueOf() : null;\n\n  var processResults = function (err, trades) {\n    if (err) {\n      return callback(err);\n    }\n\n    var parsedTrades = [];\n    _.each(trades, function (trade) {\n      // Even when you supply 'since' you can still get more trades than you asked for, it needs to be filtered\n      if (_.isNull(startTs) || startTs < moment(trade.timestamp).valueOf()) {\n        parsedTrades.push({\n          type: trade.type === 0 ? \"sell\" : \"buy\",\n          date: moment(trade.timestamp).unix(),\n          amount: String(trade.amount),\n          price: String(trade.price),\n          tid: trade.timestamp\n        });\n      }\n    }, this);\n\n    if(ascending)\n      callback(undefined, parsedTrades);\n    else\n      callback(undefined, parsedTrades.reverse());\n  };\n\n  var optionalSince = \"\";\n  if (since) {\n    optionalSince = \"/\" + startTs;\n  }\n\n  let handler = (cb) => this.coingi.api('transactions', \"/\" + this.pair + \"/512\" + optionalSince, this.handleResponse('getTrades', cb));\n  util.retryCustom(retryForever, _.bind(handler, this), _.bind(processResults, this));\n};\n\nTrader.prototype.getPortfolio = function (callback) {\n  var setBalance = function (err, data) {\n    if (err)\n      return callback(err);\n\n    log.debug('[coingi.js] entering \"setBalance\" callback after coingi-api call, data:', data);\n\n    const portfolio = [];\n    for (var i = 0; i < data.length; i++) {\n      portfolio.push({\n        name: data[i].currency.name.toUpperCase(),\n        amount: data[i].available\n      });\n    }\n\n    return callback(undefined, portfolio);\n  };\n\n  let handler = (cb) => this.coingi.api('balance', {currencies: this.asset + \",\" + this.currency}, this.handleResponse('getPortfolio', cb));\n  util.retryCustom(retryForever, _.bind(handler, this), _.bind(setBalance, this));\n};\n\n// Base fee is 0.2%\nTrader.prototype.getFee = function (callback) {\n  const fee = 0.2;\n  callback(undefined, fee / 100);\n};\n\nTrader.prototype.addOrder = function (tradeType, amount, price, callback) {\n  log.debug('[coingi.js] (add-order)', tradeType.toUpperCase(), amount, this.asset, '@', price, this.currency);\n\n  var setOrder = function (err, data) {\n    if (err)\n      return callback(err);\n\n    var uuid = data.result;\n    log.debug('[coingi.js] (addOrder) added order with uuid:', uuid);\n\n    callback(undefined, uuid);\n  };\n\n  let reqData = {\n    currencyPair: this.pair,\n    type: tradeType.toLowerCase() === \"sell\" ? 0 : 1,\n    price: price,\n    volume: amount.toString()\n  };\n\n  let handler = (cb) => this.coingi.api('add-order', reqData, this.handleResponse('addOrder', cb));\n  util.retryCustom(retryCritical, _.bind(handler, this), _.bind(setOrder, this));\n};\n\n\nTrader.prototype.getOrder = function (orderId, callback) {\n  var getOrder = function (err, order) {\n    if (err)\n      return callback(err);\n\n    if (order !== null) {\n      const price = parseFloat(order.price);\n      const amount = parseFloat(order.baseAmount);\n      const date = moment.unix(order.timestamp);\n      callback(undefined, {price, amount, date});\n    } else {\n      log.error(\"Error! Order ID '\" + orderId + \"' couldn't be found in the result of get order!\");\n    }\n  };\n\n  let reqData = {ordeId: orderId};\n  let handler = (cb) => this.coingi.api('get-order', reqData, this.handleResponse('getOrder', cb));\n  util.retryCustom(retryCritical, _.bind(handler, this), _.bind(getOrder, this));\n}\n\nTrader.prototype.buy = function (amount, price, callback) {\n  this.addOrder('buy', amount, price, callback);\n};\n\nTrader.prototype.sell = function (amount, price, callback) {\n  this.addOrder('sell', amount, price, callback);\n};\n\nTrader.prototype.checkOrder = function (orderId, callback) {\n  var check = function (err, order) {\n    if (err)\n      return callback(err);\n\n    if (order === null) {\n      log.error(\"Error! Order ID '\" + orderId + \"' couldn't be found in the result of get order!\");\n    }\n    // returns true when the order has been filled (processed in full), false otherwise\n    callback(undefined, order !== null && order.status === 2);\n  };\n\n  let reqData = {orderId: orderId};\n  let handler = (cb) => this.coingi.api('get-order', reqData, this.handleResponse('checkOrder', cb));\n  util.retryCustom(retryCritical, _.bind(handler, this), _.bind(check, this));\n};\n\nTrader.prototype.cancelOrder = function (order, callback) {\n  let reqData = {orderId: order};\n  let handler = (cb) => this.coingi.api('cancel-order', reqData, this.handleResponse('cancelOrder', cb));\n  util.retryCustom(retryForever, _.bind(handler, this), callback);\n};\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Coingi',\n    slug: 'coingi',\n    currencies: ['EUR', 'USD', 'BTC'],\n    assets: ['BTC', 'DASH', 'DOGE', 'EUR', 'LTC', 'NMC', 'PPC', 'VTC'],\n    markets: [\n      // Tradeable against BTC\n      {pair: ['USD', 'BTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['EUR', 'BTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against DASH\n      {pair: ['BTC', 'DASH'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against DOGE\n      {pair: ['BTC', 'DOGE'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['USD', 'DOGE'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against EUR\n      {pair: ['USD', 'EUR'], minimalOrder: {amount: 0.01, unit: 'asset'}, precision: 2},\n\n      // Tradeable against LTC\n      {pair: ['BTC', 'LTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['EUR', 'LTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['USD', 'LTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against NMC\n      {pair: ['BTC', 'NMC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against PPC\n      {pair: ['USD', 'PPC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['EUR', 'PPC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n      {pair: ['BTC', 'PPC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8},\n\n      // Tradeable against VTC\n      {pair: ['BTC', 'VTC'], minimalOrder: {amount: 0.00001, unit: 'asset'}, precision: 8}\n    ],\n    requires: ['key', 'secret'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    exchangeMaxHistoryAge: 30,\n    tid: 'date',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/exmo-markets.json",
    "content": "{\n  \"assets\": [\n    \"BTC\",\n    \"ETH\"\n  ],\n  \"currencies\": [\n    \"EUR\",\n    \"USD\",\n    \"LTC\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"USD\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.001\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.001\",\n        \"unit\": \"asset\"\n      }\n    },\n    {\n      \"pair\": [\n        \"LTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": \"0.01\",\n        \"unit\": \"asset\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "exchange/wrappers/exmo.js",
    "content": "const _ = require('lodash');\nconst moment = require('moment');\nconst retry = require('../exchangeUtils').retry;\n\n\nconst CryptoJS = require(\"crypto-js\");\nconst querystring = require('querystring');\nconst request = require('request');\n\nAPI_URL='https://api.exmo.com/v1/';\n\nconst marketData = require('./exmo-markets.json');\n\n\nconst Trader = function(config) {\n  _.bindAll(this);\n  this.key=\"\";\n  this.secret=\"\";\n  \n  if(_.isObject(config)) {\n      if(_.isString(config.key)) this.key = config.key;\n      if(_.isString(config.secret)) this.secret = config.secret;\n      this.currency = config.currency;\n      this.asset = config.asset;\n      this.pair = this.asset + '_' + this.currency;\n  };\n\n  this.name = 'EXMO';\n  this.nonce = new Date() * 1000;\n}\n\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  'EHOSTUNREACH',\n];\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\n\nTrader.prototype.api_query = function(method, params, callback){\n\tparams.nonce = this.nonce++;\n\tvar post_data = querystring.stringify(params);\n\n\tvar options = {\n\t  url: API_URL + method,\n\t  headers: {'Key': this.key,'Sign': CryptoJS.HmacSHA512(post_data, this.secret).toString(CryptoJS.enc.hex) },\n\t  form: params\n\t};\n\t\n \trequest.post(options, function (error, response, body) {\n        if (!error && response.statusCode == 200) {\n            data=JSON.parse(body);          \n            if(data.error) error = { message: data.error }\n            else if (data.result!=undefined && data.result==false)  error = { message: '\"result\": false' } ;\n            callback(error, data);\n        } else {\n            console.log('cb request error');\n            console.log(body);\n\n\t\t\tif(error) {\n\t\t\t  if(includes(error.message, recoverableErrors)) {\n\t\t\t\terror.notFatal = true;\n\t\t\t  }\n            console.log(error);\n        \tcallback(error);\n            };\n       };\n     });\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const processResponse = (error, data) => {\n    if (error) return callback(error);\n\n    data=data[this.pair];\n\n    var parsedTrades =  _.map(data, function(trade) {   \n        return {\n          tid: trade.trade_id,\n          date: trade.date,\n          price: +trade.price,\n          amount: +trade.quantity\n        };\n     });\n\n    if (descending) callback(undefined, parsedTrades);\n    else callback(undefined, parsedTrades.reverse());\n  };\n\n  const fetch = cb => this.api_query(\"trades\", { pair: this.pair} , cb);\n  retry(null, fetch, processResponse); \n\n}\n\nTrader.prototype.getTicker = function(callback) {\n  const processResponse = (err, data) => {\n    if (err)\n      return callback(err);\n\n    data=data[this.pair];\n\n    callback(undefined, {bid: +data.sell_price, ask: +data.buy_price});\n  };\n\n  const fetch = cb => this.api_query(\"ticker\", { pair: this.pair} , cb);\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getFee = function(callback) {\n  callback(undefined, 0.002);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  return _.floor(amount, 8);\n};\n\nTrader.prototype.roundPrice = function(price) {\n  return price;\n}\n\nTrader.prototype.submitOrder = function(type, amount, price, callback) {\n  const processResponse = (err, data) => {\n    if (err)\n      return callback(err);\n\n    callback(null, data.order_id);\n  }\n\n  const fetch = cb => this.api_query(\"order_create\", { pair: this.pair, quantity: amount, price: price, type: type } , cb);\n  retry(null, fetch, processResponse);\n  //callback(null, 1177669837);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.submitOrder('buy', amount, price, callback);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.submitOrder('sell', amount, price, callback);\n}\n\nTrader.prototype.getOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n\n    if(err) \n      return callback(err);\n\n    data=data[this.pair];\n\n    if(data==undefined) return callback(new Error('Orders not found'));\n\n    const order = _.find(data, function(o) { return o.order_id === +order_id });\n\n    if(!order) return callback(new Error('Order not found'));\n\n    callback(undefined, { price: order.price, amount: order.amount, date: moment.unix(order.date) });\n  }\n\n  const fetch = cb => this.api_query(\"user_trades\", { pair: this.pair} , cb);\n  retry(null, fetch, processResponse); \n}\n\nTrader.prototype.checkOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n\n    if(err) \n      return callback(err);\n\n    data=data[this.pair];\n\n    if(data==undefined) {\n      return callback(undefined, { executed: true, open: false });\n    }\n\n    const order = _.find(data, function(o) { return o.order_id === +order_id });\n    if(!order) \n      return callback(undefined, { executed: true, open: false });\n\n    callback(undefined, { executed: false, open: true /*, filledAmount: order.startingAmount - order.amount*/ });\n  }\n\n  const fetch = cb => this.api_query(\"user_open_orders\", { } , cb);\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.cancelOrder = function(order_id, callback) {\n  const processResponse = (err, data) => {\n    if (err) {\n      return callback(err);\n    }\n\n    return callback(undefined, false);\n  }\n\n  const fetch = cb => this.api_query(\"order_cancel\", { order_id } , cb);\n  retry(null, fetch, processResponse);\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  const processResponse = (err, data) => {\n    if (err) return callback(err);\n\n    data=data[\"balances\"];\n    const balances = _.map(data, function (v,k){ return {name: k, amount: +v};});\n    const portfolio = balances.filter(c => c.name===this.asset || c.name===this.currency)\n\n    callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.api_query(\"user_info\", {}, cb);\n  retry(null, fetch, processResponse);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'EXMO',\n    slug: 'exmo',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    providesHistory: false,\n    tid: 'tid',\n    tradable: true,\n    gekkoBroker: 0.6\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/gdax.js",
    "content": "const Gdax = require('gdax');\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst errors = require('../exchangeErrors');\nconst retry = require('../exchangeUtils').retry;\n\nconst BATCH_SIZE = 100;\nconst QUERY_DELAY = 350;\n\nconst marketData = require('./coinbase-markets.json');\n\nconst Trader = function(config) {\n  this.post_only = true;\n  this.use_sandbox = false;\n  this.name = 'GDAX';\n  this.scanback = false;\n  this.scanbackTid = 0;\n  this.scanbackResults = [];\n  this.asset = config.asset;\n  this.currency = config.currency;\n\n  this.api_url = 'https://api.pro.coinbase.com';\n  this.api_sandbox_url = 'https://api-public.sandbox.pro.coinbase.com';\n\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.passphrase = config.passphrase;\n\n    this.pair = [config.asset, config.currency].join('-').toUpperCase();\n    this.post_only =\n      typeof config.post_only !== 'undefined' ? config.post_only : true;\n    \n    if (config.sandbox) {\n      this.use_sandbox = config.sandbox;\n    }\n\n  }\n\n  this.gdax_public = new Gdax.PublicClient(\n    this.use_sandbox ? this.api_sandbox_url : undefined\n  );\n  this.gdax = new Gdax.AuthenticatedClient(\n    this.key,\n    this.secret,\n    this.passphrase,\n    this.use_sandbox ? this.api_sandbox_url : undefined\n  );\n};\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  'Rate limit exceeded',\n  'Response code 5',\n  'GDAX is currently under maintenance.',\n  'HTTP 408 Error',\n  'HTTP 504 Error',\n  'HTTP 503 Error',\n  'socket hang up',\n  'EHOSTUNREACH',\n  'EAI_AGAIN',\n  'ENETUNREACH'\n];\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.processResponse = function(method, next) {\n  return (error, response, body) => {\n    if(!error && body && !_.isEmpty(body.message)) {\n      error = new Error(body.message);\n    }\n\n    if(\n      response &&\n      response.statusCode < 200 &&\n      response.statusCode >= 300\n    ) {\n      error = new Error(`Response code ${response.statusCode}`);\n    }\n\n    if(error) {\n      if(includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n        error.backoffDelay = 1000;\n      }\n\n      if(\n        ['buy', 'sell'].includes(method) &&\n        error.message.includes('Insufficient funds')\n      ) {\n        error.retry = 10;\n      }\n\n      return next(error);\n    }\n\n    return next(undefined, body);\n  }\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n\n    var portfolio = data.map(function(account) {\n      return {\n        name: account.currency.toUpperCase(),\n        amount: parseFloat(account.available),\n      };\n    });\n    callback(undefined, portfolio);\n  };\n\n  const fetch = cb =>\n    this.gdax.getAccounts(this.processResponse('getPortfolio', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.getTicker = function(callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n    callback(undefined, { bid: +data.bid, ask: +data.ask });\n  };\n\n  const fetch = cb =>\n    this.gdax_public.getProductTicker(this.pair, this.processResponse('getTicker', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.getFee = function(callback) {\n  //https://www.gdax.com/fees\n  // const fee = this.asset == 'BTC' ? 0.0025 : 0.003;\n  const fee = 0;\n\n  //There is no maker fee, not sure if we need taker fee here\n  //If post only is enabled, gdax only does maker trades which are free\n  callback(undefined, this.post_only ? 0 : fee);\n};\n\nTrader.prototype.roundPrice = function(price) {\n  return this.getMaxDecimalsNumber(price, this.currency == 'BTC' ? 5 : 2);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  return this.getMaxDecimalsNumber(amount);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  const buyParams = {\n    price: this.getMaxDecimalsNumber(price, this.currency == 'BTC' ? 5 : 2),\n    size: this.getMaxDecimalsNumber(amount),\n    product_id: this.pair,\n    post_only: this.post_only,\n  };\n\n  const result = (err, data) => {\n    if (err) {\n      console.log({buyParams}, err.message);\n      return callback(err);\n    }\n    callback(undefined, data.id);\n  };\n\n  const fetch = cb =>\n    this.gdax.buy(buyParams, this.processResponse('buy', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.sell = function(amount, price, callback) {\n  const sellParams = {\n    price: this.getMaxDecimalsNumber(price, this.currency == 'BTC' ? 5 : 2),\n    size: this.getMaxDecimalsNumber(amount),\n    product_id: this.pair,\n    post_only: this.post_only,\n  };\n\n  const result = (err, data) => {\n    if (err) {\n      console.log({sellParams}, err.message);\n      return callback(err);\n    }\n\n    if(data.message && data.message.includes('Insufficient funds')) {\n      err = new Error(data.message);\n      err.retryOnce = true;\n      return callback(err);\n    }\n\n    callback(undefined, data.id);\n  };\n\n  const fetch = cb =>\n    this.gdax.sell(sellParams, this.processResponse('sell', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.checkOrder = function(order, callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n\n    // @link:\n    // https://stackoverflow.com/questions/48132078/available-gdax-order-statuses-and-meanings\n    var status = data.status;\n    if(status == 'pending') {\n      // technically not open yet, but will be soon\n      return callback(undefined, { executed: false, open: true, filledAmount: 0 });\n    } if (status === 'done' || status === 'settled') {\n      return callback(undefined, { executed: true, open: false });\n    } else if (status === 'rejected') {\n      return callback(undefined, { executed: false, open: false });\n    } else if(status === 'open' || status === 'active') {\n      return callback(undefined, { executed: false, open: true, filledAmount: parseFloat(data.filled_size) });\n    }\n\n    callback(new Error('Unknown status ' + status));\n  };\n\n  const fetch = cb =>\n    this.gdax.getOrder(order, this.processResponse('checkOrder', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.getOrder = function(order, callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n\n    const price = parseFloat(data.price);\n    const amount = parseFloat(data.filled_size);\n    const date = moment(data.done_at);\n    const fees = {\n      // you always pay fee in the base currency on gdax\n      [this.currency]: +data.fill_fees\n    }\n    const feePercent = +data.fill_fees / price / amount * 100;\n\n    callback(undefined, { price, amount, date, fees, feePercent });\n  };\n\n  const fetch = cb =>\n    this.gdax.getOrder(order, this.processResponse('getOrder', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  // callback for cancelOrder should be true if the order was already filled, otherwise false\n  const result = (err, data) => {\n    if(err) {\n      return callback(null, true);  // need to catch the specific error but usually an error on cancel means it was filled\n    }\n\n    return callback(null, false);\n  };\n\n  const fetch = cb =>\n    this.gdax.cancelOrder(order, this.processResponse('cancelOrder', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var lastScan = 0;\n\n  const handle = function(err, data) {\n    if (err) return callback(err);\n\n    var result = _.map(data, function(trade) {\n      return {\n        tid: trade.trade_id,\n        amount: parseFloat(trade.size),\n        date: moment.utc(trade.time).format('X'),\n        price: parseFloat(trade.price),\n      };\n    });\n\n    if (this.scanback) {\n      var last = _.last(data);\n      var first = _.first(data);\n\n      // Try to find trade id matching the since date\n      if (!this.scanbackTid) {\n        // either scan for new ones or we found it.\n        if (moment.utc(last.time) < moment.utc(since)) {\n          this.scanbackTid = last.trade_id;\n        } else {\n          console.log('Scanning backwards...' + last.time);\n          setTimeout(() => {\n            let handler = cb =>\n              this.gdax_public.getProductTrades(\n                this.pair,\n                {\n                  after: last.trade_id - BATCH_SIZE * lastScan,\n                  limit: BATCH_SIZE,\n                },\n                this.processResponse('getTrades', cb)\n              );\n            retry(\n              retryForever,\n              _.bind(handler, this),\n              _.bind(process, this)\n            );\n          }, QUERY_DELAY);\n          lastScan++;\n          if (lastScan > 100) {\n            lastScan = 10;\n          }\n        }\n      }\n\n      if (this.scanbackTid) {\n        // if scanbackTid is set we need to move forward again\n        console.log(\n          'Backwards: ' +\n            last.time +\n            ' (' +\n            last.trade_id +\n            ') to ' +\n            first.time +\n            ' (' +\n            first.trade_id +\n            ')'\n        );\n\n        this.scanbackResults = this.scanbackResults.concat(result.reverse());\n\n        if (this.scanbackTid != first.trade_id) {\n          this.scanbackTid = first.trade_id;\n          setTimeout(() => {\n            let handler = cb =>\n              this.gdax_public.getProductTrades(\n                this.pair,\n                { after: this.scanbackTid + BATCH_SIZE + 1, limit: BATCH_SIZE },\n                this.processResponse('getTrades', cb)\n              );\n            retry(\n              retryForever,\n              _.bind(handler, this),\n              _.bind(process, this)\n            );\n          }, QUERY_DELAY);\n        } else {\n          this.scanback = false;\n          this.scanbackTid = 0;\n\n          console.log('Scan finished: data found:' + this.scanbackResults.length);\n          callback(null, this.scanbackResults);\n\n          this.scanbackResults = [];\n        }\n      }\n    } else {\n      callback(null, result.reverse());\n    }\n  };\n\n  if (since || this.scanback) {\n    this.scanback = true;\n    if (this.scanbackTid) {\n      let handler = cb =>\n        this.gdax_public.getProductTrades(\n          this.pair,\n          { after: this.scanbackTid + BATCH_SIZE + 1, limit: BATCH_SIZE },\n          this.processResponse('getTrades', cb)\n        );\n      retry(\n        retryForever,\n        _.bind(handler, this),\n        _.bind(process, this)\n      );\n    } else if (since) {\n      console.log('Scanning back in the history needed...', since);\n    }\n  }\n\n  const fetch = cb =>\n    this.gdax_public.getProductTrades(\n      this.pair,\n      { limit: BATCH_SIZE },\n      this.processResponse('getTrades', cb)\n    );\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.getMaxDecimalsNumber = function(number, decimalLimit = 8) {\n  var decimalNumber = parseFloat(number);\n\n  // The ^-?\\d*\\. strips off any sign, integer portion, and decimal point\n  // leaving only the decimal fraction.\n  // The 0+$ strips off any trailing zeroes.\n  var decimalCount = (+decimalNumber).toString().replace(/^-?\\d*\\.?|0+$/g, '')\n    .length;\n\n  var decimalMultiplier = 1;\n  for (i = 0; i < decimalLimit; i++) {\n    decimalMultiplier *= 10;\n  }\n\n  return decimalCount <= decimalLimit\n    ? decimalNumber.toString()\n    : (\n        Math.floor(decimalNumber * decimalMultiplier) / decimalMultiplier\n      ).toFixed(decimalLimit);\n};\n\nTrader.getCapabilities = function() {\n  return {\n    name: 'GDAX',\n    slug: 'gdax',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret', 'passphrase'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    tid: 'tid',\n    tradable: true,\n    forceReorderDelay: false,\n    gekkoBroker: 0.6\n  };\n};\n\nmodule.exports = Trader;"
  },
  {
    "path": "exchange/wrappers/gemini.js.old",
    "content": "var Gemini = require('gemini-exchange-coffee-api/lib/gemini');\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n  }\n  this.name = 'Gemini';\n  this.balance;\n  this.price;\n  this.asset = config.asset;\n  this.currency = config.currency;\n  this.pair = this.asset + this.currency;\n  this.gemini = new Gemini(this.key, this.secret);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  this.gemini.wallet_balances(function (err, data, body) {\n\n    if(err && err.message === '401') {\n      let e = 'Gemini replied with an unauthorized error. ';\n      e += 'Double check whether your API key is correct.';\n      util.die(e);\n    }\n\n    if(err || !data)\n      return this.retry(this.getPortfolio, args);\n\n    // We are only interested in funds in the \"exchange\" wallet\n    data = data.filter(c => c.type === 'exchange');\n\n    const asset = _.find(data, c => c.currency.toUpperCase() === this.asset);\n    const currency = _.find(data, c => c.currency.toUpperCase() === this.currency);\n\n    let assetAmount, currencyAmount;\n\n    if(_.isObject(asset) && _.isNumber(+asset.available) && !_.isNaN(+asset.available))\n      assetAmount = +asset.available;\n    else {\n      log.error(`Gemini did not provide ${this.asset} amount, assuming 0`);\n      assetAmount = 0;\n    }\n\n    if(_.isObject(currency) && _.isNumber(+currency.available) && !_.isNaN(+currency.available))\n      currencyAmount = +currency.available;\n    else {\n      log.error(`Gemini did not provide ${this.currency} amount, assuming 0`);\n      currencyAmount = 0;\n    }\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount },\n    ];\n\n    callback(err, portfolio);\n  }.bind(this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  var args = _.toArray(arguments);\n  // the function that will handle the API callback\n  var process = function(err, data, body) {\n    if (err)\n        return this.retry(this.getTicker(args));\n\n    // whenever we reach this point we have valid\n    // data, the callback is still the same since\n    // we are inside the same javascript scope.\n    callback(err, {bid: +data.bid, ask: +data.ask})\n  }.bind(this);\n  this.gemini.ticker(this.pair, process);\n}\n\n// This assumes that only limit orders are being placed, so fees are the\n// \"maker fee\" of 0.1%.  It does not take into account volume discounts.\nTrader.prototype.getFee = function(callback) {\n    var makerFee = 0.25;\n    callback(false, makerFee / 100);\n}\n\nTrader.prototype.submit_order = function(type, amount, price, callback) {\n  var args = _.toArray(arguments);\n\n  amount = Math.floor(amount*100000000)/100000000;\n  this.gemini.new_order(\n    this.pair,\n    amount + '',\n    price + '',\n    this.name.toLowerCase(),\n    type,\n    'exchange limit',\n    function (err, data, body) {\n      if (err) {\n        log.error('unable to ' + type, err, body);\n        return this.retry(this.submit_order, args);\n      }\n\n      callback(err, data.order_id);\n    }.bind(this));\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.submit_order('buy', amount, price, callback);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.submit_order('sell', amount, price, callback);\n}\n\nTrader.prototype.checkOrder = function(order_id, callback) {\n  var args = _.toArray(arguments);\n  this.gemini.order_status(order_id, function (err, data, body) {\n\n    if(err || !data)\n      return this.retry(this.checkOrder, arguments);\n\n    callback(err, !data.is_live);\n  }.bind(this));\n}\n\n\nTrader.prototype.getOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var get = function(err, data) {\n    if(err || !data)\n      return this.retry(this.getOrder, arguments);\n\n    var price = parseFloat(data.avg_execution_price);\n    var amount = parseFloat(data.executed_amount);\n    var date = moment.unix(data.timestamp);\n\n    callback(undefined, {price, amount, date});\n  }.bind(this);\n\n  this.gemini.order_status(order, get);\n}\n\n\nTrader.prototype.cancelOrder = function(order_id, callback) {\n  var args = _.toArray(arguments);\n  this.gemini.cancel_order(order_id, function (err, data, body) {\n      if (err || !data) {\n        // gemini way of telling it was already cancelled..\n        if(err.message === 'Order could not be cancelled.')\n          return callback();\n\n        log.error('unable to cancel order', order_id, '(', err, data, '), retrying...');\n        return this.retry(this.cancelOrder, args);\n      }\n\n      return callback();\n  }.bind(this));\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n\n  var path = this.pair;\n  if(since)\n    path += '?limit_trades=2000';\n\n  this.gemini.trades(path, function(err, data) {\n    if (err)\n      return this.retry(this.getTrades, args);\n\n    var trades = _.map(data, function(trade) {\n      return {\n        tid: trade.tid,\n        date:  trade.timestamp,\n        price: +trade.price,\n        amount: +trade.amount\n      }\n    });\n\n    callback(null, descending ? trades : trades.reverse());\n  }.bind(this));\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Gemini',\n    slug: 'gemini',\n    currencies: ['USD', 'BTC'],\n    assets: ['BTC', 'ETH'],\n    markets: [\n      \n        { pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n        { pair: ['USD', 'ETH'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n        { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n\n    ],\n    requires: ['key', 'secret'],\n    tid: 'tid',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/kraken-markets.json",
    "content": "{\n  \"assets\": [\n    \"ADA\",\n    \"BCH\",\n    \"DASH\",\n    \"EOS\",\n    \"GNO\",\n    \"QTUM\",\n    \"USDT\",\n    \"ETC\",\n    \"ETH\",\n    \"ICN\",\n    \"LTC\",\n    \"MLN\",\n    \"REP\",\n    \"XTZ\",\n    \"XBT\",\n    \"XDG\",\n    \"XLM\",\n    \"XMR\",\n    \"XRP\",\n    \"ZEC\"\n  ],\n  \"currencies\": [\n    \"CAD\",\n    \"ETH\",\n    \"EUR\",\n    \"USD\",\n    \"XBT\",\n    \"GBP\",\n    \"JPY\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"CAD\",\n        \"ADA\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"ADA\"\n      ],\n      \"book\": \"ADACAD\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ADA\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"ADA\"\n      ],\n      \"book\": \"ADAETH\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ADA\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"ADA\"\n      ],\n      \"book\": \"ADAEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ADA\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"ADA\"\n      ],\n      \"book\": \"ADAUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ADA\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"ADA\"\n      ],\n      \"book\": \"ADAXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 8,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BCH\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"BCH\"\n      ],\n      \"book\": \"BCHEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"BCH\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"BCH\"\n      ],\n      \"book\": \"BCHUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"BCH\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"BCH\"\n      ],\n      \"book\": \"BCHXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"DASH\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"DASH\"\n      ],\n      \"book\": \"DASHEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"DASH\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"DASH\"\n      ],\n      \"book\": \"DASHUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"DASH\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"DASH\"\n      ],\n      \"book\": \"DASHXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"EOS\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"EOS\"\n      ],\n      \"book\": \"EOSETH\",\n      \"minimalOrder\": {\n        \"amount\": \"3.0\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"EOS\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"EOS\"\n      ],\n      \"book\": \"EOSEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"3.0\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"EOS\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"EOS\"\n      ],\n      \"book\": \"EOSUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"3.0\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"EOS\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"EOS\"\n      ],\n      \"book\": \"EOSXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"3.0\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"GNO\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"GNO\"\n      ],\n      \"book\": \"GNOETH\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"GNO\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"GNO\"\n      ],\n      \"book\": \"GNOEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"GNO\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"GNO\"\n      ],\n      \"book\": \"GNOUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"GNO\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"GNO\"\n      ],\n      \"book\": \"GNOXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"QTUM\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"QTUM\"\n      ],\n      \"book\": \"QTUMCAD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"QTUM\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"QTUM\"\n      ],\n      \"book\": \"QTUMETH\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"QTUM\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"QTUM\"\n      ],\n      \"book\": \"QTUMEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"QTUM\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"QTUM\"\n      ],\n      \"book\": \"QTUMUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"QTUM\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"QTUM\"\n      ],\n      \"book\": \"QTUMXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"USDT\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"USDT\"\n      ],\n      \"book\": \"USDTZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"5\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ETC\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"XETC\"\n      ],\n      \"book\": \"XETCXETH\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ETC\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XETC\"\n      ],\n      \"book\": \"XETCXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETC\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XETC\"\n      ],\n      \"book\": \"XETCZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETC\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XETC\"\n      ],\n      \"book\": \"XETCZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHZCAD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"ZGBP\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHZGBP\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"ZJPY\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHZJPY\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 0,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ETH\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XETH\"\n      ],\n      \"book\": \"XETHZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.02\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"ICN\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"XICN\"\n      ],\n      \"book\": \"XICNXETH\",\n      \"minimalOrder\": {\n        \"amount\": \"2\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ICN\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XICN\"\n      ],\n      \"book\": \"XICNXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"2\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"LTC\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XLTC\"\n      ],\n      \"book\": \"XLTCXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"LTC\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XLTC\"\n      ],\n      \"book\": \"XLTCZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"LTC\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XLTC\"\n      ],\n      \"book\": \"XLTCZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"MLN\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"XMLN\"\n      ],\n      \"book\": \"XMLNXETH\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"MLN\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XMLN\"\n      ],\n      \"book\": \"XMLNXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"REP\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"XREP\"\n      ],\n      \"book\": \"XREPXETH\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"REP\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XREP\"\n      ],\n      \"book\": \"XREPXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"REP\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XREP\"\n      ],\n      \"book\": \"XREPZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"REP\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XREP\"\n      ],\n      \"book\": \"XREPZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.3\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"XTZ\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"XTZ\"\n      ],\n      \"book\": \"XTZCAD\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"ETH\",\n        \"XTZ\"\n      ],\n      \"prefixed\": [\n        \"XETH\",\n        \"XTZ\"\n      ],\n      \"book\": \"XTZETH\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XTZ\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XTZ\"\n      ],\n      \"book\": \"XTZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XTZ\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XTZ\"\n      ],\n      \"book\": \"XTZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 4,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"XTZ\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XTZ\"\n      ],\n      \"book\": \"XTZXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 7,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"XBT\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"XXBT\"\n      ],\n      \"book\": \"XXBTZCAD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XBT\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XXBT\"\n      ],\n      \"book\": \"XXBTZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"GBP\",\n        \"XBT\"\n      ],\n      \"prefixed\": [\n        \"ZGBP\",\n        \"XXBT\"\n      ],\n      \"book\": \"XXBTZGBP\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"XBT\"\n      ],\n      \"prefixed\": [\n        \"ZJPY\",\n        \"XXBT\"\n      ],\n      \"book\": \"XXBTZJPY\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 0,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XBT\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XXBT\"\n      ],\n      \"book\": \"XXBTZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.002\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 1,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"XDG\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XXDG\"\n      ],\n      \"book\": \"XXDGXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"3000\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 8,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"XLM\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XXLM\"\n      ],\n      \"book\": \"XXLMXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 8,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XLM\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XXLM\"\n      ],\n      \"book\": \"XXLMZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XLM\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XXLM\"\n      ],\n      \"book\": \"XXLMZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"XMR\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XXMR\"\n      ],\n      \"book\": \"XXMRXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 6,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XMR\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XXMR\"\n      ],\n      \"book\": \"XXMRZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XMR\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XXMR\"\n      ],\n      \"book\": \"XXMRZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.1\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"XRP\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XXRP\"\n      ],\n      \"book\": \"XXRPXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 8,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"XRP\"\n      ],\n      \"prefixed\": [\n        \"ZCAD\",\n        \"XXRP\"\n      ],\n      \"book\": \"XXRPZCAD\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"XRP\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XXRP\"\n      ],\n      \"book\": \"XXRPZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"XRP\"\n      ],\n      \"prefixed\": [\n        \"ZJPY\",\n        \"XXRP\"\n      ],\n      \"book\": \"XXRPZJPY\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XRP\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XXRP\"\n      ],\n      \"book\": \"XXRPZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"30\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ZEC\"\n      ],\n      \"prefixed\": [\n        \"XXBT\",\n        \"XZEC\"\n      ],\n      \"book\": \"XZECXXBT\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 5,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ZEC\"\n      ],\n      \"prefixed\": [\n        \"ZEUR\",\n        \"XZEC\"\n      ],\n      \"book\": \"XZECZEUR\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"JPY\",\n        \"ZEC\"\n      ],\n      \"prefixed\": [\n        \"ZJPY\",\n        \"XZEC\"\n      ],\n      \"book\": \"XZECZJPY\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 3,\n      \"amountPrecision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"ZEC\"\n      ],\n      \"prefixed\": [\n        \"ZUSD\",\n        \"XZEC\"\n      ],\n      \"book\": \"XZECZUSD\",\n      \"minimalOrder\": {\n        \"amount\": \"0.03\",\n        \"unit\": \"asset\"\n      },\n      \"pricePrecision\": 2,\n      \"amountPrecision\": 8\n    }\n  ]\n}"
  },
  {
    "path": "exchange/wrappers/kraken.js",
    "content": "const Kraken = require('kraken-api');\nconst moment = require('moment');\nconst _ = require('lodash');\nconst exchangeUtils = require('../exchangeUtils');\nconst retry = exchangeUtils.retry;\nconst scientificToDecimal = exchangeUtils.scientificToDecimal;\n\nconst marketData = require('./kraken-markets.json');\n\nconst Trader = function(config) {\n  _.bindAll(this);\n\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency.toUpperCase()\n    this.asset = config.asset.toUpperCase();\n  }\n\n  this.name = 'kraken';\n  this.since = null;\n  \n  this.market = _.find(Trader.getCapabilities().markets, (market) => {\n    return market.pair[0] === this.currency && market.pair[1] === this.asset\n  });\n  this.pair = this.market.book;\n\n  this.interval = 3100;\n\n  this.kraken = new Kraken(\n    this.key,\n    this.secret,\n    {timeout: +moment.duration(60, 'seconds')}\n  );\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  'Service:Unavailable',\n  'Request timed out',\n  'Empty response',\n  'API:Invalid nonce',\n  'General:Temporary lockout',\n  'Response code 525',\n  'Service:Busy'\n];\n\n// errors that might mean\n// the API call succeeded.\nconst unknownResultErrors = [\n  'Response code 502',\n  'Response code 504',\n  'Response code 522',\n  'Response code 520',\n]\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.handleResponse = function(funcName, callback, nonMutating, payload) {\n  return (error, body) => {\n\n    if(!error && !body) {\n      error = new Error('Empty response');\n    }\n\n    if(error) {\n      if(includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n      }\n\n      if(includes(error.message, ['Rate limit exceeded'])) {\n        error.notFatal = true;\n        error.backoffDelay = 2500;\n      }\n\n      if(nonMutating && includes(error.message, unknownResultErrors)) {\n        // this call only tried to retrieve data, safe to redo\n        error.notFatal = true;\n      }\n\n      if(funcName === 'addOrder' && includes(error.message, unknownResultErrors)) {\n\n        const { tradeType, amount, price } = payload;\n\n        return setTimeout(() => {\n          this.getRawOpenOrders((err2, orders) => {\n            if(err2) {\n              console.log('err2', err2);\n              return callback(err2);\n            }\n\n            _.each(orders, (o, id) => {\n              o.id = id;\n            });\n\n            const order = _.find(orders, o => {\n              if(o.descr.type !== tradeType) {\n                return false;\n              }\n\n              const ts = moment.unix((o.opentm + '').split('.')[0])\n              if(moment().diff(ts, 'm') > 10) {\n                return false;\n              }\n\n              // string vs float\n              if(+o.descr.price != price) {\n                return false;\n              }\n\n              // string vs float\n              if(o.vol != amount) {\n                return false;\n              }\n\n              return true;\n            });\n\n            if(!order) {\n              console.log('broken add order, appears not created:', {payload, orders: JSON.stringify(orders)});\n              return this.addOrder(tradeType, amount, price, callback);\n            }\n\n            return callback(undefined, { catched: true, id: order.id });\n          });\n        }, 5000);\n      }\n\n      if(funcName === 'cancelOrder' && includes(error.message, unknownResultErrors)) {\n        console.log('broken cancel');\n\n        return setTimeout(() => {\n          const handle = (err2, data) => {\n            if(err2) {\n              console.log('err2', err2);\n              return callback(err2);\n            }\n\n            const order = _.get(data, `result[\"${payload}\"]`);\n\n            if(!_.isObject(order)) {\n              console.log('refetched broken cancel, cannot find order...', data);\n              throw 'a';\n            }\n\n            console.log(order);\n\n            if(order.status !== 'canceled') {\n              console.log(new Date, 'it still exists, retrying cancel');\n              return this.cancelOrder(payload, callback);\n            }\n\n            console.log(new Date, 'it was canceled');\n            return callback(undefined, true, { catched: true, filled: parseFloat(order.vol_exec) });\n\n          };\n\n          const reqData = {txid: payload};\n\n          const fetch = cb => this.kraken.api('QueryOrders', reqData, this.handleResponse('checkOrder', cb, true));\n          retry(null, fetch, handle);\n        }, 5000);\n      }\n\n      return callback(error);\n    }\n\n    return callback(undefined, body);\n  }\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const startTs = since ? moment(since).valueOf() : null;\n\n  const handle = (err, trades) => {\n    if (err) return callback(err);\n\n    var parsedTrades = [];\n    _.each(trades.result[this.pair], function(trade) {\n      // Even when you supply 'since' you can still get more trades than you asked for, it needs to be filtered\n      if (_.isNull(startTs) || startTs < moment.unix(trade[2]).valueOf()) {\n        parsedTrades.push({\n          tid: moment.unix(trade[2]).valueOf() * 1000000,\n          date: parseInt(Math.round(trade[2]), 10),\n          price: parseFloat(trade[0]),\n          amount: parseFloat(trade[1])\n        });\n      }\n    }, this);\n\n    if(descending)\n      callback(undefined, parsedTrades.reverse());\n    else\n      callback(undefined, parsedTrades);\n  };\n\n  const reqData = {\n    pair: this.pair\n  };\n\n  if(since) {\n    // Kraken wants a tid, which is found to be timestamp_ms * 1000000 in practice. No clear documentation on this though\n    reqData.since = startTs * 1000000;\n  }\n\n  const fetch = cb => this.kraken.api('Trades', reqData, this.handleResponse('getTrades', cb, true));\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const handle = (err, data) => {\n    if(err) return callback(err);\n\n    let assetAmount = parseFloat( data.result[this.market.prefixed[1]] );\n    let currencyAmount = parseFloat( data.result[this.market.prefixed[0]] );\n\n    if(!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      console.log(`Kraken did not return portfolio for ${this.asset}, assuming 0.`);\n      assetAmount = 0;\n    }\n\n    if(!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      console.log(`Kraken did not return portfolio for ${this.currency}, assuming 0.`);\n      currencyAmount = 0;\n    }\n\n    const portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n\n    return callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.kraken.api('Balance', {}, this.handleResponse('getPortfolio', cb, true));\n  retry(null, fetch, handle);\n};\n\n// This assumes that only limit orders are being placed with standard assets pairs\n// It does not take into account volume discounts.\n// Base maker fee is 0.16%, taker fee is 0.26%.\nTrader.prototype.getFee = function(callback) {\n  const makerFee = 0.16;\n  callback(undefined, makerFee / 100);\n};\n\nTrader.prototype.getTicker = function(callback) {\n  const handle = (err, data) => {\n    if (err) return callback(err);\n\n    const result = data.result[this.pair];\n    const ticker = {\n      ask: result.a[0],\n      bid: result.b[0]\n    };\n    callback(undefined, ticker);\n  };\n\n  const reqData = {pair: this.pair}\n  const fetch = cb => this.kraken.api('Ticker', reqData, this.handleResponse('getTicker', cb, true));\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.roundAmount = function(amount) {\n  return _.floor(amount, this.market.amountPrecision);\n};\n\nTrader.prototype.roundPrice = function(amount) {\n  return scientificToDecimal(_.round(amount, this.market.pricePrecision));\n};\n\nTrader.prototype.addOrder = function(tradeType, amount, price, callback) {\n  price = this.roundPrice(price); // only round price, not amount\n\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    let txid;\n\n    if(data.catched) {\n      // handled timeout, but order was created\n      txid = data.id;\n    } else if(_.isString(data)) {\n      // handled timeout, order was NOT created\n      txid = data;\n    } else {\n      // normal flow\n      txid = data.result.txid[0];\n    }\n\n    callback(undefined, txid);\n  };\n\n  const reqData = {\n    pair: this.pair,\n    type: tradeType.toLowerCase(),\n    ordertype: 'limit',\n    price: price,\n    volume: amount\n  };\n\n  const fetch = cb => this.kraken.api('AddOrder', reqData, this.handleResponse('addOrder', cb, false, { tradeType, amount, price }));\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.addOrder('buy', amount, price, callback);\n};\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.addOrder('sell', amount, price, callback);\n};\n\n\nTrader.prototype.getOrder = function(order, callback) {\n  const handle = (err, data) => {\n    if(err) return callback(err);\n\n    const price = parseFloat( data.result[ order ].price );\n    const amount = parseFloat( data.result[ order ].vol_exec );\n    const date = moment.unix( data.result[ order ].closetm );\n\n    // TODO: figure out fees, kraken is reporting 0 fees:\n    // { 'OF6L2D-6LIKD-4OOHR7':\n    //   { refid: null,\n    //     userref: 0,\n    //     status: 'closed',\n    //     reason: null,\n    //     opentm: 1530694339.8116,\n    //     closetm: 1530694402.9572,\n    //     starttm: 0,\n    //     expiretm: 0,\n    //     descr: [Object],\n    //     vol: '0.00500000',\n    //     vol_exec: '0.00500000',\n    //     cost: '27.9',\n    //     fee: '0',\n    //     price: '5595.0',\n    //     stopprice: '0.00000',\n    //     limitprice: '0.00000',\n    //     misc: '',\n    //     oflags: 'fciq' } } }\n\n    callback(undefined, {\n      price,\n      amount,\n      date,\n      feePercent: 0.16 // default for now\n    });\n  };\n\n  const reqData = {txid: order};\n\n  const fetch = cb => this.kraken.api('QueryOrders', reqData, this.handleResponse('getOrder', cb, true));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  const handle = (err, data) => {\n    if(err) return callback(err);\n\n    const result = data.result[order];\n\n    callback(undefined, {\n      executed: result.vol === result.vol_exec,\n      open: result.status === 'open',\n      filledAmount: +result.vol_exec\n    });\n  };\n\n  const reqData = {txid: order};\n\n  const fetch = cb => this.kraken.api('QueryOrders', reqData, this.handleResponse('checkOrder', cb, true));\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  const reqData = {txid: order};\n\n  const handle = (err, data) => {\n    if(err) {\n      if(err.message.includes('Unknown order')) {\n        return callback(undefined, true);\n      }\n\n      // catch race condition:\n      // if we cancel, that request times out\n      // we recheck: it's live BUT then the\n      // timeout request goes through nonetheless\n      // (only times out behind cloudflare)\n      if(err.message.includes('Invalid order')) {\n        return callback(undefined, true);\n      }\n\n      return callback(err)\n    }\n\n    if(data.filled) {\n      callback(undefined, false, data);\n    }\n\n    callback(undefined, false);\n  }\n\n  const fetch = cb => this.kraken.api('CancelOrder', reqData, this.handleResponse('cancelOrder', cb, false, order));\n  retry(null, fetch, handle);\n};\n\n\nTrader.prototype.getRawOpenOrders = function(callback) {\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err)\n    }\n\n    callback(undefined, data.result.open);\n  }\n\n  const fetch = cb => this.kraken.api('OpenOrders', {}, this.handleResponse('getOpenOrders', cb, true));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getOpenOrders = function(callback) {\n\n  this.getRawOpenOrders((err, allOrders) => {\n    if(err) {\n      console.log(err);\n\n      return callback(err)\n    }\n\n    const orders = [];\n\n    _.each(allOrders, (o, id) => {\n      if(o.descr.pair === this.pair) {\n        orders.push(id);\n      }\n    });\n\n    callback(undefined, orders);\n  });\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Kraken',\n    slug: 'kraken',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    tid: 'date',\n    tradable: true,\n    gekkoBroker: 0.6\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/lakebtc.js",
    "content": "var Lakebtc = require(\"lakebtc_nodejs\");\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n  }\n  this.name = 'LakeBTC';\n  this.balance;\n  this.price;\n\n  this.lakebtc = new Lakebtc(this.key, this.secret);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var set = function(err, data) {\n    var portfolio = [];\n    _.map(data.balance, function(amount, asset) {\n\t  portfolio.push({name: asset, amount: parseFloat(amount)});\n    });\n    callback(err, portfolio);\n  }\n  this.lakebtc.getAccountInfo(_.bind(set, this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  this.lakebtc.ticker(callback);\n}\n\nTrader.prototype.getFee = function(callback) {\n  callback(false, 0.002);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  var set = function(err, result) {\n    if(err || result.error)\n      return log.error('unable to buy:', err, result);\n\n    callback(null, result.id);\n  };\n\n  // TODO: fees are hardcoded here?\n  amount *= 0.998; // remove fees\n  // prevent: Ensure that there are no more than 4 digits in total.\n  amount *= 10000;\n  amount = Math.floor(amount);\n  amount /= 10000;\n  this.lakebtc.buyOrder(_.bind(set, this), [price, amount, 'USD']);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  var set = function(err, result) {\n    if(err || result.error)\n      return log.error('unable to sell:', err, result);\n\n    callback(null, result.id);\n  };\n\n  this.lakebtc.sell(_.bind(set, this), [price, amount, 'USD']);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var check = function(err, result) {\n    var stillThere = _.find(result, function(o) { return o.id === order });\n    callback(err, !stillThere);\n  };\n\n  this.lakebtc.getOrders(_.bind(check, this));\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var cancel = function(err, result) {\n    if(err || !result.result)\n      log.error('unable to cancel order', order, '(', err, result, ')');\n  };\n\n  this.lakebtc.cancelOrder(_.bind(cancel, this), [order]);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n    callback(null, descending ? result.reverse() : result);\n  };\n  since = since ? since.unix() : moment().subtract(5, 'minutes').unix();\n  this.lakebtc.bctrades( _.bind(process, this), since);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'LakeBTC',\n    slug: 'lakebtc',\n    currencies: ['USD'],\n    assets: ['BTC'],\n    markets: [\n      {\n        pair: ['USD', 'BTC'], minimalOrder: { amount: 1, unit: 'currency' }\n      }\n    ],\n    requires: ['key', 'secret'],\n    providesHistory: false,\n    fetchTimespan: 60,\n    tid: 'tid'\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/luno.js",
    "content": "const Luno = require(\"bitx\");\nconst _ = require('lodash');\nconst moment = require('moment');\nconst node_util = require('util');\nconst Errors = require('../exchangeErrors');\nconst retry = require('../exchangeUtils').retry;\nconst name = 'Luno';\n\nvar tradeAttempt = 0;\n\nconst Trader = function(config) {\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency;\n    this.asset = config.asset;\n    this.pair = config.asset + config.currency;\n  }\n  this.luno = new Luno(this.key, this.secret, {\n    pair: this.pair\n  });\n  this.market = _.find(Trader.getCapabilities().markets, (market) => {\n    return market.pair[0] === this.currency && market.pair[1] === this.asset;\n  });\n  this.interval = 2000;\n}\n\nconst log = function() {\n  const message = node_util.format.apply(null, _.toArray(arguments));\n  console.log(moment().format('YYYY-MM-DD HH:mm:ss') + ' (DEBUG):    ' + message);\n}\n\nTrader.prototype.inspect = function(obj) {\n  return node_util.inspect(obj, {\n    showhidden: false,\n    depth: null,\n    breakLength: Infinity,\n    colors: true\n  });\n};\n\nconst setPrecision = (amount, digits) => {\n  let precision = 100000000;\n  if (Number.isInteger(digits)) precision = Math.pow(10, digits);\n  amount *= precision;\n  amount = Math.floor(amount);\n  amount /= precision;\n  return amount;\n}\n\nconst round = (value, decimals = 14) => {\n  return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);\n}\n\nconst includes = (str, list) => {\n  if (!_.isString(str))\n    return false;\n  let result = _.some(list, item => str.includes(item));\n  return result;\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND'\n];\n\n\nconst processResponse = function(funcName, callback) {\n  return (error, body) => {\n    /* BitX Error Codes\n          Error: BitX error 400: invalid id\n          Error: BitX error 401: \"error\":\"API key not found\",\"error_code\":\"ErrAPIKeyNotFound\",\"error_action\":\n          Error: BitX error 429: -- API limit\n          Error: BitX error 500: Something went wrong, we're looking into it.\n     */\n\n    if (!error && !body) {\n      error = new Error('received empty response');\n    }\n\n    if (error) {\n      log(name, funcName + '() received error -->', error.message);\n\n      if (includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n      }\n\n      if (includes(error.message, ['error 429'])) {\n        error.notFatal = true;\n        error.backoffDelay = 3000;\n      }\n\n      if (includes(error.message, ['error 500'])) {\n        error.notFatal = true;\n        error.backoffDelay = 15000;\n      }\n\n      if (includes(error.message, ['Insufficient balance'])) {\n        error.notFatal = true;\n        error.backoffDelay = 2000;\n        tradeAttempt++;\n        if (tradeAttempt >= 3) {\n          error.notFatal = false;\n          log(name, funcName + '() giving up after 3 failed attempts.');\n        }\n      }\n\n      return callback(error, undefined);\n    }\n\n    return callback(undefined, body);\n  }\n};\n\n//------- Gekko Functions ---------//\n\nTrader.prototype.getTicker = function(callback) {\n  // log(name, 'getTicker()');\n\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    const ticker = {\n      ask: data.ask,\n      bid: data.bid,\n      spread: round(data.ask - data.bid)\n    };\n    log(name, 'getTicker() -->', this.inspect(ticker));\n    callback(undefined, ticker);\n  };\n\n  const handler = cb => this.luno.getTicker(processResponse('getTicker', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.getFee = function(callback) {\n  // log(name, 'getFee()');\n\n  if (this.pair === 'ETHXBT')\n    return callback(undefined, 0.000025);\n  else if (this.pair === 'XBTIDR')\n    return callback(undefined, 0.00002);\n  else\n    return callback(undefined, 0.0001);\n\n  /*\n  const process = (err, data) => {\n    if (err) {\n      // log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    // log(name, 'getFee() --> fee:', data.taker_fee / 100);\n    callback(undefined, data.taker_fee / 100);\n  };\n  const handler = cb => this.luno.getFee(processResponse('getFee', cb));\n  retry(null, handler, process);\n  */\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  // log(name, 'getPortfolio()');\n\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    const assetProfile = _.find(data.balance, a => a.asset === this.asset);\n    const currencyProfile = _.find(data.balance, a => a.asset === this.currency);\n    let assetAmount = round(assetProfile.balance - assetProfile.reserved);\n    let currencyAmount = round(currencyProfile.balance - currencyProfile.reserved);\n\n    if (!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      assetAmount = 0;\n    }\n\n    if (!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      currencyAmount = 0;\n    }\n\n    const portfolio = [{\n        name: this.asset.toUpperCase(),\n        amount: assetAmount\n      },\n      {\n        name: this.currency.toUpperCase(),\n        amount: currencyAmount\n      }\n    ];\n    log(name, 'getPortfolio() --> ' + this.inspect(portfolio));\n    callback(undefined, portfolio);\n  };\n\n  const handler = cb => this.luno.getBalance(processResponse('getPortfolio', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  log(name, 'buy() amount:', amount, 'price:', price);\n\n  tradeAttempt = 0;\n  amount = round(amount);\n  price = round(price);\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'unable to buy:', err.message);\n      return callback(err);\n    }\n    log(name, 'buy() order id: -->', data.order_id);\n    callback(undefined, data.order_id);\n  };\n\n  const handler = cb => this.luno.postBuyOrder(amount, price, processResponse('buy', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  log(name, 'sell() amount:', amount, 'price:', price);\n\n  tradeAttempt = 0;\n  amount = round(amount);\n  price = round(price);\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'unable to sell:', err.message);\n      return callback(err);\n    }\n    log(name, 'sell() order id: -->', data.order_id);\n    callback(undefined, data.order_id);\n  };\n\n  const handler = cb => this.luno.postSellOrder(amount, price, processResponse('sell', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  amount = setPrecision(amount, this.market.precision);\n  return amount;\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return +price;\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n  // log(name, 'getOrder() order id:', order);\n\n  if (!order) {\n    return callback('invalid order_id', false);\n  }\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    const price = parseFloat(data.limit_price);\n    const amount = parseFloat(data.base);\n    let date = moment();\n    const fees = {\n      [this.asset]: +data.fee_base,\n      [this.currency]: +data.fee_counter\n    };\n    const feePercent = round(data.fee_base / data.base * 100, 2);\n    if (data.state === 'PENDING') {\n      date = moment(data.creation_timestamp);\n    } else {\n      date = moment(data.completed_timestamp);\n    }\n    const result = {\n      price,\n      amount,\n      date,\n      fees,\n      feePercent\n    };\n    log(name, 'getOrder() -->', this.inspect(result));\n    callback(undefined, result);\n  };\n\n  const handler = cb => this.luno.getOrder(order, processResponse('getOrder', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  // log(name, 'checkOrder() order id:', order);\n\n  if (!order) {\n    return callback('invalid order_id');\n  }\n  const process = (err, data) => {\n    if (err) {\n      log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    const result = {\n      open: data.state === 'PENDING',\n      executed: data.limit_volume === data.base,\n      filledAmount: +data.base,\n      remaining: round(+data.limit_volume - +data.base)\n    }\n    log(name, 'checkOrder()', order, 'result:', this.inspect(result));\n    callback(undefined, result);\n  };\n\n  const handler = cb => this.luno.getOrder(order, processResponse('checkOrder', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  log(name, 'cancelOrder() order id:', order);\n\n  if (!order) {\n    return callback('invalid order_id');\n  }\n  const process = (err, data) => {\n    if (err) {\n      if (_.includes(err.message, 'Cannot stop unknown')) {\n        log(name, 'unable to cancel order:', order, '(' + err.message + ') assuming success...');\n      } else {\n        log(name, 'unable to cancel order:', order, '(' + err.message + ') aborting...');\n        return callback(err);\n      }\n    }\n\n    if (data && !data.success) {\n      log('cancelOrder() --> status:', data.success);\n      return callback(undefined, false);\n    }\n\n    this.checkOrder(order, (error, orderStatus) => {\n      if (error) {\n        log(name, 'cancelOrder\\'s checkOrder failed. What do i do here?');\n        return callback(error, false);\n      }\n\n      if (orderStatus.executed) {\n        log(name, 'cancelOrder() -->', order, 'was fulfilled before cancelOrder was completed.');\n        return callback(undefined, true);\n      }\n      const remaining = {\n        remaining: orderStatus.remaining,\n        filled: orderStatus.filledAmount\n      }\n      log(name, 'cancelOrder() --> status: false remaining:', this.inspect(remaining));\n      return callback(undefined, false, remaining);\n    });\n  }\n\n  const handler = cb => this.luno.stopOrder(order, processResponse('cancelOrder', cb));\n  retry(null, handler, process);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  // log(name, 'getTrades() since:', since);\n\n  const process = (err, result) => {\n    if (err) {\n      log(name, 'Error: -->', err);\n      return callback(err);\n    }\n    let trades = _.map(result.trades, (t) => {\n      return {\n        price: t.price,\n        date: Math.round(t.timestamp / 1000),\n        amount: t.volume,\n        tid: t.timestamp\n      }\n    });\n    if (!descending) {\n      trades = trades.reverse()\n    }\n    callback(undefined, trades);\n  };\n\n  if (moment.isMoment(since)) since = since.valueOf();\n  (_.isNumber(since) && since > 0) ? since: since = 0;\n\n  const options = {\n    pair: this.pair,\n    since: since\n  }\n\n  const handler = cb => this.luno.getTrades(options, processResponse('getTrades', cb));\n  retry(null, handler, process);\n}\n\nTrader.getCapabilities = function() {\n  return {\n    name: 'Luno',\n    slug: 'luno',\n    currencies: ['MYR', 'KES', 'NGN', 'ZAR', 'XBT'],\n    assets: ['ETH', 'XBT'],\n    markets: [\n      { pair: ['XBT', 'ETH'], minimalOrder: { amount: 0.01,   unit: 'asset' }, precision: 2 },\n      { pair: ['MYR', 'XBT'], minimalOrder: { amount: 0.0005, unit: 'asset' }, precision: 6 },\n      { pair: ['KES', 'XBT'], minimalOrder: { amount: 0.0005, unit: 'asset' }, precision: 6 },\n      { pair: ['NGN', 'XBT'], minimalOrder: { amount: 0.0005, unit: 'asset' }, precision: 6 },\n      { pair: ['ZAR', 'XBT'], minimalOrder: { amount: 0.0005, unit: 'asset' }, precision: 6 },\n    ],\n    requires: ['key', 'secret'],\n    providesFullHistory: true,\n    providesHistory: 'date',\n    // maxHistoryFetch: 100,\n    tid: 'tid',\n    tradable: true,\n    forceReorderDelay: true,\n    gekkoBroker: 0.6\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/mexbt.js.old",
    "content": "var Mexbt = require(\"mexbt\");\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.userId = config.username;\n    this.pair = config.asset || this.currency;\n  }\n  this.name = 'meXBT';\n  this.mexbt = new Mexbt(this.key, this.secret, this.userId);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var set = function(err, data) {\n    var portfolio = [];\n    _.each(data.currencies, function(balanceInfo) {\n      portfolio.push({name: balanceInfo.name, amount: balanceInfo.balance});\n    });\n    callback(err, portfolio);\n  }\n  this.mexbt.accountBalance(_.bind(set, this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  this.mexbt.ticker(callback);\n}\n\nTrader.prototype.getFee = function(callback) {\n  var set = function(err, data) {\n    if(err)\n      callback(err);\n\n    callback(false, data.fee);\n  }\n  this.mexbt.getTradingFee({amount: 1, type: 'limit'}, _.bind(set, this));\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  var set = function(err, result) {\n    if(err || result.error)\n      return log.error('unable to buy:', err, result);\n\n    callback(null, result.serverOrderId);\n  };\n\n  this.mexbt.createOrder({amount: amount, price: price, side: 'buy', type: 'limit'}, _.bind(set, this));\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  var set = function(err, result) {\n    if(err || result.error)\n      return log.error('unable to sell:', err, result);\n\n    callback(null, result.serverOrderId);\n  };\n\n  this.mexbt.createOrder({amount: amount, price: price, side: 'sell', type: 'limit'}, _.bind(set, this));\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var currentPair = this.pair;\n\n  var check = function(err, result) {\n    var ordersForPair = _.find(result, function(o) { return o.ins === currentPair});\n    var stillThere = _.find(ordersForPair.openOrders, function(o) { return o.ServerOrderId === order });\n    callback(err, !stillThere);\n  };\n\n  this.mexbt.accountOrders(_.bind(check, this));\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var cancel = function(err, result) {\n    if(err || !result)\n      log.error('unable to cancel order', order, '(', err, result, ')');\n  };\n\n  this.mexbt.cancelOrder({id: order}, _.bind(cancel, this));\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n    trades = _.map(result.trades, function (t) {\n      return {tid: t.tid, price: t.px, date: t.unixtime, amount: t.qty};\n    });\n    if (descending) {\n      trades = trades.reverse()\n    }\n    callback(null, trades);\n  }.bind(this);\n\n  var endDate = moment().unix();\n\n  // FIXME: there is a bug in meXBT tradesByDate function, that it doesnt return all data\n  // when trying to fetch all.\n  // So if no since, we just fetch all via trades and giving a high count\n  if (since) {\n    this.mexbt.tradesByDate({startDate: since.unix(), endDate: endDate}, process);\n  } else {\n    // improvised\n    this.mexbt.trades({count: 1000}, process);\n  }\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'meXBT',\n    slug: 'mexbt',\n    currencies: ['MXN'],\n    assets: ['BTC'],\n    markets: [\n      {\n        pair: ['MXN', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' }\n      }\n    ],\n    requires: ['key', 'secret', 'username'],\n    providesHistory: 'date',\n    tid: 'tid'\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/mtgox.js.old",
    "content": "// HERE FOR HISTORICAL PURPOSES\n\nvar MtGoxClient = require(\"mtgox-apiv2\");\nvar _ = require('lodash');\nvar moment = require('moment');\nvar util = require('../core/util.js');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency || 'USD';\n\n    this.pair = 'BTC' + this.currency;\n  }\n  this.name = 'Mt. Gox';\n\n  _.bindAll(this);\n\n  this.mtgox = new MtGoxClient(this.key, this.secret, this.pair);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  var process = function(err, result) {\n    this.checkUnauthorized(err);\n    // if Mt. Gox is down or lagging\n    if(err || result.result === 'error')\n      log.error('unable to buy (', err, result, ')');\n\n    callback(null, result.data);\n  };\n  this.mtgox.add('bid', amount, price, _.bind(process, this));\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  var process = function(err, result) {\n    this.checkUnauthorized(err);\n    // if Mt. Gox is down or lagging\n    if(err || result.result === 'error')\n      log.error('unable to sell (', err, result, ')');\n\n    callback(null, result.data);\n  };\n  this.mtgox.add('ask', amount, price, _.bind(process, this));\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  if(since && !_.isNumber(since))\n    since = util.toMicro(since);\n\n  var args = _.toArray(arguments);\n  this.mtgox.fetchTrades(since, _.bind(function(err, trades) {\n    if (err || !trades)\n      return this.retry(this.getTrades, args);\n\n    trades = trades.data;\n    if (trades.length === 0)\n      return this.retry(this.getTrades, args);\n\n    if(descending)\n      callback(false, trades.reverse());\n    else\n      callback(false, trades);\n  }, this));\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait.\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.checkUnauthorized = function(err) {\n  if(err && err.message === 'Request failed with 403')\n    util.die('It appears your ' + this.name + ' API key and secret are incorrect');\n}\n\n// calls callback with the following data structure:\n//\n// [\n//  { name: 'BTC', amount: 10.12413123},\n//  { name: 'USD', amount: 500.0241},\n//  { name: 'EUR', amount: 0},\n// ]\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var calculate = function(err, result) {\n    this.checkUnauthorized(err);\n    if(err)\n      return this.retry(this.getPortfolio, args);\n\n    if(!('Wallets' in result.data))\n      log.error('unable to get portfolio, do I have get_info rights?');\n\n    var assets = [];\n    _.each(result.data.Wallets, function(wallet, name) {\n      var amount = parseFloat(wallet.Balance.value);\n      assets.push({name: name, amount: amount});\n    });\n    callback(null, assets);\n  };\n\n  this.mtgox.info(_.bind(calculate, this));\n}\n\nTrader.prototype.getFee = function(callback) {\n  var args = _.toArray(arguments);\n  var calculate = function(err, result) {\n    this.checkUnauthorized(err);\n    if(err)\n      return this.retry(this.getFee, args);\n\n    // convert the %\n    var fee = result.data.Trade_Fee / 100;\n    callback(null, fee);\n  };\n\n  this.mtgox.info(_.bind(calculate, this));\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  // we can't just request the order id\n  // @link https://bitbucket.org/nitrous/mtgox-api/#markdown-header-moneyorderresult\n  var check = function(err, result) {\n    if(err)\n      return this.retry(this.checkOrder, args);\n\n    var stillThere = _.find(result.data, function(o) { return o.oid === order });\n    callback(null, !stillThere);\n  };\n\n  this.mtgox.orders(_.bind(check, this));\n}\n\nTrader.prototype.cancelOrder = function(order) {\n  var cancel = function(err, result) {\n    if(err || result.result !== 'succes')\n      log.error('unable to cancel order', order, '(', err, result, ')');\n  };\n\n  this.mtgox.cancel(order, _.bind(cancel, this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, result) {\n    if(err)\n      return this.retry(this.getTicker, args);\n\n    var ticker = {\n      bid: result.data.buy.value,\n      ask: result.data.sell.value\n    }\n    callback(err, ticker);\n  };\n\n  this.mtgox.ticker(_.bind(set, this));\n}\n\nTrader.getCapabilities = function () {\n  return {};\n  // ---- Keeping this here for historical purposes. ----\n  // {\n  //\n  //   name: 'MtGox',\n  //   slug: 'mtgox',\n  //   direct: true,\n  //   infinityOrder: true,\n  //   currencies: [\n  //     'USD', 'EUR', 'GBP', 'AUD', 'CAD', 'CHF', 'CNY',\n  //     'DKK', 'HKD', 'PLN', 'RUB', 'SGD', 'THB'\n  //   ],\n  //   assets: ['BTC'],\n  //   markets: [\n  //     { pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['EUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['GBP', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['AUD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['CAD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['CHF', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['CNY', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['DKK', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['HKD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['PLN', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['RUB', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['SGD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n  //     { pair: ['THB', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } }\n  //   ],\n  //   requires: ['key', 'secret'],\n  //   providesHistory: false\n  // }\n}\n\nmodule.exports = Trader;\n\n"
  },
  {
    "path": "exchange/wrappers/okcoin.js.old",
    "content": "var OKCoin = require('okcoin-china');\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n  }\n    this.pair = [config.asset, config.currency].join('_').toLowerCase();\n    this.name = 'okcoin';\n    this.okcoin = new OKCoin(this.key, this.secret);\n    this.lastTid = false;\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n    var wait = +moment.duration(10, 'seconds');\n    log.debug(this.name, 'returned an error, retrying..');\n\n    var self = this;\n\n    // make sure the callback (and any other fn)\n    // is bound to Trader\n    _.each(args, function(arg, i) {\n        if (_.isFunction(arg))\n            args[i] = _.bind(arg, self);\n    });\n\n    // run the failed method again with the same\n    // arguments after wait\n    setTimeout(\n        function() {\n            method.apply(self, args)\n        },\n        wait\n    );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var calculate = function(err, data) {\n    if(err) {\n      if(err.message === 'invalid api key')\n        util.die('Your ' + this.name + ' API keys are invalid');\n      return this.retry(this.okcoin.getUserInfo, calculate);\n    }\n\n    var portfolio = [];\n    _.each(data.info.funds.free, function(amount, asset) {\n      portfolio.push({name: asset.toUpperCase(), amount: +amount});\n    });\n\n    callback(err, portfolio);\n  }.bind(this);\n\n  this.okcoin.getUserInfo(calculate);\n}\n\nTrader.prototype.getTicker = function(callback) {\n    var args = [this.pair, process];\n    var process = function(err, data) {\n        if (err)\n            return this.retry(this.okcoin.getTicker(args));\n\n        var ticker = _.extend(data.ticker, {\n            bid: +data.ticker.sell,\n            ask: +data.ticker.buy\n        });\n\n        callback(err, ticker);\n    }.bind(this);\n\n    this.okcoin.getTicker(process, args);\n}\n\n// This assumes that only limit orders are being placed, so fees are the\n// \"maker fee\" of 0.1%.  It does not take into account volume discounts.\nTrader.prototype.getFee = function(callback) {\n    var makerFee = 0.1;\n    callback(false, makerFee / 100);\n}\n\nTrader.prototype.buy = function(raw_amount, price, callback) {\n  var amount = Math.floor(raw_amount * 10000) / 10000\n  var set = function(err, result) {\n    if(err)\n      return log.error('unable to process order:', err, result);\n\n    callback(null, result.order_id);\n  }.bind(this);\n\n  this.okcoin.addTrade(set, this.pair, 'buy', amount, price);\n}\n\nTrader.prototype.sell = function(raw_amount, price, callback) {\n  var amount = Math.floor(raw_amount * 10000) / 10000\n  var set = function(err, result) {\n    if(err)\n      return log.error('unable to process order:', err, result);\n\n    callback(null, result.order_id);\n  }.bind(this);\n\n  this.okcoin.addTrade(set, this.pair, 'sell', amount, price);\n}\n\n\nTrader.prototype.checkOrder = function(order_id, callback) {\n  var check = function(err, result) {\n    if(err || !result.result) {\n      log.error('Perhaps the order already got filled?', '(', result, ')');\n      callback(err, !result.result);\n    } else {\n      callback(err, true);\n    }\n  }\n\n  this.okcoin.getOrderInfo(check, this.pair, order_id);\n}\n\nTrader.prototype.cancelOrder = function(order_id, callback) {\n  var cancel = function(err, result) {\n    if(err || !result.result) {\n      return log.error('unable to cancel order ', order_id, '(', result, ')');\n    }\n\n    callback();\n  }.bind(this);\n\n  this.okcoin.cancelOrder(cancel, this.pair, order_id);\n}\n\nTrader.prototype.getOrder = function(order_id, callback) {\n\n  var handle = (err, resp) => {\n    var order = _.first(resp.orders);\n\n    var amount = order.deal_amount;\n    var price = order.price;\n    var date = moment(order.date).utc();\n\n    callback(undefined, {amount, price, date});\n  }\n\n  this.okcoin.getOrderInfo(handle, this.pair, order_id)\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n    var args = _.toArray(arguments);\n\n    if(since)\n      since = 600;\n\n    this.okcoin.getTrades(function(err, data) {\n        if (err)\n            return this.retry(this.getTrades, args);\n\n        var trades = _.map(data, function(trade) {\n            return {\n                price: +trade.price,\n                amount: +trade.amount,\n                tid: +trade.tid,\n                date: trade.date\n            }\n        });\n\n        callback(null, trades.reverse());\n    }.bind(this), this.pair, since);\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'OkCoin',\n    slug: 'okcoin',\n    currencies: ['BTC', 'CNY'],\n    assets: ['BTC', 'LTC'],\n    markets: [\n      { pair: ['CNY', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n      { pair: ['CNY', 'LTC'], minimalOrder: { amount: 0.01, unit: 'asset' } }\n    ],\n    requires: ['key', 'secret', 'username'],\n    providesHistory: false,\n    fetchTimespan: 60,\n    tid: 'date',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;"
  },
  {
    "path": "exchange/wrappers/poloniex-markets.json",
    "content": "{\n\t\"currencies\": [\"BTC\", \"ETH\", \"XMR\", \"USDT\", \"USDC\"],\n\t\"assets\": [\n    \"1CR\", \"ABY\", \"AC\", \"ACH\", \"ADN\", \"AEON\", \"AERO\", \"AIR\", \"AMP\", \"APH\",\n    \"ARCH\", \"AUR\", \"AXIS\", \"BALLS\", \"BANK\", \"BBL\", \"BBR\", \"BCC\", \"BCH\", \"BCN\",\n    \"BCY\", \"BDC\", \"BDG\", \"BELA\", \"BITCNY\", \"BITS\", \"BITUSD\", \"BLK\", \"BLOCK\",\n    \"BLU\", \"BNS\", \"BONES\", \"BOST\", \"BTC\", \"BTCD\", \"BTCS\", \"BTM\", \"BTS\",\n    \"BURN\", \"BURST\", \"C2\", \"CACH\", \"CAI\", \"CC\", \"CCN\", \"CGA\", \"CHA\", \"CINNI\",\n    \"CLAM\", \"CNL\", \"CNMT\", \"CNOTE\", \"COMM\", \"CON\", \"CORG\", \"CRYPT\", \"CURE\",\n    \"CVC\", \"CYC\", \"DAO\", \"DASH\", \"DCR\", \"DGB\", \"DICE\", \"DIEM\", \"DIME\", \"DIS\", \"DNS\",\n    \"DOGE\", \"DRKC\", \"DRM\", \"DSH\", \"DVK\", \"EAC\", \"EBT\", \"ECC\", \"EFL\", \"EMC2\",\n    \"EMO\", \"ENC\", \"ETC\", \"ETH\", \"eTOK\", \"EXE\", \"EXP\", \"FAC\", \"FCN\", \"FCT\",\n    \"FIBRE\", \"FLAP\", \"FLDC\", \"FLO\", \"FLT\", \"FOX\", \"FRAC\", \"FRK\", \"FRQ\", \"GNO\",\n    \"FVZ\", \"FZ\", \"FZN\", \"GAME\", \"GAP\", \"GAS\", \"GDN\", \"GEMZ\", \"GEO\", \"GIAR\", \"GLB\",\n    \"GML\", \"GNS\", \"GNT\", \"GOLD\", \"GPC\", \"GPUC\", \"GRC\", \"GRCX\", \"GRS\", \"GUE\", \"H2O\",\n    \"HIRO\", \"HOT\", \"HUC\", \"HUGE\", \"HVC\", \"HYP\", \"HZ\", \"IFC\", \"INDEX\", \"IOC\",\n    \"ITC\", \"IXC\", \"JLH\", \"JPC\", \"JUG\", \"KDC\", \"KEY\", \"LBC\", \"LC\", \"LCL\",\n    \"LEAF\", \"LGC\", \"LOL\", \"LOVE\", \"LQD\", \"LSK\", \"LTBC\", \"LTC\", \"LTCX\",\n    \"MAID\", \"MAST\", \"MAX\", \"MCN\", \"MEC\", \"METH\", \"MIL\", \"MIN\", \"MINT\", \"MMC\",\n    \"MMNXT\", \"MMXIV\", \"MNTA\", \"MON\", \"MRC\", \"MRS\", \"MTS\", \"MUN\", \"MYR\",\n    \"MZC\", \"N5X\", \"NAS\", \"NAUT\", \"NAV\", \"NBT\", \"NEOS\", \"NL\", \"NMC\", \"NOBL\",\n    \"NOTE\", \"NOXT\", \"NRS\", \"NSR\", \"NTX\", \"NXT\", \"NXTI\", \"OMG\", \"OMNI\", \"OPAL\",\n    \"PAND\", \"PASC\", \"PAWN\", \"PIGGY\", \"PINK\", \"PLX\", \"PMC\", \"POT\", \"PPC\", \"PRC\",\n    \"PRT\", \"PTS\", \"Q2C\", \"QBK\", \"QCN\", \"QORA\", \"QTL\", \"RADS\", \"RBY\", \"RDD\", \"REP\",\n    \"RIC\", \"RZR\", \"SBD\", \"SC\", \"SDC\", \"SHIBE\", \"SHOPX\", \"SILK\", \"SJCX\",\n    \"SLR\", \"SMC\", \"SOC\", \"SPA\", \"SQL\", \"SRCC\", \"SRG\", \"SSD\", \"STEEM\", \"STR\",\n    \"SUM\", \"SUN\", \"SWARM\", \"SXC\", \"SYNC\", \"SYS\", \"TAC\", \"TOR\", \"TRUST\",\n    \"TWE\", \"UIS\", \"ULTC\", \"UNITY\", \"URO\", \"USDE\", \"USDT\", \"UTC\", \"UTIL\",\n    \"UVC\", \"VIA\", \"VOOT\", \"VOX\", \"VRC\", \"VTC\", \"WC\", \"WDC\", \"WIKI\", \"WOLF\",\n    \"X13\", \"XAI\", \"XAP\", \"XBC\", \"XC\", \"XCH\", \"XCN\", \"XCP\", \"XCR\", \"XDN\",\n    \"XDP\", \"XEM\", \"XHC\", \"XLB\", \"XMG\", \"XMR\", \"XPB\", \"XPM\", \"XRP\", \"XSI\",\n    \"XST\", \"XSV\", \"XUSD\", \"XVC\", \"XXC\", \"BCH\", \"YACC\", \"YANG\", \"YC\", \"YIN\", \"ZEC\",\n\t\t\"ZRX\", \"BCHSV\", \"BCHABC\"\n\t],\n\t\"markets\": [\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"1CR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ABY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ACH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ADN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AEON\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AERO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AIR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AMP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"APH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ARCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AUR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"AXIS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BALLS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BANK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BBL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BBR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BCC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BCY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BDC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BDG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BELA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BITCNY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BITS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BITUSD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BLK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BLOCK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BLU\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BNS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BONES\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BOST\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BTCD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BTCS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BTM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BTS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BURN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"BURST\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"C2\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CACH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CAI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CGA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CHA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CINNI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CLAM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CNL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CNMT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CNOTE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"COMM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CON\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CORG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CRYPT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CURE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CVC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"CYC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DAO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DASH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DCR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DGB\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DICE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DIEM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DIME\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DIS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DNS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DOGE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DRKC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DRM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DSH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"DVK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EAC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EBT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ECC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EFL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EMC2\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EMO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ENC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ETC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ETH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"eTOK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EXE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"EXP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FAC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FCT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FIBRE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FLAP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FLDC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FLO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FLT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FOX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FRAC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FRK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FRQ\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FVZ\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FZ\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"FZN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GAME\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GAP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GAS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GDN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GEMZ\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GEO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GIAR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GLB\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GML\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GNS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GOLD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GPC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GPUC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GRC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GRCX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GRS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"GUE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"H2O\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HIRO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HOT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HUC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HUGE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HVC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HYP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"HZ\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"IFC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"INDEX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"IOC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ITC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"IXC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"JLH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"JPC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"JUG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"KDC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"KEY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LBC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LCL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LEAF\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LGC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LOL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LOVE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LQD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LSK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LTBC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"LTCX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MAID\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MAST\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MAX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MEC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"METH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MIL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MIN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MINT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MMC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MMNXT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MMXIV\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MNTA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MON\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MRC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MRS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MTS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MUN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MYR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"MZC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"N5X\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NAS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NAUT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NAV\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NBT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NEOS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NMC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NOBL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NOTE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NOXT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NRS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NSR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NTX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NXT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"NXTI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"OMG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"OMNI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"OPAL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PAND\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PASC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PAWN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PIGGY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PINK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PLX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PMC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"POT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PPC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PRC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PRT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"PTS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"Q2C\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"QBK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"QCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"QORA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"QTL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"RADS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"RBY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"RDD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"REP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"RIC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"RZR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SBD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SDC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SHIBE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SHOPX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SILK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SJCX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SLR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SMC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SOC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SPA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SQL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SRCC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SRG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SSD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"STEEM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"STR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SUM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SUN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SWARM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SXC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SYNC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"SYS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"TAC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"TOR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"TRUST\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"TWE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"UIS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ULTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"UNITY\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"URO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"USDE\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"USDT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"UTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"UTIL\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"UVC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"VIA\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"VOOT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"VOX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"VRC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"VTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"WC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"WDC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"WIKI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"WOLF\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"X13\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XAI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XAP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XBC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XCP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XCR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XDN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XDP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XEM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XHC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XLB\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XMG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XMR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XPB\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XPM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XRP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XSI\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XST\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XSV\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XUSD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XVC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"XXC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"YACC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"YANG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"YC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"YIN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ZEC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"BTC\",\n\t      \"ZRX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"BTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"BCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"DASH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"ETC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"ETH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"LTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"NXT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"REP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"STR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"XMR\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"XRP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDT\",\n\t      \"ZEC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"CVC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"ETC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"BCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"GAS\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"GNO\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"GNT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"LSK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"OMG\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"REP\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"STEEM\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"ZEC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"ETH\",\n\t      \"ZRX\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"BCN\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"BLK\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"BTCD\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"DASH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"LTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"MAID\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"NXT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"XMR\",\n\t      \"ZEC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"BTC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t\t{\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"USDT\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"ETH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"BCHSV\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"BCHABC\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  },\n\t  {\n\t    \"pair\": [\n\t      \"USDC\",\n\t      \"BCH\"\n\t    ],\n\t    \"minimalOrder\": {\n\t      \"amount\": 0.0001,\n\t      \"unit\": \"asset\"\n\t    }\n\t  }\n\t]\n}"
  },
  {
    "path": "exchange/wrappers/poloniex.js",
    "content": "const Poloniex = require(\"gekko-broker-poloniex\");\nconst _ = require('lodash');\nconst moment = require('moment');\nconst retry = require('../exchangeUtils').retry;\nconst marketData = require('./poloniex-markets.json');\n\nconst Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.currency = config.currency;\n    this.asset = config.asset;\n  }\n  this.name = 'Poloniex';\n  this.balance;\n  this.price;\n\n  this.pair = this.currency + '_' + this.asset;\n\n  this.fillDataOnCancel = true;\n\n  this.poloniex = new Poloniex({\n    key: this.key,\n    secret: this.secret,\n    userAgent: 'Gekko Broker v' + require('../package.json').version\n  });\n}\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  '429',\n  '522',\n  '504',\n  '503',\n  '500',\n  '502',\n  'socket hang up',\n  'Empty response',\n  'Please try again in a few minutes.',\n  'Nonce must be greater than',\n  'Internal error. Please try again.',\n  'Connection timed out. Please try again.',\n  // getaddrinfo EAI_AGAIN poloniex.com poloniex.com:443\n  'EAI_AGAIN',\n  'ENETUNREACH',\n  'socket hang up'\n];\n\n// errors that might mean\n// the API call succeeded.\nconst unknownResultErrors = [\n  'ETIMEDOUT',\n]\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.outbidPrice = function(price, isUp) {\n  let newPrice;\n\n  const tickSize = 0.00000001;\n\n  if(isUp) {\n    newPrice = price + 0.00000001;\n  } else {\n    newPrice = price - tickSize;\n  }\n\n  return this.roundPrice(newPrice);\n}\n\nTrader.prototype.processResponse = function(next, fn, payload) {\n  // TODO: in very rare cases the callback is\n  // called twice (first on ETIMEDOUT later\n  // without error). Temp workaround.\n  next = _.once(next);\n\n  return (err, data) => {\n    let error;\n\n    if(err) {\n      if(err.message) {\n        error = err;\n      } else {\n        console.log('err but no message,', typeof err, {err, data});\n        error = new Error(err);\n      }\n    } else if(!data) {\n      error = new Error('Empty response');\n    } else if(data.error) {\n      error = new Error(data.error);\n    } else if(includes(data, ['Please complete the security check to proceed.'])) {\n      error = new Error(\n        'Your IP has been flagged by CloudFlare. ' +\n        'As such Gekko Broker cannot access Poloniex.'\n      );\n      data = undefined;\n    } else if(includes(data, ['Please try again in a few minutes.'])) {\n      error = new Error('Please try again in a few minutes.');\n      error.notFatal = true;\n      data = undefined;\n    } else if(includes(data, ['<!DOCTYPE html>'])) {\n      error = new Error(data);\n      data = undefined;\n    }\n\n    if(error) {\n\n      if(includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n      }\n\n      if(includes(error.message, ['Currently in maintenance mode.'])) {\n        console.log(new Date, '[Poloniex] Currently in maintenance mode. Retrying...');\n        error.notFatal = true;\n        error.backoffDelay = 1000;\n      }\n\n      // not actually an error, means order never executed against other trades\n      if(fn === 'getOrder' &&\n        error.message.includes('Order not found, or you are not the person who placed it.')\n      ) {\n        error = undefined;\n        data = { unfilled: true };\n        console.log(new Date, 'UNKNOWN ORDER!', payload);\n      }\n\n      if(fn === 'cancelOrder') {\n\n        // already filled\n        if(includes(error.message, ['Invalid order number, or you are not the person who placed the order.'])) {\n          console.log(new Date, 'cancelOrder invalid order');\n          error = undefined;\n          data = { filled: true };\n        }\n\n        // it might be cancelled\n        else if(includes(error.message, unknownResultErrors)) {\n          setTimeout(() => {\n            this.getRawOpenOrders((err, orders) => {\n              if(err) {\n                return next(err);\n              }\n\n              const order = _.find(orders, o => o.orderNumber == payload);\n\n              // the cancel did not work since the order still exists\n              if(order) {\n                error.notFatal = true;\n                return next(error);\n              }\n\n              // it was cancelled, we need to check filled amount..\n              console.log(new Date, '[CANCELFIX] process cancel response');\n              console.log('[CANCELFIX] rechecking fill')\n              setTimeout(() => {\n                this.getOrder(payload, (error, order) => {\n                  if(error) {\n                    return next(error)\n                  }\n\n                  console.log('[CANCELFIX] checked, got:', order);\n\n                  return next(undefined, { filled: order.amount });\n                });\n              }, this.checkInterval);\n            });\n\n          }, this.checkInterval);\n          return;\n        }\n      }\n\n      if(fn === 'order') {\n        if(includes(error.message, ['Not enough'])) {\n          error.retry = 2;\n        }\n\n        // we need to check whether the order was actually created\n        if(includes(error.message, unknownResultErrors)) {\n          return setTimeout(() => {\n            this.findLastOrder(10, payload, (err, lastTrade) => {\n              if(lastTrade) {\n                return next(undefined, lastTrade);\n              }\n\n              next(error);\n            });\n\n          }, this.checkInterval);\n        }\n      }\n    }\n\n    return next(error, data);\n  }\n}\n\nTrader.prototype.findLastOrder = function(since, side, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      return callback(err);\n    }\n\n    result = result.filter(t => t.type === side);\n\n    if(!result.length) {\n      return callback(undefined, undefined);\n    }\n\n    let order;\n    if(since) {\n      const threshold = moment().subtract(since, 'm');\n      order = _.find(result, o => moment.utc(o.date) > threshold);\n    } else {\n      order = _.last(result);\n    }\n\n    callback(undefined, order);\n  };\n\n  this.getRawOpenOrders(handle);\n}\n\nTrader.prototype.getRawOpenOrders = function(callback) {\n  const fetch = next => this.poloniex.returnOpenOrders(this.currency, this.asset, this.processResponse(next));\n  retry(null, fetch, callback);\n}\n\nTrader.prototype.getOpenOrders = function(callback) {\n  this.getRawOpenOrders((err, orders) => {\n    if(err) {\n      return callback(err);\n    }\n\n    console.log(orders);\n\n    const ids = orders.map(o => o.orderNumber);\n\n    return callback(undefined, ids);\n  })\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    var assetAmount = parseFloat( data[this.asset] );\n    var currencyAmount = parseFloat( data[this.currency] );\n\n    if(\n      !_.isNumber(assetAmount) || _.isNaN(assetAmount) ||\n      !_.isNumber(currencyAmount) || _.isNaN(currencyAmount)\n    ) {\n      assetAmount = 0;\n      currencyAmount = 0;\n    }\n\n    var portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n\n    callback(undefined, portfolio);\n  }\n\n  const fetch = next => this.poloniex.myBalances(this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getFullPortfolio = function(callback) {\n  const handle = (err, data) => {\n    if(err) {\n      return callback(err);\n    }\n\n    const asset = data[this.asset];\n    const currency = data[this.currency];\n\n    let assetAmount = parseFloat(asset.available) + parseFloat(asset.onOrders);\n    let currencyAmount = parseFloat(currency.available) + parseFloat(asset.onOrders);\n\n    if(!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      assetAmount = 0;\n    }\n\n    if(!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      currencyAmount = 0;\n    }\n\n    var portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n\n    callback(undefined, portfolio);\n  }\n\n  const fetch = next => this.poloniex.returnCompleteBalances(this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  const handle = (err, data) => {\n    if(err)\n      return callback(err);\n\n    var tick = data[this.pair];\n\n    callback(null, {\n      bid: parseFloat(tick.highestBid),\n      ask: parseFloat(tick.lowestAsk),\n    });\n  };\n\n\n  const fetch = next => this.poloniex.getTicker(this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getFee = function(callback) {\n  const handle = (err, data) => {\n    if(err)\n      return callback(err);\n\n    callback(undefined, parseFloat(data.makerFee));\n  }\n\n  const fetch = next => this.poloniex._private('returnFeeInfo', this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.roundAmount = function(amount) {\n  return _.floor(amount, 8);\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return +price;\n}\n\nTrader.prototype.isValidLot = function(price, amount) {\n  // Error: Total must be at least 0.0001.\n  return amount * price >= 0.0001;\n}\n\nTrader.prototype.createOrder = function(side, amount, price, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      console.log('createOrder', {side, amount, price});\n      return callback(err);\n    }\n\n    // console.log(new Date, 'PORDER created', result.orderNumber);\n\n    callback(undefined, result.orderNumber);\n  }\n\n  const fetch = next => {\n    this.poloniex[side](this.currency, this.asset, price, amount, this.processResponse(next, 'order', side))\n  };\n  retry(null, fetch, handle);  \n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.createOrder('buy', amount, price, callback);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.createOrder('sell', amount, price, callback);\n}\n\nTrader.prototype.checkOrder = function(id, callback) {\n  const handle = (err, result) => {\n\n    if(err) {\n      return callback(err);\n    }\n\n    if(result.completed) {\n      return callback(undefined, { executed: true, open: false });\n    }\n\n    const order = _.find(result, function(o) { return o.orderNumber === id });\n    if(!order) {\n      console.log(new Date, 'order not open', id, result);\n      // if the order is not open it's fully executed\n      return callback(undefined, { executed: true, open: false });\n    }\n\n    callback(undefined, { executed: false, open: true, filledAmount: order.startingAmount - order.amount });\n  }\n\n  const fetch = next => this.poloniex.myOpenOrders(this.currency, this.asset, this.processResponse(next, 'checkOrder'));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getOrder = function(order, callback) {\n  const handle = (err, result) => {\n    if(err)\n      return callback(err);\n\n    let price = 0;\n    let amount = 0;\n    let date = moment(0);\n\n    if(result.unfilled) {\n      return callback(null, {price, amount, date});\n    }\n\n    _.each(result, trade => {\n      date = moment(trade.date);\n      price = ((price * amount) + (+trade.rate * trade.amount)) / (+trade.amount + amount);\n      amount += +trade.amount;\n    });\n\n    const fees = {};\n    const feePercent = _.first(result).fee * 100;\n\n    if(_.first(result).type === 'sell') {\n      const fee = price * amount * _.first(result).fee;\n      fees[this.currency] = fee;\n    } else {\n      const fee = amount * _.first(result).fee;\n      fees[this.asset] = fee;\n    }\n\n    callback(err, {price, amount, date, fees, feePercent});\n  };\n\n  const fetch = next => this.poloniex.returnOrderTrades(order, this.processResponse(next, 'getOrder', order));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      return callback(err);\n    }\n\n    // console.log(new Date, 'PORDER cancel', order);\n\n    if(result.filled) {\n      console.log(new Date, 'result.filled', result);\n      return callback(undefined, true);\n    }\n\n    let data;\n\n    if(result.amount) {\n      data = { remaining: result.amount };\n    } else {\n      console.log(new Date, 'not result.amount', result);\n    }\n\n\n    callback(undefined, false, data);\n  };\n  \n  const fetch = next => this.poloniex.cancelOrder(this.currency, this.asset, order, this.processResponse(next, 'cancelOrder', order));\n  retry(null, fetch, handle);\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n\n  const firstFetch = !!since;\n  const args = _.toArray(arguments);\n\n  const handle = (err, result) => {\n    if(err)\n      return callback(err);\n\n    // Edge case, see here:\n    // @link https://github.com/askmike/gekko/issues/479\n    if(firstFetch && _.size(result) === 50000)\n      return callback(\n        [\n          'Poloniex did not provide enough data. Read this:',\n          'https://github.com/askmike/gekko/issues/479'\n        ].join('\\n\\n')\n      );\n\n    result = _.map(result, function(trade) {\n      return {\n        tid: trade.tradeID,\n        amount: +trade.amount,\n        date: moment.utc(trade.date).unix(),\n        price: +trade.rate\n      };\n    });\n\n    callback(null, result.reverse());\n  };\n\n  var params = {\n    currencyPair: this.pair\n  }\n\n  if(since)\n    params.start = since.unix();\n\n  const fetch = next => this.poloniex._public('returnTradeHistory', params, this.processResponse(next, 'getTrades', since));\n  retry(null, fetch, handle);\n}\n\nTrader.getCapabilities = function () {\n\treturn {\n\t\tname: 'Poloniex',\n\t\tslug: 'poloniex',\n\t\tcurrencies: marketData.currencies,\n\t\tassets: marketData.assets,\n\t\tmarkets: marketData.markets,\n\t\tcurrencyMinimums: {BTC: 0.0001, ETH: 0.0001, XMR: 0.0001, USDT: 1.0},\n\t\trequires: ['key', 'secret'],\n\t\ttid: 'tid',\n\t\tprovidesHistory: 'date',\n\t\tprovidesFullHistory: true,\n\t\ttradable: true,\n    gekkoBroker: 0.6\n\t};\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/quadriga-markets.json",
    "content": "{\n  \"assets\": [\n    \"XBT\",\n    \"ETH\",\n    \"LTC\",\n    \"BCH\",\n    \"BTG\"\n  ],\n  \"currencies\": [\n    \"CAD\",\n    \"USD\",\n    \"XBT\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"CAD\",\n        \"XBT\"\n      ],\n      \"book\": \"btc_cad\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"USD\",\n        \"XBT\"\n      ],\n      \"book\": \"btc_usd\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"BCH\"\n      ],\n      \"book\": \"bch_cad\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"BCH\"\n      ],\n      \"book\": \"bch_btc\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"ETH\"\n      ],\n      \"book\": \"eth_cad\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"ETH\"\n      ],\n      \"book\": \"eth_btc\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"LTC\"\n      ],\n      \"book\": \"ltc_cad\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"LTC\"\n      ],\n      \"book\": \"ltc_btc\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"CAD\",\n        \"BTG\"\n      ],\n      \"book\": \"btg_cad\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    },\n    {\n      \"pair\": [\n        \"XBT\",\n        \"BTG\"\n      ],\n      \"book\": \"btg_btc\",\n      \"minimalOrder\": {\n        \"amount\": \"0.0005\",\n        \"unit\": \"asset\"\n      },\n      \"precision\": 8\n    }\n  ]\n}\n"
  },
  {
    "path": "exchange/wrappers/quadriga.js.old",
    "content": "var QuadrigaCX = require('quadrigacx');\nvar moment = require('moment');\nvar util = require('../core/util');\nvar _ = require('lodash');\nvar log = require('../core/log');\n\n\nvar Trader = function(config) {\n  _.bindAll(this);\n\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientId = config.username;\n    this.asset = config.asset;\n    this.currency = config.currency;\n  }\n    \n  this.pair = this.asset.toLowerCase() + '_' + this.currency.toLowerCase(); \n  this.name = 'quadriga';\n  this.since = null;\n\n  this.quadriga = new QuadrigaCX(\n    this.clientId ? this.clientId : \"1\",\n    this.key ? this.key : \"\",\n    this.secret ? this.secret : \"\",\n  );\n}\n\nTrader.prototype.retry = function(method, warn, args, error) {\n  var wait = +moment.duration(30, 'seconds');\n  if (error.code === 200) {\n    log.debug(`${this.name}: API rate limit exceeded! unable to call ${method}, will retry in 2 minutes`)\n    wait = +moment.duration(120, 'seconds');\n  }\n  else {\n    log.debug(JSON.stringify(error));\n    log.debug(`${this.name}: ${warn}, will retry in 30 seconds`);\n  }\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, trades) {\n    if (trades && trades.error) return this.retry(this.getTrades, 'unable to get trades', args, trades.error);\n    if (err) return this.retry(this.getTrades, 'unable to get trades', args, err);\n\n    var parsedTrades = [];\n    _.each(trades, function(trade) {\n      parsedTrades.push({\n        tid: trade.tid,\n        date: trade.date,\n        price: parseFloat(trade.price),\n        amount: parseFloat(trade.amount)\n      });\n    }, this);\n\n    if(descending)\n      callback(null, parsedTrades);\n    else\n      callback(null, parsedTrades.reverse());\n  };\n\n  var reqData = {\n    book: this.pair,\n    time: 'hour'\n  };\n\n  this.quadriga.api('transactions', reqData, _.bind(process, this));\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var set = function(err, data) {\n\n    if (data && data.error) return this.retry(this.getPortfolio, 'unable to get balance', args, data.error);\n    if (err) return this.retry(this.getPortfolio, 'unable to get balance', args, err);\n\n    var assetAmount = parseFloat( data[this.asset.toLowerCase() + '_available'] );\n    var currencyAmount = parseFloat( data[this.currency.toLowerCase() + '_available'] );\n\n    if(!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      log.error(`Quadriga did not return balance for ${this.asset.toLowerCase()}, assuming 0.`);\n      assetAmount = 0;\n    }\n\n    if(!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      log.error(`Quadriga did not return balance for ${this.currency.toLowerCase()}, assuming 0.`);\n      currencyAmount = 0;\n    }\n\n    var portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n    callback(err, portfolio);\n  };\n\n  this.quadriga.api('balance', _.bind(set, this));\n};\n\nTrader.prototype.getFee = function(callback) {\n  callback(false, 0.005);\n};\n\nTrader.prototype.getTicker = function(callback) {\n  var set = function(err, data) {\n\n    if (data && data.error) return this.retry(this.getTicker, 'unable to get quote', args, data.error);\n    if (err) return this.retry(this.getTicker, 'unable to get quote', args, err);\n\n    var ticker = {\n      ask: data.ask,\n      bid: data.bid\n    };\n    callback(err, ticker);\n  };\n\n  this.quadriga.api('ticker', {book: this.pair}, _.bind(set, this));\n};\n\nTrader.prototype.roundAmount = function(amount) {\n  var precision = 100000000;\n  var market = Trader.getCapabilities().markets.find(function(market){ return market.pair[0] === this.currency && market.pair[1] === this.asset });\n\n  if(Number.isInteger(market.precision))\n    precision = 10 * market.precision;\n\n  amount *= precision;\n  amount = Math.floor(amount);\n  amount /= precision;\n  return amount;\n};\n\nTrader.prototype.addOrder = function(tradeType, amount, price, callback) {\n  var args = _.toArray(arguments);\n\n  amount = this.roundAmount(amount);\n  log.debug(tradeType.toUpperCase(), amount, this.asset, '@', price, this.currency);\n\n  var set = function(err, data) {\n\n    if (data && data.error) return this.retry(this.addOrder, 'unable to place order', args, data.error);\n    if (err) return this.retry(this.addOrder, 'unable to place order', args, err);\n    \n    var txid = data.id;\n    log.debug('added order with txid:', txid);\n\n    callback(undefined, txid);\n  };\n\n  this.quadriga.api(tradeType, {\n    book: this.pair,\n    price: price,\n    amount: amount\n  }, _.bind(set, this));\n};\n\n\nTrader.prototype.getOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n\n  var get = function(err, data) {\n    if (data && data.error) return this.retry(this.getOrder, 'unable to get order', args, data.error);\n    if (err) return this.retry(this.getOrder, 'unable to get order', args, err);\n\n    var price = parseFloat( data[0].price );\n    var amount = parseFloat( data[0].amount );\n    var date = (data[0].updated) ? moment.unix( data[0].updated ) : false;\n\n    callback(undefined, {price, amount, date});\n  }.bind(this);\n\n  this.quadriga.api('lookup_oder', {id: order}, get);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  this.addOrder('buy', amount, price, callback);\n};\n\nTrader.prototype.sell = function(amount, price, callback) {\n  this.addOrder('sell', amount, price, callback);\n};\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  \n  var check = function(err, data) {\n\n    if (data && data.error) return this.retry(this.checkOrder, 'unable to get order', args, data.error);\n    if (err) return this.retry(this.checkOrder, 'unable to get order', args, err);\n\n    var result = data[0];\n    var stillThere = result.status === 0 || result.status === 1;\n    callback(err, !stillThere);\n  };\n\n  this.quadriga.api('lookup_order', {id: order}, _.bind(check, this));\n};\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var args = _.toArray(arguments);\n  var cancel = function(err, data) {\n\n    if (data && data.error) return this.retry(this.cancelOrder, 'unable to cancel order', args, data.error);\n    if (err) return this.retry(this.cancelOrder, 'unable to cancel order', args, err);\n\n    callback();\n  };\n\n  this.quadriga.api('cancel_order', {id: order}, _.bind(cancel, this));\n};\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Quadriga',\n    slug: 'quadriga',\n    currencies: ['CAD', 'USD', 'BTC'],\n    assets: ['BTC', 'ETH', 'LTC', 'BCH'],\n    markets: [\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n      { pair: ['CAD', 'ETH'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n      { pair: ['CAD', 'BTC'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n      { pair: ['CAD', 'LTC'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n      { pair: ['CAD', 'BCH'], minimalOrder: { amount: 0.00001, unit: 'asset' }, precision: 8 },\n    ],\n    requires: ['key', 'secret', 'username'],\n    providesHistory: false,\n    tid: 'tid',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/therocktrading-markets.json",
    "content": "{\n  \"assets\": [\n    \"ETH\",\n    \"LTC\",\n    \"BTC\",\n    \"BCH\",\n    \"EUR\",\n    \"PPC\",\n    \"ZEC\",\n    \"NOKU\",\n    \"FDZ\"\n  ],\n  \"currencies\": [\n    \"BTC\",\n    \"EUR\",\n    \"ETH\",\n    \"GUSD\",\n    \"XRP\"\n  ],\n  \"markets\": [\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.0005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"PPC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.05,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"EUR\",\n        \"GUSD\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ETH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.001,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"PPC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.05,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"LTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"BCH\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"BTC\",\n        \"ZEC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 1e-8,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"GUSD\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.0005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"XRP\",\n        \"EUR\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.01,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    },\n    {\n      \"pair\": [\n        \"XRP\",\n        \"BTC\"\n      ],\n      \"minimalOrder\": {\n        \"amount\": 0.005,\n        \"price\": 0.01,\n        \"order\": 0\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "exchange/wrappers/therocktrading.js",
    "content": "const Therocktrading = require('therocktrading');\nconst _ = require('lodash');\nconst moment = require('moment');\nconst retry = require('../exchangeUtils').retry;\nconst marketData = require(\"./therocktrading-markets.json\");\n\nconst QUERY_DELAY = 350;\n\nconst Trader = function(config) {\n  this.post_only = true;\n  this.use_sandbox = false;\n  this.name = 'Therocktrading';\n  this.scanback = true;\n  this.scanbackTid = 0;\n  this.since = null;\n  this.asset = config.asset;\n  this.currency = config.currency;\n\n  this.api_url = 'https://api.therocktrading.com';\n  this.api_sandbox_url = 'https://api-staging.therocktrading.com';\n\n  if (_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n\n    this.pair = [config.asset, config.currency].join('').toUpperCase();\n    this.post_only =\n      typeof config.post_only !== 'undefined' ? config.post_only : true;\n    \n    if (config.sandbox) {\n      this.use_sandbox = config.sandbox;\n    }\n\n  }\n\n  this.therocktrading = new Therocktrading(this.key, this.secret, 'Gekko Broker v' + require('../package.json').version);\n};\n\nconst recoverableErrors = [\n  'SOCKETTIMEDOUT',\n  'TIMEDOUT',\n  'CONNRESET',\n  'CONNREFUSED',\n  'NOTFOUND',\n  'Rate limit exceeded',\n  'Response code 5',\n  'Therocktrading is currently under maintenance.',\n  'HTTP 408 Error',\n  'HTTP 504 Error',\n  'HTTP 503 Error',\n  'EHOSTUNREACH',\n  'EAI_AGAIN',\n  'ENETUNREACH'\n];\n\nconst includes = (str, list) => {\n  if(!_.isString(str))\n    return false;\n\n  return _.some(list, item => str.includes(item));\n}\n\nTrader.prototype.processResponse = function(method, next) {\n  return (error, body) => {\n    if (body && body.code) {\n      error = new Error(`Error ${body.code}: ${body.msg}`);\n    }\n\n    if(!error && body && !_.isEmpty(body.message)) {\n      error = new Error(body.message);\n    }\n\n    /*if(\n      response &&\n      response.statusCode < 200 &&\n      response.statusCode >= 300\n    ) {\n      error = new Error(`Response code ${response.statusCode}`);\n    }*/\n\n    if(error) {\n      if(_.isString(error)) {\n        error = new Error(error);\n      }\n\n      if(includes(error.message, recoverableErrors)) {\n        error.notFatal = true;\n      }\n\n      return next(error);\n    }\n\n    return next(undefined, body);\n  }\n};\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  const handle = (err, data) => {\n    if (err) return callback(err);\n    var trades = [];\n    if (_.isArray(data.trades)) {\n      trades = _.map(data.trades, function(trade) {\n        return {\n          tid: trade.id,\n          price: trade.price,\n          amount: trade.amount,\n          date: moment.utc(trade.date).format('X')\n        };\n      });\n    }\n\n    callback(null, descending ? trades : trades.reverse());\n  };\n\n  if (moment.isMoment(since)) since = since.format();\n  //if (moment.isMoment(to)) to = to.format();\n\n  var options = {\n    order: \"DESC\" // which is default at therock\n  }\n  if (since)\n  \toptions.after = since;\n  const fetch = cb => this.therocktrading.trades(this.pair, options, this.processResponse('getTrades', cb));\n  retry(null, fetch, handle);\n};\n\n\nTrader.prototype.getTicker = function(callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n    callback(undefined, { bid: data.bid, ask: data.ask });\n  };\n\n  const fetch = cb =>\n    this.therocktrading.ticker(this.pair, this.processResponse('getTicker', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.getFee = function(callback) {\n  const fee = 0.2;\n  // should check for discounts ?\n  callback(undefined, fee);\n};\n\nTrader.prototype.getPortfolio = function(callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n    var portfolio = data.balances.map(function(balance) {\n      return {\n        name: balance.currency.toUpperCase(),\n        amount: parseFloat(balance.trading_balance),\n      };\n    });\n    callback(undefined, portfolio);\n  };\n\n  const fetch = cb => this.therocktrading.balances(this.processResponse('getPortfolio', cb));\n  retry(undefined, fetch, result);\n};\n\n\nTrader.prototype.buy = function(amount, price, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      return callback(err);\n    }\n    callback(undefined, result.id);\n  }\n  const fetch = next => {\n    this.therocktrading.buy(this.pair, amount.toString(), price.toString(), this.processResponse('order', next))\n  };\n  retry(null, fetch, handle);  \n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      return callback(err);\n    }\n    callback(undefined, result.id);\n  }\n  const fetch = next => {\n    this.therocktrading.sell(this.pair, amount.toString(), price.toString(), this.processResponse('order', next))\n  };\n  retry(null, fetch, handle);  \n}\n\n\nTrader.prototype.getOrder = function(order, callback) {\n  const handle = (err, result) => {\n    if(err)\n      return callback(err);\n\n    let price = 0;\n    let amount = 0;\n    let date = moment(0);\n\n    if(result.amount === result.amount_unfilled) {\n      return callback(null, {price, amount, date});\n    }\n\n    _.each(result.trades, trade => {\n      date = moment(trade.date);\n      price = ((price * amount) + (+trade.price * trade.amount)) / (+trade.amount + amount);\n      amount += +trade.amount;\n    });\n\n    const fees = {};\n    const feePercent = this.makerFee;\n\n    const fee = price * amount * feePercent;\n    fees[this.currency] = fee;\n\n    callback(err, {price, amount, date, fees, feePercent});\n  };\n\n  const fetch = cb => this.therocktrading.order_status(this.pair, order, this.processResponse('order_status', cb));\n  retry(null, fetch, handle);\n};\n\nTrader.prototype.checkOrder = function(order, callback) {\n  const result = (err, data) => {\n    if (err) return callback(err);\n\n    var status = data.status;\n    if (status == 'executed') {\n      return callback(undefined, { executed: true, open: false, filledAmount: parseFloat(data.amount) });\n    } else if (status === 'deleted') {\n      return callback(undefined, { executed: false, open: false, filledAmount: parseFloat(data.amount - data.amount_unfilled) });\n    } else if (status === 'active') {\n      // should check if not expired (data.close_on)?\n      return callback(undefined, { executed: false, open: true, filledAmount:  parseFloat(data.amount - data.amount_unfilled) });\n    }\n\n    callback(new Error('Unknown status ' + status));\n  };\n\n  const fetch = cb =>\n    this.therocktrading.order_status(this.pair, order, this.processResponse('order_status', cb));\n  retry(null, fetch, result);\n};\n\n\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  // callback for cancelOrder should be true if the order was already filled, otherwise false\n  const result = (err, data) => {\n    if(err) {\n      return callback(null, true);  // need to catch the specific error but usually an error on cancel means it was filled\n    }\n\n    return callback(null, false);\n  };\n\n  const fetch = cb =>\n    this.therocktrading.cancel_order(this.pair, order, this.processResponse('cancel_order', cb));\n  retry(null, fetch, result);\n};\n\nTrader.prototype.roundAmount = function(amount) {\n  return _.floor(amount, 8);\n}\n\nTrader.prototype.roundPrice = function(price) {\n  return +price;\n}\n\nTrader.getCapabilities = function() {\n  return {\n    name: 'Therocktrading',\n    slug: 'therocktrading',\n    currencies: marketData.currencies,\n    assets: marketData.assets,\n    markets: marketData.markets,\n    requires: ['key', 'secret'],\n    providesHistory: 'date',\n    providesFullHistory: true,\n    // following tid, define type to use on trade to batch trades\n    tid: 'tid',\n    tradable: true,\n    gekkoBroker: 0.6\n  };\n};\n\nmodule.exports = Trader;\n\n"
  },
  {
    "path": "exchange/wrappers/wex.nz.js.old",
    "content": "var WEX = require('node-wex');\n\nvar moment = require('moment');\nvar util = require('../core/util');\nvar _ = require('lodash');\nvar log = require('../core/log')\n\nvar Trader = function(config) {\n  this.key = config.key;\n  this.secret = config.secret;\n  this.asset = config.asset;\n  this.currency = config.currency;\n  this.pair = [config.asset, config.currency].join('_').toLowerCase();\n  this.name = 'wex.nz';\n\n  _.bindAll(this);\n\n  this.wex = new WEX(this.key, this.secret);\n  _.bindAll(this.wex, ['trade', 'trades', 'getInfo', 'ticker', 'orderList']);\n\n  // see @link https://github.com/askmike/gekko/issues/302\n  this.wexHistorocial = new WEX(false, false, {public_url: 'https://wex.nz/api/3/'});\n  _.bindAll(this.wexHistorocial, 'trades');\n}\n\nTrader.prototype.round = function(amount) {\n  // Prevent \"You incorrectly entered one of fields.\"\n  // because of more than 8 decimals.\n  amount *= 100000000;\n  amount = Math.floor(amount);\n  amount /= 100000000;\n\n  return amount;\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  amount = this.round(amount);\n\n  var set = function(err, data) {\n    if(err || !data || !data.return)\n      return log.error('unable to buy:', err);\n\n    callback(null, data.return.order_id);\n  }.bind(this);\n\n  // workaround for nonce error\n  setTimeout(function() {\n    this.wex.trade(this.pair, 'buy', price, amount, _.bind(set, this));\n  }.bind(this), 1000);\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  amount = this.round(amount);\n\n  var set = function(err, data) {\n    if(err || !data || !data.return)\n      return log.error('unable to sell:\\n\\n', err);\n\n    callback(null, data.return.order_id);\n  };\n\n  // workaround for nonce error\n  setTimeout(function() {\n    this.wex.trade(this.pair, 'sell', price, amount, _.bind(set, this));\n  }.bind(this), 1000);\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var args = _.toArray(arguments);\n  var calculate = function(err, data) {\n\n    if(err) {\n      if(err.message === 'invalid api key')\n        util.die('Your ' + this.name + ' API keys are invalid');\n\n      return this.retry(this.getPortfolio, args);\n    }\n\n    if(_.isEmpty(data))\n      err = 'no data';\n\n    if (err || !data.return || !data.return.funds)\n      return this.retry(this.getPortfolio, args);\n\n    var assetAmount = parseFloat( data.return.funds[this.asset.toLowerCase()] );\n    var currencyAmount = parseFloat( data.return.funds[this.currency.toLowerCase()] );\n\n    if(!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {\n      log.error(`wex.nz did not return portfolio for ${this.asset}, assuming 0.`);\n      assetAmount = 0;\n    }\n\n    if(!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {\n      log.error(`wex.nz did not return portfolio for ${this.currency}, assuming 0.`);\n      currencyAmount = 0;\n    }\n\n    var portfolio = [\n      { name: this.asset, amount: assetAmount },\n      { name: this.currency, amount: currencyAmount }\n    ];\n\n    callback(err, portfolio);\n  }.bind(this);\n\n  this.wex.getInfo(calculate);\n}\n\nTrader.prototype.getTicker = function(callback) {\n  // wex.nz doesn't state asks and bids in its\n  // ticker\n  var set = function(err, data) {\n\n    if(err)\n      return this.retry(this.wex.ticker, [this.pair, set]);\n\n    var ticker = {\n      ask: data.ticker.buy,\n      bid: data.ticker.sell\n    };\n\n    callback(err, ticker);\n  }.bind(this);\n\n  this.wex.ticker(this.pair, set);\n}\n\nTrader.prototype.getFee = function(callback) {\n  // wex.nz doesn't have different fees based on orders\n  // at this moment it is always 0.2%\n  callback(false, 0.002);\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var check = function(err, result) {\n    // wex returns an error when you have no open trades\n    // right now we assume on every error that the order\n    // was filled.\n    //\n    // TODO: check whether the error states that there are no\n    // open trades or that there is something else.\n    if(err)\n      callback(false, true);\n    else\n      callback(err, !result[order]);\n  }.bind(this);\n\n  this.wex.orderList({}, check);\n}\n\nTrader.prototype.getOrder = function(orderId, callback) {\n  console.log('getOrder', orderId);\n  var args = _.toArray(arguments);\n  var check = function(err, result) {\n    if(err) {\n      log.error('error on getOrder', err);\n      return this.retry(this.getOrder, args);\n    }\n\n    var order = null;\n\n    _.each(result.return, o => {\n      if(o.order_id === +orderId)\n        order = o;\n    });\n\n    if(!order)\n      return log.error('wex.nz did not provide the order');\n\n    var price = parseFloat(order.rate);\n    var amount = parseFloat(order.amount);\n    var date = moment.unix(order.timestamp);\n\n    callback(undefined, {price, amount, date});\n  }.bind(this);\n\n  this.wex.tradeHistory({pair: this.pair}, check);\n}\n\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  this.wex.cancelOrder(order, (err, result) => {\n    callback();\n  });\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(err, trades) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    if(descending)\n      callback(false, trades);\n    else\n      callback(false, trades.reverse());\n  }.bind(this);\n\n  // see @link https://github.com/askmike/gekko/issues/302\n  if(since) {\n    this.wexHistorocial.makePublicApiRequest(\n      'trades',\n      this.pair + '?limit=2000',\n      this.processAPIv3Trades(process)\n    )\n  } else\n    this.wex.trades(this.pair, process);\n}\n\nTrader.prototype.processAPIv3Trades = function(cb) {\n  return function(err, data) {\n    var trades = _.map(data[this.pair], function(t) {\n      return {\n        price: t.price,\n        amount: t.amount,\n        tid: t.tid,\n        date: t.timestamp\n      }\n    })\n    cb(err, trades);\n  }.bind(this)\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'wex.nz',\n    slug: 'wex.nz',\n    currencies: ['USD', 'RUR', 'EUR', 'BTC', 'LTC', 'ETH', 'NMC', 'NMC', 'NVC', 'PPC', 'DSH', 'BCH'],\n    assets: [\n      'BTC', 'LTC', 'NMC', 'NVC', 'USD', 'EUR', 'PPC', 'DSH', 'ETH',\n      'USDET', 'RURET', 'EURET', 'BTCET', 'LTCET', 'ETHET', 'NMCET', 'NVCET', 'PPCET', 'DSHET', 'BCHET' // Token\n    ],\n    markets: [\n      { pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n      { pair: ['RUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n      { pair: ['EUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },\n      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'LTC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'LTC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['EUR', 'LTC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'NMC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'NMC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'NVC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'NVC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'USD'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'EUR'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'EUR'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'PPC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'PPC'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['EUR', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['LTC', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['ETH', 'DSH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'ETH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['EUR', 'ETH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['LTC', 'ETH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'ETH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['USD', 'BCH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'BCH'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      \n      // Token pairs\n      { pair: ['USD', 'USDET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['RUR', 'RURET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['EUR', 'EURET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BTC', 'BTCET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['LTC', 'LTCET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['ETH', 'ETHET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['NMC', 'NMCET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['NVC', 'NVCET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['PPC', 'PPCET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['DSH', 'DSHET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n      { pair: ['BCH', 'BCHET'], minimalOrder: { amount: 0.1, unit: 'asset' } },\n\n    ],\n    requires: ['key', 'secret'],\n    providesHistory: false,\n    tid: 'tid',\n    tradable: true\n  };\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "exchange/wrappers/zaif.jp.js.old",
    "content": "var Zaif = require(\"zaif.jp\");\nvar util = require('../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../core/log');\n\nvar Trader = function(config) {\n  _.bindAll(this);\n  if(_.isObject(config)) {\n    this.key = config.key;\n    this.secret = config.secret;\n    this.clientID = config.username;\n  }\n  this.name = 'Zaif';\n  this.balance;\n  this.price;\n\n  this.zaif = Zaif.createPrivateApi(this.key, this.secret, 'user agent is node-zaif');\n  this.api = Zaif.PublicApi;\n}\n\n// if the exchange errors we try the same call again after\n// waiting 10 seconds\nTrader.prototype.retry = function(method, args) {\n  var wait = +moment.duration(10, 'seconds');\n  log.debug(this.name, 'returned an error, retrying..');\n\n  var self = this;\n\n  // make sure the callback (and any other fn)\n  // is bound to Trader\n  _.each(args, function(arg, i) {\n    if(_.isFunction(arg))\n      args[i] = _.bind(arg, self);\n  });\n\n  // run the failed method again with the same\n  // arguments after wait\n  setTimeout(\n    function() { method.apply(self, args) },\n    wait\n  );\n}\n\nTrader.prototype.getPortfolio = function(callback) {\n  var set = function(data) {\n    var portfolio = [];\n    _.each(data.funds, function(amount, asset) {\n//      if(asset.indexOf('available') !== -1) {\n        asset = asset.substr(0, 3).toUpperCase();\n        portfolio.push({name: asset, amount: parseFloat(amount)});\n//      }\n    });\n    callback(err, portfolio);\n  }\n  this.zaif.getInfo().then(_.bind(set, this));\n}\n\nTrader.prototype.getTicker = function(callback) {\n  this.api.ticker('btc_jpy').then(callback);\n}\n\nTrader.prototype.getFee = function(callback) {\n    var makerFee = 0.0;\n    callback(false, makerFee / 100);\n}\n\nTrader.prototype.buy = function(amount, price, callback) {\n  var set = function(result) {\n    if(!result)\n      return log.error('unable to buy:', result);\n\n    callback(null, result.order_id);\n  };\n\n  // TODO: fees are hardcoded here?\n//  amount *= 0.995; // remove fees\n  // prevent: Ensure that there are no more than 8 digits in total.\n  amount *= 100000000;\n  amount = Math.floor(amount);\n  amount /= 100000000;\n  this.zaif.trade('bid', price, amount).then(_.bind(set, this));\n}\n\nTrader.prototype.sell = function(amount, price, callback) {\n  var set = function(result) {\n    if(!result)\n      return log.error('unable to sell:', result);\n\n    callback(null, result.order_id);\n  };\n\n  this.zaif.trade('ask', price, amount).then(_.bind(set, this));\n}\n\nTrader.prototype.checkOrder = function(order, callback) {\n  var check = function(result) {\n    var stillThere = (order in result);\n    callback(null, !stillThere);\n  };\n\n  this.zaif.activeorders().then(_.bind(check, this));\n}\n\nTrader.prototype.cancelOrder = function(order, callback) {\n  var cancel = function(result) {\n    if(!result)\n      log.error('unable to cancel order', order, '(', result, ')');\n  };\n\n  this.zaif.cancelorder(order).then(_.bind(cancel, this));\n}\n\nTrader.prototype.getTrades = function(since, callback, descending) {\n  var args = _.toArray(arguments);\n  var process = function(result) {\n    if(!result)\n      return this.retry(this.getTrades, args);\n\n    callback(null, result.reverse());\n  };\n\n  this.api.trades('btc_jpy').then(_.bind(process, this));\n}\n\nTrader.getCapabilities = function () {\n  return {\n    name: 'Zaif.jp',\n    slug: 'zaif.jp',\n    currencies: ['JPY'],\n    assets: ['BTC'],\n    markets: [\n      {\n        pair: ['JPY', 'BTC'], minimalOrder: { amount: 1, unit: 'currency' }\n      }\n    ],\n    requires: ['key', 'secret', 'username'],\n    providesHistory: false,\n    fetchTimespan: 60,\n    tid: 'tid'\n  };\n}\n\nmodule.exports = Trader;"
  },
  {
    "path": "gekko.js",
    "content": "/*\n\n  Gekko is a Bitcoin trading bot for popular Bitcoin exchanges written \n  in node, it features multiple trading methods using technical analysis.\n\n  If you are interested in how Gekko works, read more about Gekko's \n  architecture here:\n\n  https://gekko.wizb.it/docs/internals/architecture.html\n\n  Disclaimer:\n\n  USE AT YOUR OWN RISK!\n\n  The author of this project is NOT responsible for any damage or loss caused \n  by this software. There can be bugs and the bot may not perform as expected \n  or specified. Please consider testing it first with paper trading and/or \n  backtesting on historical data. Also look at the code to see what how \n  it is working.\n\n*/\n\nconsole.log(`\n    ______   ________  __    __  __    __   ______\n   /      \\\\ /        |/  |  /  |/  |  /  | /      \\\\\n  /$$$$$$  |$$$$$$$$/ $$ | /$$/ $$ | /$$/ /$$$$$$  |\n  $$ | _$$/ $$ |__    $$ |/$$/  $$ |/$$/  $$ |  $$ |\n  $$ |/    |$$    |   $$  $$<   $$  $$<   $$ |  $$ |\n  $$ |$$$$ |$$$$$/    $$$$$  \\\\  $$$$$  \\\\  $$ |  $$ |\n  $$ \\\\__$$ |$$ |_____ $$ |$$  \\\\ $$ |$$  \\\\ $$ \\\\__$$ |\n  $$    $$/ $$       |$$ | $$  |$$ | $$  |$$    $$/ \n   $$$$$$/  $$$$$$$$/ $$/   $$/ $$/   $$/  $$$$$$/\n`);\n\nconst util = require(__dirname + '/core/util');\n\nconsole.log('\\tGekko v' + util.getVersion());\nconsole.log('\\tI\\'m gonna make you rich, Bud Fox.', '\\n\\n');\n\nconst dirs = util.dirs();\n\nif(util.launchUI()) {\n  return require(util.dirs().web + 'server');\n}\n\nconst pipeline = require(dirs.core + 'pipeline');\nconst config = util.getConfig();\nconst mode = util.gekkoMode();\n\nif(\n  config.trader &&\n  config.trader.enabled &&\n  !config['I understand that Gekko only automates MY OWN trading strategies']\n)\n  util.die('Do you understand what Gekko will do with your money? Read this first:\\n\\nhttps://github.com/askmike/gekko/issues/201');\n\n// > Ever wonder why fund managers can't beat the S&P 500?\n// > 'Cause they're sheep, and sheep get slaughtered.\npipeline({\n  config: config,\n  mode: mode\n});\n\n"
  },
  {
    "path": "importers/exchanges/binance.js",
    "content": "const moment = require('moment');\nconst util = require('../../core/util.js');\nconst _ = require('lodash');\nconst log = require('../../core/log');\n\nvar config = util.getConfig();\nvar dirs = util.dirs();\n\nvar Fetcher = require(dirs.exchanges + 'binance');\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n  fetcher.import = true;\n  fetcher.getTrades(from, handleFetch);\n};\n\nvar handleFetch = (err, trades) => {\n  if (err) {\n    log.error(`There was an error importing from Binance ${err}`);\n    fetcher.emit('done');\n    return fetcher.emit('trades', []);\n}\n\n  if (trades.length > 0) {\n    var last = moment.unix(_.last(trades).date).utc();\n    // Conversion to milliseconds epoch time means we have to compensate for possible leap seconds\n    var next = from.clone().add(1, 'h').subtract(1, 's');\n  } else {\n    // Conversion to milliseconds epoch time means we have to compensate for possible leap seconds\n    var next = from.clone().add(1, 'h').subtract(1, 's');\n    log.debug('Import step returned no results, moving to the next 1h period');\n  }\n\n  if (from.add(1, 'h') >= end) {\n    fetcher.emit('done');\n\n    var endUnix = end.unix();\n    trades = _.filter(trades, t => t.date <= endUnix);\n  }\n\n  from = next.clone();\n  fetcher.emit('trades', trades);\n};\n\nmodule.exports = function(daterange) {\n  from = daterange.from.clone().utc();\n  end = daterange.to.clone().utc();\n\n  return {\n    bus: fetcher,\n    fetch: fetch,\n  };\n};\n"
  },
  {
    "path": "importers/exchanges/bitfinex.js",
    "content": "const Bitfinex = require('bitfinex-api-node');\nconst util = require('../../core/util.js');\nconst _ = require('lodash');\nconst moment = require('moment');\nconst log = require('../../core/log');\n\nconst config = util.getConfig();\n\nconst dirs = util.dirs();\n\nconst Fetcher = require(dirs.exchanges + 'bitfinex');\nconst retry = require(dirs.exchanges + '../exchangeUtils').retry;\n\nFetcher.prototype.getTrades = function(upto, callback, descending) {\n  const handle = (err, data) => {\n    if (err) return callback(err);\n\n    var trades = [];\n    if (_.isArray(data)) {\n      trades = _.map(data, function(trade) {\n        return {\n          tid: trade.ID,\n          date: moment(trade.MTS).format('X'),\n          price: +trade.PRICE,\n          amount: +Math.abs(trade.AMOUNT),\n        };\n      });\n    }\n\n    callback(null, descending ? trades : trades.reverse());\n  };\n\n  let path = 'trades/t' + this.pair + '/hist';\n  if (upto) {\n    let start = moment(upto).subtract(1, 'd').valueOf();\n    let end = moment(upto).valueOf();\n    path += `?limit=1000&start=${start}&end=${end}`;\n  }\n\n  log.debug('Querying trades with: ' + path);\n  const fetch = cb => this.bitfinex.makePublicRequest(path, this.handleResponse('getTrades', cb));\n  retry(null, fetch, handle);\n};\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar lastTimestamp = false;\nvar lastId = false;\n\nvar batch = [];\nvar batch_start = false;\nvar batch_end = false;\nvar batch_last = false;\n\nconst SCANNING_STRIDE = 24;\nconst ITERATING_STRIDE = 2;\nvar stride = ITERATING_STRIDE;\n\nvar fetcher = new Fetcher(config.watch);\nfetcher.bitfinex = new Bitfinex(null, null, { version: 2, transform: true }).rest;\n\nvar retryCritical = {\n  retries: 10,\n  factor: 1.2,\n  minTimeout: 70 * 1000,\n  maxTimeout: 120 * 1000,\n};\n\nvar fetch = () => {\n  fetcher.import = true;\n\n  if (lastTimestamp) {\n    // We need to slow this down to prevent hitting the rate limits\n    setTimeout(() => {\n\n      // make sure we fetch with overlap from last batch\n      const since = lastTimestamp - 1000;\n      fetcher.getTrades(since, handleFetch);\n    }, 2500);\n  } else {\n    lastTimestamp = from.valueOf();\n    batch_start = moment(from);\n    batch_end = moment(from).add(stride, 'h');\n\n    fetcher.getTrades(batch_end, handleFetch);\n  }\n};\n\nvar handleFetch = (err, trades) => {\n  if (err) {\n    log.error(`There was an error importing from Bitfinex ${err}`);\n    fetcher.emit('done');\n    return fetcher.emit('trades', []);\n  }\n\n  trades = _.filter(trades, t => !lastId || t.tid < lastId);\n\n  if (trades.length) {\n    stride = ITERATING_STRIDE;\n    batch = trades.concat(batch);\n    var last = moment.unix(_.first(trades).date);\n    lastTimestamp = last.valueOf();\n    lastId = _.first(trades).tid;\n  } else {\n    stride = SCANNING_STRIDE;\n    lastTimestamp = moment(lastTimestamp)\n      .subtract(stride, 'h')\n      .valueOf();\n  }\n\n  // if we're not done the batch we need to refetch\n  if (trades.length && moment(lastTimestamp) >= batch_start) {\n    return fetch();\n  }\n\n  var lastBatch = batch;\n\n  // in this case we've finished the last batch and are complete\n  if (batch_end.isSame(end)) {\n    fetcher.emit('done');\n  } else {\n    // the batch if complete, lets advance to the next set\n    lastId = false;\n    batch = [];\n    batch_start = moment(batch_end);\n    batch_end = moment(batch_end).add(stride, 'h');\n\n    if (batch_end > end) batch_end = moment(end);\n\n    lastTimestamp = batch_end.valueOf();\n  }\n\n  fetcher.emit('trades', lastBatch);\n};\n\nmodule.exports = function(daterange) {\n  from = daterange.from.clone();\n  end = daterange.to.clone();\n\n  return {\n    bus: fetcher,\n    fetch: fetch,\n  };\n};\n"
  },
  {
    "path": "importers/exchanges/btcc.js",
    "content": "var BTCChina = require('btc-china-fork');\nvar util = require('../../core/util.js');\nvar _ = require('lodash');\nvar moment = require('moment');\nvar log = require('../../core/log');\n\nvar config = util.getConfig();\n\nvar dirs = util.dirs();\n\nvar Fetcher = require(dirs.exchanges + 'btcc');\n\n// patch getTrades..\nFetcher.prototype.getTrades = function(fromTid, sinceTime, callback) {\n  var args = _.toArray(arguments);\n  var process = function(err, result) {\n    if(err)\n      return this.retry(this.getTrades, args);\n\n    callback(result);\n  }.bind(this);\n\n  if(sinceTime)\n    var params = {\n      limit: 1,\n      sincetype: 'time',\n      since: sinceTime\n    }\n\n  else if(fromTid)\n    var params = {\n      limit: 5000,\n      since: fromTid\n    }\n\n  this.btcc.getHistoryData(process, params);\n}\n\nutil.makeEventEmitter(Fetcher);\n\nvar iterator = false;\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n  if(!iterator)\n    fetcher.getTrades(false, from, handleFirstFetch);\n  else\n    fetcher.getTrades(iterator, false, handleFetch);\n}\n\n// we use the first fetch to figure out \n// the tid of the moment we want data from\nvar handleFirstFetch = trades => {\n  iterator = _.first(trades).tid;\n  fetch();\n}\n\nvar handleFetch = trades => {\n\n  iterator = _.last(trades).tid;\n  var last = moment.unix(_.last(trades).date);\n\n  if(last > end) {\n    fetcher.emit('done');\n\n    var endUnix = end.unix();\n    trades = _.filter(\n      trades,\n      t => t.date <= endUnix\n    );\n  }\n\n  fetcher.emit('trades', trades);\n}\n\nmodule.exports = function (daterange) {\n  from = daterange.from.unix();\n  end = daterange.to.clone();\n\n  return {\n    bus: fetcher,\n    fetch: fetch\n  }\n}\n\n"
  },
  {
    "path": "importers/exchanges/coinfalcon.js",
    "content": "const moment = require('moment');\nconst util = require('../../core/util.js');\nconst _ = require('lodash');\nconst log = require('../../core/log');\n\nvar config = util.getConfig();\nvar dirs = util.dirs();\n\nvar Fetcher = require(dirs.exchanges + 'coinfalcon');\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n  fetcher.import = true;\n  log.debug('[CoinFalcon] Getting trades from: ', from);\n  fetcher.getTrades(from, handleFetch, true);\n};\n\nvar handleFetch = (unk, trades) => {\n  if (trades.length > 0) {\n    var last = moment.unix(_.last(trades).date).utc();\n    var next = last.clone();\n  } else {\n    var next = from.clone().add(1, 'h');\n    log.debug('Import step returned no results, moving to the next 1h period');\n  }\n\n  if (from.add(1, 'h') >= end) {\n    fetcher.emit('done');\n\n    var endUnix = end.unix();\n    trades = _.filter(trades, t => t.date <= endUnix);\n  }\n\n  from = next.clone();\n  fetcher.emit('trades', trades);\n};\n\nmodule.exports = function(daterange) {\n  from = daterange.from.clone().utc();\n  end = daterange.to.clone().utc();\n\n  return {\n    bus: fetcher,\n    fetch: fetch,\n  };\n};\n"
  },
  {
    "path": "importers/exchanges/gdax.js",
    "content": "const util = require('../../core/util.js');\nconst _ = require('lodash');\nconst moment = require('moment');\nconst log = require('../../core/log');\n\nconst config = util.getConfig();\n\nconst dirs = util.dirs();\n\nconst QUERY_DELAY = 350;\nconst BATCH_SIZE = 100;\nconst SCAN_ITER_SIZE = 50000;\nconst BATCH_ITER_SIZE = BATCH_SIZE * 10;\n\nconst Fetcher = require(dirs.exchanges + 'gdax');\nconst retry = require(dirs.exchanges + '../exchangeUtils').retry;\n\nFetcher.prototype.getTrades = function(sinceTid, callback) {\n  let lastScan = 0;\n\n  const handle = (err, data) => {\n    if (err) return callback(err);\n\n    let result = _.map(data, function(trade) {\n      return {\n        tid: trade.trade_id,\n        amount: parseFloat(trade.size),\n        date: moment.utc(trade.time).format(\"X\"),\n        price: parseFloat(trade.price)\n      };\n    });\n\n    callback(null, result.reverse());\n  };\n\n  const fetch = cb => this.gdax_public.getProductTrades(this.pair, { after: sinceTid, limit: BATCH_SIZE }, this.processResponse('getTrades', cb));\n  retry(null, fetch, handle);\n};\n\nFetcher.prototype.findFirstTrade = function(sinceTs, callback) {\n  let currentId = 0;\n  let sinceM = moment(sinceTs).utc();\n\n  log.info(`Scanning for the first trade ID to start batching requests, may take a few minutes ...`);\n\n  const handle = (err, data) => {\n    if (err) return callback(err);\n\n    let m = moment.utc(_.first(data).time);\n    let ts = m.valueOf();\n    if (ts < sinceTs) {\n      log.info(`First trade ID for batching found ${currentId - SCAN_ITER_SIZE}`);\n      return callback(undefined, currentId - SCAN_ITER_SIZE);\n    }\n\n    currentId = _.first(data).trade_id;\n    log.debug(`Have trade id ${currentId} for date ${_.first(data).time} ${sinceM.from(m, true)} to scan`);\n\n    let nextScanId = currentId - SCAN_ITER_SIZE;\n    if (nextScanId <= SCAN_ITER_SIZE) {\n      currentId = BATCH_ITER_SIZE;\n      log.info(`First trade ID for batching found ${currentId}`);\n      return callback(undefined, currentId);\n    }\n\n    setTimeout(() => {\n      const fetch = cb => this.gdax_public.getProductTrades(this.pair, { after: nextScanId, limit: 1 }, this.processResponse('getTrades', cb));\n      retry(null, fetch, handle);\n    }, QUERY_DELAY);\n  }\n\n  const fetch = cb => this.gdax_public.getProductTrades(this.pair, { limit: 1 }, this.processResponse('getTrades', cb));\n  retry(null, fetch, handle);\n}\n\nutil.makeEventEmitter(Fetcher);\n\nlet end = false;\nlet done = false;\nlet from = false;\n\nlet batch = [];\nlet batchId = false; // Lowest ID for the current a batch\n\nlet lastId = false;\n\nlet latestId = false;\nlet latestMoment = false;\n\nlet fetcher = new Fetcher(config.watch);\n\nlet retryForever = {\n  forever: true,\n  factor: 1.2,\n  minTimeout: 10 * 1000,\n  maxTimeout: 120 * 1000\n};\n\nlet fetch = () => {\n  fetcher.import = true;\n\n  // We are in the sub-iteration step for a given batch\n  if (lastId) {\n    setTimeout(() => {\n      fetcher.getTrades(lastId, handleFetch);\n    }, QUERY_DELAY);\n  }\n  // We are running the first query, and need to find the starting batch\n  else {\n    let process = (err, firstBatchId) => {\n      if (err) return handleFetch(err);\n\n      batchId = firstBatchId;\n      fetcher.getTrades(batchId + 1, handleFetch);\n    }\n    fetcher.findFirstTrade(from.valueOf(), process);\n  }\n}\n\nlet handleFetch = (err, trades) => {\n  if (err) {\n    log.error(`There was an error importing from GDAX ${err}`);\n    fetcher.emit('done');\n    return fetcher.emit('trades', []);\n  }\n\n  if (trades.length) {\n    batch = trades.concat(batch);\n\n    let last = moment.unix(_.first(trades).date).utc();\n    lastId = _.first(trades).tid\n\n    let latestTrade = _.last(trades);\n    if (!latestId || latestTrade.tid > latestId) {\n      latestId = latestTrade.tid;\n      latestMoment = moment.unix(latestTrade.date).utc();\n    }\n\n    // still doing sub-iteration in the batch\n    if (lastId >= (batchId - BATCH_ITER_SIZE) && last >= from)\n      return fetch();\n  }\n\n  batchId += BATCH_ITER_SIZE;\n  lastId = batchId + 1;\n\n  if (latestMoment >= end) {\n    fetcher.emit('done');\n  }\n\n  let endUnix = end.unix();\n  let startUnix = from.unix();\n  batch = _.filter(batch, t => t.date >= startUnix && t.date <= endUnix);\n\n  fetcher.emit('trades', batch);\n  batch = [];\n}\n\nmodule.exports = function (daterange) {\n\n  from = daterange.from.utc().clone();\n  end = daterange.to.utc().clone();\n\n  return {\n    bus: fetcher,\n    fetch: fetch\n  }\n}\n"
  },
  {
    "path": "importers/exchanges/kraken.js",
    "content": "var _ = require('lodash');\nvar moment = require('moment');\n\nvar util = require('../../core/util.js');\nvar log = require('../../core/log');\n\nvar config = util.getConfig();\n\nvar dirs = util.dirs();\n\nvar Fetcher = require(dirs.exchanges + 'kraken');\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar lastId = false;\nvar prevLastId = false;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n    fetcher.import = true;\n\n    if (lastId) {\n        var tidAsTimestamp = lastId / 1000000;\n        setTimeout(() => {\n            fetcher.getTrades(tidAsTimestamp, handleFetch)\n        }, 500);\n    }\n    else\n        fetcher.getTrades(from, handleFetch);\n}\n\nvar handleFetch = (err, trades) => {\n    if(!err && !trades.length) {\n        console.log('no trades');\n        err = 'No trades';\n    }\n\n    if (err) {\n        log.error(`There was an error importing from Kraken ${err}`);\n        fetcher.emit('done');\n        return fetcher.emit('trades', []);\n    }\n\n    var last = moment.unix(_.last(trades).date).utc();\n    lastId = _.last(trades).tid\n    if(last < from) {\n        log.debug('Skipping data, they are before from date', last.format());\n        return fetch();\n    }\n\n    if  (last > end || lastId === prevLastId) {\n        fetcher.emit('done');\n\n        var endUnix = end.unix();\n        trades = _.filter(\n            trades,\n            t => t.date <= endUnix\n        )\n    }\n\n    prevLastId = lastId\n    fetcher.emit('trades', trades);\n}\n\nmodule.exports = function (daterange) {\n\n    from = daterange.from.clone();\n    end = daterange.to.clone();\n\n    return {\n        bus: fetcher,\n        fetch: fetch\n    }\n}\n\n\n"
  },
  {
    "path": "importers/exchanges/luno.js",
    "content": "const moment = require('moment');\nconst util = require('../../core/util.js');\nconst _ = require('lodash');\nconst retry = require('../../exchange/exchangeUtils').retry;\n\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst Fetcher = require(dirs.exchanges + 'luno');\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar from = false;\nconst REQUEST_INTERVAL = 5 * 1000;\n\nFetcher.prototype.getTrades = function(since, callback, descending) {\n  const recoverableErrors = [\n    'SOCKETTIMEDOUT',\n    'TIMEDOUT',\n    'CONNRESET',\n    'CONNREFUSED',\n    'NOTFOUND'\n  ];\n\n  const processResponse = function(funcName, callback) {\n    return (error, body) => {\n      if (!error && !body) {\n        error = new Error('Empty response');\n      }\n\n      if (error) {\n        console.log(funcName, 'processResponse received ERROR:', error.message);\n        if (includes(error.message, recoverableErrors)) {\n          error.notFatal = true;\n        }\n\n        if (includes(error.message, ['error 429'])) {\n          error.notFatal = true;\n          error.backoffDelay = 10000;\n        }\n\n        return callback(error, undefined);\n      }\n\n      return callback(undefined, body);\n    }\n  };\n\n  const process = (err, result) => {\n    if (err) {\n      console.log('Error importing trades:', err);\n      return;\n    }\n    trades = _.map(result.trades, function(t) {\n      return {\n        price: t.price,\n        date: Math.round(t.timestamp / 1000),\n        amount: t.volume,\n        tid: t.timestamp\n      };\n    });\n    callback(null, trades.reverse());\n  }\n\n  if (moment.isMoment(since)) since = since.valueOf();\n  (_.isNumber(since) && since > 0) ? since: since = 0;\n\n  console.log('importer getting trades from Luno since', moment.utc(since).format('YYYY-MM-DD HH:mm:ss'), 'UTC');\n\n  const handler = cb => this.luno.getTrades({ since: since, pair: this.pair }, processResponse('getTrades', cb));\n  retry(null, handler, process);\n}\n\nconst fetcher = new Fetcher(config.watch);\n\nconst fetch = () => {\n  fetcher.import = true;\n  setTimeout(() => fetcher.getTrades(from, handleFetch), REQUEST_INTERVAL);\n};\n\nconst handleFetch = (err, trades) => {\n  if (err) {\n    console.log(`There was an error importing from Luno: ${err}`);\n    fetcher.emit('done');\n    return fetcher.emit('trades', []);\n  }\n\n  if (trades.length > 0) {\n    from = moment.utc(_.last(trades).tid + 1).clone();\n  } else {\n    fetcher.emit('done');\n  }\n\n  if (from >= end) {\n    fetcher.emit('done');\n    const endUnix = end.unix();\n    trades = _.filter(trades, t => t.date <= endUnix);\n  }\n\n  fetcher.emit('trades', trades);\n};\n\nmodule.exports = function(daterange) {\n  from = daterange.from.clone().utc();\n  end = daterange.to.clone().utc();\n\n  return {\n    bus: fetcher,\n    fetch: fetch,\n  };\n};\n"
  },
  {
    "path": "importers/exchanges/poloniex.js",
    "content": "const util = require('../../core/util.js');\nconst _ = require('lodash');\nconst moment = require('moment');\nconst log = require('../../core/log');\nconst retry = require('../../exchange/exchangeUtils').retry;\n\nconst config = util.getConfig();\n\nconst dirs = util.dirs();\n\nconst Fetcher = require(dirs.exchanges + 'poloniex');\n\nconst batchSize = 60 * 2; // 2 hour\nconst overlapSize = 10; // 10 minutes\n\n// Helper methods\nfunction joinCurrencies(currencyA, currencyB){\n    return currencyA + '_' + currencyB;\n}\n\n// patch getTrades..\nFetcher.prototype.getTrades = function(range, callback) {\n  const handle = (err, result) => {\n    if(err) {\n      return callback(err);\n    }\n\n    if(_.size(result) === 50000) {\n      // to many trades..\n      util.die('too many trades..');\n    }\n\n    result = _.map(result, function(trade) {\n      return {\n        tid: trade.tradeID,\n        amount: +trade.amount,\n        date: moment.utc(trade.date).format('X'),\n        price: +trade.rate\n      };\n    });\n\n    callback(result.reverse());\n  };\n\n  const params = {\n    currencyPair: joinCurrencies(this.currency, this.asset)\n  }\n\n  params.start = range.from.unix();\n  params.end = range.to.unix();\n\n  const fetch = next => this.poloniex._public('returnTradeHistory', params, this.processResponse(next));\n  retry(null, fetch, handle);\n}\n\nutil.makeEventEmitter(Fetcher);\n\nvar iterator = false;\nvar end = false;\nvar done = false;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n  log.info(\n    config.watch.currency,\n    config.watch.asset,\n    'Requesting data from',\n    iterator.from.format('YYYY-MM-DD HH:mm:ss') + ',',\n    'to',\n    iterator.to.format('YYYY-MM-DD HH:mm:ss')\n  );\n\n  if(util.gekkoEnv === 'child-process') {\n    let msg = ['Requesting data from',\n      iterator.from.format('YYYY-MM-DD HH:mm:ss') + ',',\n      'to',\n      iterator.to.format('YYYY-MM-DD HH:mm:ss')].join('');\n    process.send({type: 'log', log: msg});\n  }\n  fetcher.getTrades(iterator, handleFetch);\n}\n\nvar handleFetch = trades => {\n  iterator.from.add(batchSize, 'minutes').subtract(overlapSize, 'minutes');\n  iterator.to.add(batchSize, 'minutes').subtract(overlapSize, 'minutes');\n\n  if(!_.size(trades)) {\n    // fix https://github.com/askmike/gekko/issues/952\n    if(iterator.to.clone().add(batchSize * 4, 'minutes') > end) {\n      fetcher.emit('done');\n    }\n\n    return fetcher.emit('trades', []);\n  }\n\n  var last = moment.unix(_.last(trades).date);\n\n  if(last > end) {\n    fetcher.emit('done');\n\n    var endUnix = end.unix();\n    trades = _.filter(\n      trades,\n      t => t.date <= endUnix\n    );\n  }\n\n  fetcher.emit('trades', trades);\n}\n\nmodule.exports = function (daterange) {\n  iterator = {\n    from: daterange.from.clone(),\n    to: daterange.from.clone().add(batchSize, 'minutes')\n  }\n  end = daterange.to.clone();\n\n  return {\n    bus: fetcher,\n    fetch: fetch\n  }\n}\n\n\n\n"
  },
  {
    "path": "importers/exchanges/therocktrading.js",
    "content": "const moment = require('moment');\nconst util = require('../../core/util');\nconst log = require('../../core/log');\nconst _ = require('lodash');\nconst retry = require('../../exchange/exchangeUtils').retry;\n\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst Fetcher = require(dirs.exchanges + 'therocktrading');\n\nFetcher.prototype.getTrades = function(since, to, page, callback, descending) {\n  const handle = (err, data) => {\n    if (err) return callback(err);\n    var trades = [];\n    if (_.isArray(data.trades)) {\n      trades = _.map(data.trades, function(trade) {\n        return {\n          tid: trade.id,\n          price: trade.price,\n          amount: trade.amount,\n          date: moment.utc(trade.date).format('X')\n        };\n      });\n    }\n\n    callback(null, descending ? trades : trades.reverse());\n  };\n\n  if (moment.isMoment(since)) since = since.format();\n  if (moment.isMoment(to)) to = to.format();\n\n  let options = {\n    before: to,\n    after: since,\n    page: page,\n    order: \"ASC\",\n    per_page: 200\n  }\n  const fetch = cb => this.therocktrading.trades(this.pair, options, this.processResponse('getTrades', cb));\n  retry(null, fetch, handle);\n};\n\nutil.makeEventEmitter(Fetcher);\n\nvar end = false;\nvar done = false;\nvar from = false;\n\nvar page = 1;\n\nvar fetcher = new Fetcher(config.watch);\n\nvar fetch = () => {\n    fetcher.import = true;\n\n    log.debug(\"IMPORTER: starting fetcher\")\n\n    fetcher.getTrades(from, end, page, handleFetch);\n}\n\nvar handleFetch = (err, trades) => {\n    if(!err && !trades.length) {\n        console.log('no more trades');\n        fetcher.emit('done');\n    }\n\n    if (err) {\n        log.error(`There was an error importing from TheRockTrading ${err}`);\n        fetcher.emit('done');\n        return fetcher.emit('trades', []);\n    }\n\n    if (trades.length > 0) {\n        page = page + 1;\n    }\n\n    fetcher.emit('trades', trades);\n}\n\nmodule.exports = function (daterange) {\n\n    from = daterange.from.clone();\n    end = daterange.to.clone();\n\n    return {\n        bus: fetcher,\n        fetch: fetch\n    }\n}\n\n\n"
  },
  {
    "path": "logs/.gitignore",
    "content": "*\n!.gitignore"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"gekko\",\n  \"version\": \"0.6.8\",\n  \"description\": \"A bitcoin trading bot for auto trading at various exchanges\",\n  \"keywords\": [\n    \"trading\",\n    \"bot\",\n    \"bitcoin\",\n    \"TA\",\n    \"finance\"\n  ],\n  \"scripts\": {\n    \"test\": \"./node_modules/.bin/mocha test/*.js --recursive test -u tdd --reporter spec\",\n    \"start\": \"node ./gekko --config config.js --ui\"\n  },\n  \"author\": \"Mike van Rossum <mike@mvr.me>\",\n  \"dependencies\": {\n    \"async\": \"2.1.2\",\n    \"bitfinex-api-node\": \"^1.2.1\",\n    \"co-fs\": \"^1.2.0\",\n    \"commander\": \"^2.13.0\",\n    \"gekko\": \"0.0.9\",\n    \"humanize-duration\": \"^3.10.0\",\n    \"koa\": \"^1.2.0\",\n    \"koa-bodyparser\": \"^2.2.0\",\n    \"koa-cors\": \"0.0.16\",\n    \"koa-logger\": \"^1.3.0\",\n    \"koa-router\": \"^5.4.0\",\n    \"koa-static\": \"^2.0.0\",\n    \"lodash\": \"2.x\",\n    \"moment\": \"^2.20.1\",\n    \"opn\": \"^4.0.2\",\n    \"promisify-node\": \"^0.5.0\",\n    \"prompt-lite\": \"0.1.1\",\n    \"relieve\": \"^2.1.3\",\n    \"retry\": \"^0.10.1\",\n    \"semver\": \"5.4.1\",\n    \"sqlite3\": \"^4.0.6\",\n    \"stats-lite\": \"^2.0.4\",\n    \"tiny-promisify\": \"^0.1.1\",\n    \"toml\": \"^2.3.0\",\n    \"ws\": \"^6.0.0\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^4.1.2\",\n    \"mocha\": \"^5.0.0\",\n    \"proxyquire\": \"^1.7.10\",\n    \"request\": \"^2.83.0\",\n    \"request-promise\": \"^4.2.2\",\n    \"sinon\": \"^4.2.0\"\n  },\n  \"engines\": {\n    \"node\": \">=8.11.2\"\n  },\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/askmike/gekko.git\"\n  }\n}\n"
  },
  {
    "path": "plugins/adviceLogger.js",
    "content": "var log = require('../core/log');\nvar moment = require('moment');\nvar _ = require('lodash');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar adviceLoggerConfig = config.adviceLogger;\n\nvar Actor = function() {\n  this.price = 'N/A';\n  this.marketTime = {format: function() {return 'N/A'}};\n  _.bindAll(this);\n}\n\nActor.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n  this.marketTime = candle.start;\n\n  done();\n};\n\nActor.prototype.processAdvice = function(advice) {\n  if (adviceLoggerConfig.muteSoft && advice.recommendation == 'soft') return;\n  console.log()\n  log.info('We have new trading advice!');\n  log.info('\\t Position:', advice.recommendation);\n  log.info('\\t Market price:', this.price);\n  log.info('\\t Based on market time:', this.marketTime.format('YYYY-MM-DD HH:mm:ss'));\n  console.log()\n};\n\nActor.prototype.finalize = function(advice, done) {\n  // todo\n  done();\n};\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins/backtestResultExporter.js",
    "content": "// Small plugin that subscribes to some events, stores\n// them and sends it to the parent process.\n\nconst log = require('../core/log');\nconst _ = require('lodash');\nconst util = require('../core/util.js');\nconst env = util.gekkoEnv();\nconst config = util.getConfig();\nconst moment = require('moment');\nconst fs = require('fs');\n\nconst BacktestResultExporter = function() {\n  this.performanceReport;\n  this.roundtrips = [];\n  this.stratUpdates = [];\n  this.stratCandles = [];\n  this.trades = [];\n\n  this.candleProps = config.backtestResultExporter.data.stratCandleProps;\n\n  if(!config.backtestResultExporter.data.stratUpdates)\n    this.processStratUpdate = null;\n\n  if(!config.backtestResultExporter.data.roundtrips)\n    this.processRoundtrip = null;\n\n  if(!config.backtestResultExporter.data.stratCandles)\n    this.processStratCandles = null;\n\n  if(!config.backtestResultExporter.data.portfolioValues)\n    this.processPortfolioValueChange = null;\n\n  if(!config.backtestResultExporter.data.trades)\n    this.processTradeCompleted = null;\n\n  _.bindAll(this);\n}\n\nBacktestResultExporter.prototype.processPortfolioValueChange = function(portfolio) {\n  this.portfolioValue = portfolio.balance;\n}\n\nBacktestResultExporter.prototype.processStratCandle = function(candle) {\n  let strippedCandle;\n\n  if(!this.candleProps) {\n    strippedCandle = {\n      ...candle,\n      start: candle.start.unix()\n    }\n  } else {\n    strippedCandle = {\n      ..._.pick(candle, this.candleProps),\n      start: candle.start.unix()\n    }\n  }\n\n  if(config.backtestResultExporter.data.portfolioValues)\n    strippedCandle.portfolioValue = this.portfolioValue;\n\n  this.stratCandles.push(strippedCandle);\n};\n\nBacktestResultExporter.prototype.processRoundtrip = function(roundtrip) {\n  this.roundtrips.push({\n    ...roundtrip,\n    entryAt: roundtrip.entryAt.unix(),\n    exitAt: roundtrip.exitAt.unix()\n  });\n};\n\nBacktestResultExporter.prototype.processTradeCompleted = function(trade) {\n  this.trades.push({\n    ...trade,\n    date: trade.date.unix()\n  });\n};\n\nBacktestResultExporter.prototype.processStratUpdate = function(stratUpdate) {\n  this.stratUpdates.push({\n    ...stratUpdate,\n    date: stratUpdate.date.unix()\n  });\n}\n\nBacktestResultExporter.prototype.processPerformanceReport = function(performanceReport) {\n  this.performanceReport = performanceReport;\n}\n\nBacktestResultExporter.prototype.finalize = function(done) {\n  const backtest = {\n    market: config.watch,\n    tradingAdvisor: config.tradingAdvisor,\n    strategyParameters: config[config.tradingAdvisor.method],\n    performanceReport: this.performanceReport\n  };\n\n  if(config.backtestResultExporter.data.stratUpdates)\n    backtest.stratUpdates = this.stratUpdates;\n\n  if(config.backtestResultExporter.data.roundtrips)\n    backtest.roundtrips = this.roundtrips;\n\n  if(config.backtestResultExporter.data.stratCandles)\n    backtest.stratCandles = this.stratCandles;\n\n  if(config.backtestResultExporter.data.trades)\n    backtest.trades = this.trades;\n\n  if(env === 'child-process') {\n    process.send({backtest});\n  }\n\n  if(config.backtestResultExporter.writeToDisk) {\n    this.writeToDisk(backtest, done);\n  } else {\n    done();\n  }\n};\n\nBacktestResultExporter.prototype.writeToDisk = function(backtest, next) {\n  let filename;\n\n  if(config.backtestResultExporter.filename) {\n    filename = config.backtestResultExporter.filename;\n  } else {\n    const now = moment().format('YYYY-MM-DD_HH-mm-ss');\n    filename = `backtest-${config.tradingAdvisor.method}-${now}.json`;\n  }\n\n  fs.writeFile(\n    util.dirs().gekko + filename,\n    JSON.stringify(backtest),\n    err => {\n      if(err) {\n        log.error('unable to write backtest result', err);\n      } else {\n        log.info('written backtest to: ', util.dirs().gekko + filename);\n      }\n\n      next();\n    }\n  );\n}\n\nmodule.exports = BacktestResultExporter;\n"
  },
  {
    "path": "plugins/blotter.js",
    "content": "const fsw = require('fs');\nconst _ = require('lodash');\nconst log = require('../core/log.js');\nconst util = require('../core/util.js');\nconst config = util.getConfig();\nconst blotterConfig = config.blotter;\n\nvar Blotter = function(done) {\n  _.bindAll(this);\n\n  this.time;\n  this.valueAtBuy = 0.0;\n  this.filename = blotterConfig.filename;\n  this.dateformat = blotterConfig.dateFormat;\n  this.timezone = blotterConfig.timezone;\n  this.headertxt = '';\n  this.outtxt = '';\n  this.tradeError = false;\n  this.inaccurateData = false;\n\n  this.done = done;\n  this.setup();\n};\n\nBlotter.prototype.setup = function(done) {\n\n  this.headertxt = \"Date,Price,Amount,Side,Fees,Value,P&L,Notes\\n\";\n\n  fsw.readFile(this.filename, (err, _) => {\n    if (err) {\n      log.warn('No file with the name', this.filename, 'found. Creating new blotter file');\n      fsw.appendFile(this.filename, this.headertxt, 'utf8', (err) => {\n        if(err) {\n          log.error('Unable to write header text to blotter');\n        }\n      });\n    } \n  });\n\n};\n\nBlotter.prototype.processTradeCompleted = function(trade) {\n  // if exchange doesn't send correct timezone, correct it\n  if (trade.date.format('Z') == '+00:00') {\n    var adjustTimezone = trade.date.utcOffset(this.timezone);\n    this.time = adjustTimezone.format(this.dateformat);\n  } else {\n    this.time = trade.date.format(this.dateformat);\n  }\n  // If a trade date is from 1969 or 1970, there was an error with the trade\n  if (trade.date.format('YY') == '69' || trade.date.format('YY') == '70') {\n    log.error('Received 1969/1970 error, trade failed to execute, did not record in blotter');\n    // Prevent roundTrip from writing error P&L in processRoundtrip method\n    if (trade.action == 'sell') {\n      this.tradeError = true;\n    }\n    return;\n  }\n\n  this.valueAtBuy = this.roundUp(trade.effectivePrice * trade.amount);\n\n  if (trade.action === 'buy') {\n    //time, price, amount, side, fees, value at buy\n    this.outtxt = this.time + \",\" + trade.effectivePrice.toFixed(2) + \",\" + trade.amount.toFixed(8) + \",\" + trade.action + \",\" + trade.feePercent + \",\" + this.valueAtBuy;\n    if ((trade.price == 0 || isNaN(trade.price)) && (trade.amount == 0|| isNaN(trade.amount))) {\n      this.outtxt = this.outtxt + \",\" + \",Trade probably went through but didn't receive correct price/amount info\\n\";\n    } else {\n      this.outtxt = this.outtxt  + \"\\n\";\n    }\n    this.writeBlotter();\n    return;\n  }\n  else if (trade.action === 'sell'){\n    var sellValue = (this.roundUp(trade.effectivePrice * trade.amount));\n    //time, price, amount, side, fees, value at sell\n    this.outtxt = this.time + \",\" + trade.effectivePrice.toFixed(2) + \",\" + trade.amount.toFixed(8) + \",\" + trade.action + \",\" + trade.feePercent + \",\" + sellValue + \",\";\n    if ((trade.price == 0 || isNaN(trade.price)) && (trade.amount == 0|| isNaN(trade.amount))) {\n      this.inaccurateData = true;\n    }\n    this.valueAtBuy = 0.0;\n    // wait til processRoundtrip complete to write to file\n  }\n\n}\n\nBlotter.prototype.writeBlotter = function() {\n  fsw.appendFile(this.filename, this.outtxt, 'utf8', (err) => {\n    if(err) {\n      log.error('Unable to write trade to blotter');\n    }\n  });\n}\n\nBlotter.prototype.processRoundtrip = function(trip) {\n  log.info('Roundtrip', trip);\n  if (!this.tradeError) {\n    this.outtxt = this.outtxt + this.roundUp(trip.pnl) +'\\n';\n    this.writeBlotter();\n    return;\n  }\n  if (this.inaccurateData) {\n    this.outtxt = this.outtxt + this.roundUp(trip.pnl) + \",Trade probably went through but didn't receive correct price/amount info\\n\";\n    this.inaccurateData = false;\n    this.writeBlotter;\n    return;\n  }\n\n  // 1969/1970 sell trade error not written to blotter, resetting flag to false \n  this.tradeError = false;\n}\n\nBlotter.prototype.roundUp = function(value) {\n  var cents = value * 100; \n  var roundedCents = Math.round(cents); \n  return roundedCents / 100; \n}\n\nmodule.exports = Blotter;\n"
  },
  {
    "path": "plugins/campfire.js",
    "content": "var _ = require('lodash');\nvar Moment = require('moment');\nvar Ranger = require('ranger');\n\nvar config = require('../core/util').getConfig().campfire;\n\nvar Actor = function() {\n  _.bindAll(this);\n\n  this.commands = [{\n    'handler': 'advice',\n    'callback': this.sayAdvice,\n    'description': \"Advice on what position to take, depending on the current trend\"\n  }, {\n    'handler': 'price',\n    'callback': this.sayPrice,\n    'description': \"The current price of the asset in the configured currency\"\n  }, {\n    'handler': 'donate',\n    'callback': this.sayDonate,\n    'description': \"Where to send all of that extra coin that's weighing you down\"\n  }, {\n    'handler': 'help',\n    'callback': this.sayHelp,\n    'description': \"You are here\"\n  }];\n\n  this.advice = null;\n  this.adviceTime = Moment.utc();\n  this.price = null;\n  this.priceTime = Moment.utc();\n\n  this.client = Ranger.createClient(config.account, config.apiKey);\n  this.client.room(config.roomId, this.joinRoom);\n  this.client.me(this.whoAmI);\n};\n\nActor.prototype = {\n  processCandle: function(candle, done) {\n    this.price = candle.close;\n    this.priceTime = candle.date.start();\n\n    done();\n  },\n\n  processAdvice: function(advice) {\n    if (campfire.muteSoft && advice.recommendation === 'soft') return;\n    this.advice = advice.recommendation;\n    this.adviceTime = Moment.utc();\n\n    if (config.emitUpdates) {\n      this.sayAdvice();\n    }\n  },\n\n  sayAdvice: function() {\n    var message;\n\n    if (this.advice !== null) {\n      message = [\"We think you should\", this.advice + \".\", \"(\" + this.adviceTime.fromNow() + \")\"];\n    } else {\n      message = [\"We don't have any advice for you quite yet.\"];\n    }\n\n    this.room.speak(message.join(' '));\n  },\n\n  sayPrice: function() {\n    var message;\n\n    if (this.price !== null) {\n      message = [\"The price at the moment is\", this.price + \".\", \"(\" + this.priceTime.fromNow() + \")\"];\n    } else {\n      message = [\"We don't know the price right now.\"];\n    }\n\n    this.room.speak(message.join(' '));\n  },\n\n  sayDonate: function() {\n    this.room.speak(\"If you'd like to donate a few coins, you can send them here: 13r1jyivitShUiv9FJvjLH7Nh1ZZptumwW\");\n  },\n\n  sayHelp: function() {\n    this.room.speak(\"I listen for the following inquiries...\", this.pasteDescriptions);\n  },\n\n  pasteDescriptions: function() {\n    var descriptions = _.map(this.commands, function(command) {\n      return [command.handler + ':', command.description].join(' ');\n    }, this).join('\\n');\n\n    this.room.paste(descriptions);\n  },\n\n  joinRoom: function(room) {\n    this.room = room;\n    this.room.join(this.listenForCommands);\n  },\n\n  listenForCommands: function() {\n    this.room.listen(this.executeCommands);\n  },\n\n  executeCommands: function(message) {\n    if (message.userId === this.user.id) return false; // Make the bot ignore itself\n    if (message.body === null) return false; // Handle weird cases where body is null sometimes\n\n    _.each(this.commands, function(command) {\n      if (this.textHasCommandForBot(message.body, config.nickname, command.handler)) {\n        command.callback();\n      }\n    }, this);\n  },\n\n  textHasCommandForBot: function(text, nickname, handler) {\n    var normalizedText = text.toLowerCase(),\n        normalizedNickname = nickname.toLowerCase(),\n        normalizedHandler = handler.toLowerCase();\n\n    var nicknameWasMentioned = normalizedText.indexOf(normalizedNickname) >= 0,\n        handlerWasMentioned = normalizedText.indexOf(normalizedHandler) >= 0;\n\n    return nicknameWasMentioned && handlerWasMentioned;\n  },\n\n  whoAmI: function(user) {\n    this.user = user;\n  }\n};\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins/candleUploader.js",
    "content": "const axios = require('axios');\nconst _ = require('lodash');\nconst log = require('../core/log.js');\nconst util = require('../core/util.js');\nconst config = util.getConfig();\n\nconst CandleUploader = function(done) {\n  _.bindAll(this);\n\n  done();\n  this.candles = [];\n  this.schedule();\n};\n\nCandleUploader.prototype.processCandle = function(candle, done) {\n  this.candles.push(candle);\n  done();\n};\n\nCandleUploader.prototype.schedule = function() {\n  this.timer = setTimeout(this.upload, 10 * 1000);\n}\n\nCandleUploader.prototype.rawUpload = function(candles, count, next) {\n\n  const amount = candles.length;\n\n  axios({\n    url: config.candleUploader.url,\n    method: 'post',\n    data: {\n      apiKey: config.candleUploader.apiKey,\n      watch: config.watch,\n      candles: candles\n    }\n  })\n    .then(r => {\n      if(r.data.success === false) {\n        console.log('error uploading:', r.data);\n      }\n      console.log(new Date, 'uploaded', amount, 'candles');\n\n      next();\n    })\n    .catch(e => {\n      console.log('error uploading:', e.message);\n\n      count++;\n\n      if(count > 10) {\n        console.log('FINAL error uploading:', e.message);\n        return next();\n      }\n\n      setTimeout(() => this.rawUpload(candles, count, next), 2000);\n    });\n}\n\nCandleUploader.prototype.upload = function() {\n  const amount = this.candles.length;\n  if(!amount) {\n    return this.schedule();\n  }\n\n  this.rawUpload(this.candles, 0, () => {\n    this.schedule();\n  });\n\n  this.candles = [];\n}\n\nCandleUploader.prototype.finish = function(next) {\n  this.upload();\n  clearTimeout(this.timer);\n}\n\nmodule.exports = CandleUploader;\n"
  },
  {
    "path": "plugins/childToParent.js",
    "content": "// Small plugin that subscribes to some events, stores\n// them and sends it to the parent process.\n\nconst log = require('../core/log');\nconst _ = require('lodash');\nconst subscriptions = require('../subscriptions');\nconst config = require('../core/util').getConfig();\n\nconst ChildToParent = function() {\n\n  subscriptions\n    // .filter(sub => config.childToParent.events.includes(sub.event))\n    .forEach(sub => {\n      this[sub.handler] = (event, next) => {\n        process.send({type: sub.event, payload: event});\n        if(_.isFunction(next)) {\n          next();\n        }\n      }\n    }, this);\n\n}\n\nmodule.exports = ChildToParent;"
  },
  {
    "path": "plugins/eventLogger.js",
    "content": "const log = require('../core/log');\nconst _ = require('lodash');\nconst subscriptions = require('../subscriptions');\nconst config = require('../core/util').getConfig().eventLogger;\n\nconst EventLogger = function() {}\n\n_.each(subscriptions, sub => {\n  if(config.whitelist && !config.whitelist.includes(sub.event)) {\n    return;\n  }\n\n  EventLogger.prototype[sub.handler] = (event, next) => {\n    log.info(`\\t\\t\\t\\t[EVENT ${sub.event}]\\n`, event);\n    if(_.isFunction(next))\n      next();\n  }\n});\n\nmodule.exports = EventLogger;"
  },
  {
    "path": "plugins/ifttt.js",
    "content": "const superagent = require('superagent');\nconst _ = require('lodash');\nconst log = require('../core/log.js');\nconst util = require('../core/util.js');\nconst config = util.getConfig();\nconst iftttConfig = config.ifttt;\n\nconst IFTTT = function(done) {\n  _.bindAll(this);\n  this.ifttt;\n  this.price = 'N/A';\n  this.done = done;\n  this.setup();\n};\n\nIFTTT.prototype.setup = function(done) {\n  var setupIFTTT = function () {\n    if(iftttConfig.sendMessageOnStart){\n      var exchange = config.watch.exchange;\n      var currency = config.watch.currency;\n      var asset = config.watch.asset;\n      var body = \"Gekko has started, Ive started watching \"\n        +exchange\n        +\" \"\n        +currency\n        +\" \"\n        +asset\n        +\" I'll let you know when I got some advice\";\n      this.send(body);\n    }else{\n      log.debug('Skipping Send message on startup')\n    }\n  };\n  setupIFTTT.call(this)\n};\n\nIFTTT.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n\n  done();\n};\n\nIFTTT.prototype.portfolioUpdate = function(portfolio) {\n  var message = \"Gekko has detected a portfolio update. \" +\n    \"Your current \" + config.watch.currency + \" balance is \" + portfolio.currency + '.' +\n    \"Your current \" + config.watch.exchange + \" balance is \" + portfolio.assert + '.';\n  this.send(message);\n}\n\nIFTTT.prototype.processAdvice = function(advice) {\n  if (advice.recommendation == 'soft' && iftttConfig.muteSoft) return;\n\n  const text = [\n    'Gekko is watching ',\n    config.watch.exchange,\n    ' and has detected a new trend, advice is to go ',\n    advice.recommendation,\n    '.\\n\\nThe current ',\n    config.watch.asset,\n    ' price is ',\n    this.price\n  ].join('');\n\n  this.send(text);\n};\n\nIFTTT.prototype.send = function(content) {\n  superagent.\n    post('https://maker.ifttt.com/trigger/' + iftttConfig.eventName + '/with/key/' + iftttConfig.makerKey)\n    .send({value1: content})\n    .end(function(err, res){\n      if(err || !res){\n        log.error('IFTTT ERROR:', error)\n      }else{\n        log.info('IFTTT Message Sent')\n      }\n    });\n};\n\nIFTTT.prototype.checkResults = function(error) {\n  if (error) {\n    log.warn('error sending IFTTT', error);\n  } else {\n    log.info('Send advice via IFTTT.');\n  }\n};\n\nmodule.exports = IFTTT;\n"
  },
  {
    "path": "plugins/ircbot.js",
    "content": "var log = require('../core/log');\nvar moment = require('moment');\nvar _ = require('lodash');\nvar config = require('../core/util').getConfig();\nvar ircbot = config.ircbot;\nvar utc = moment.utc;\n\nvar irc = require(\"irc\");\n\nvar Actor = function() {\n  _.bindAll(this);\n\n  this.bot = new irc.Client(ircbot.server, ircbot.botName, {\n    channels: [ ircbot.channel ] \n  });\n\n  this.bot.addListener(\"message\", this.verifyQuestion);\n  this.bot.addListener(\"error\", this.logError);\n\n  this.advice = 'Dont got one yet :(';\n  this.adviceTime = utc();\n\n  this.price = 'Dont know yet :(';\n  this.priceTime = utc();\n\n  this.commands = {\n    ';;advice': 'emitAdvice',\n    ';;price': 'emitPrice',\n    ';;donate': 'emitDonation',\n    ';;real advice': 'emitRealAdvice',\n    ';;help': 'emitHelp'\n  };\n\n  this.rawCommands = _.keys(this.commands);\n}\n\nActor.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n  this.priceTime = candle.start;\n\n  done();\n};\n\nActor.prototype.processAdvice = function(advice) {\n  if (advice.recommendation == \"soft\" && ircbot.muteSoft) return;\n  this.advice = advice.recommendation;\n  this.adviceTime = utc();\n\n  if(ircbot.emitUpdates)\n    this.newAdvice();\n};\n\nActor.prototype.verifyQuestion = function(from, to, text, message) {\n  if(text in this.commands)\n    this[this.commands[text]]();\n}\n\nActor.prototype.newAdvice = function() {\n  this.bot.say(ircbot.channel, 'Guys! Important news!');\n  this.emitAdvice();\n}\n\n// sent advice over to the IRC channel\nActor.prototype.emitAdvice = function() {\n  var message = [\n    'Advice for ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' using ',\n    config.tradingAdvisor.method,\n    ' at ',\n    config.tradingAdvisor.candleSize,\n    ' minute candles, is:\\n',\n    this.advice,\n    ' ',\n    config.watch.asset,\n    ' (from ',\n      this.adviceTime.fromNow(),\n    ')'\n  ].join('');\n\n  this.bot.say(ircbot.channel, message);\n};\n\n// sent price over to the IRC channel\nActor.prototype.emitPrice = function() {\n\n  var message = [\n    'Current price at ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' is ',\n    this.price,\n    ' ',\n    config.watch.currency,\n    ' (from ',\n      this.priceTime.fromNow(),\n    ')'\n  ].join('');\n\n  this.bot.say(ircbot.channel, message);\n};\n\n// sent donation info over to the IRC channel\nActor.prototype.emitDonation = function() {\n  var message = 'You want to donate? How nice of you! You can send your coins here:';\n  message += '\\nBTC:\\t13r1jyivitShUiv9FJvjLH7Nh1ZZptumwW';\n\n  this.bot.say(ircbot.channel, message);\n};\n\nActor.prototype.emitHelp = function() {\n  var message = _.reduce(\n    this.rawCommands,\n    function(message, command) {\n      return message + ' ' + command + ',';\n    },\n    'possible commands are:'\n  );\n\n  message = message.substr(0, _.size(message) - 1) + '.';\n\n  this.bot.say(ircbot.channel, message);\n\n}\n\nActor.prototype.emitRealAdvice = function() {\n  // http://www.examiner.com/article/uncaged-a-look-at-the-top-10-quotes-of-gordon-gekko\n  // http://elitedaily.com/money/memorable-gordon-gekko-quotes/\n  var realAdvice = [\n    'I don\\'t throw darts at a board. I bet on sure things. Read Sun-tzu, The Art of War. Every battle is won before it is ever fought.',\n    'Ever wonder why fund managers can\\'t beat the S&P 500? \\'Cause they\\'re sheep, and sheep get slaughtered.',\n    'If you\\'re not inside, you\\'re outside!',\n    'The most valuable commodity I know of is information.',\n    'It\\'s not a question of enough, pal. It\\'s a zero sum game, somebody wins, somebody loses. Money itself isn\\'t lost or made, it\\'s simply transferred from one perception to another.',\n    'What\\'s worth doing is worth doing for money. (Wait, wasn\\'t I a free and open source bot?)',\n    'When I get a hold of the son of a bitch who leaked this, I\\'m gonna tear his eyeballs out and I\\'m gonna suck his fucking skull.'\n  ];\n\n  this.bot.say(ircbot.channel, _.first(_.shuffle(realAdvice)));\n}\n\nActor.prototype.logError = function(message) {\n  log.error('IRC ERROR:', message);\n};\n\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins/kodi.js",
    "content": "/**\n * Created by billymcintosh on 24/12/17.\n */\n\nvar _ = require('lodash');\nvar request = require('request');\nvar log = require('../core/log.js');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar kodiConfig = config.kodi;\n\nvar Kodi = function(done) {\n    _.bindAll(this);\n\n    this.exchange = config.watch.exchange.charAt().toUpperCase() + config.watch.exchange.slice(1)\n\n    this.price = 'N/A';\n    this.done = done;\n    this.setup();\n};\n\nKodi.prototype.setup = function(done) {\n    var setupKodi = function (err, result) {\n        if(kodiConfig.sendMessageOnStart) {\n            var currency = config.watch.currency;\n            var asset = config.watch.asset;\n            var title = \"Gekko Started\";\n            var message = `Watching ${this.exchange} - ${currency}/${asset}`;\n            this.mail(title, message);\n        } else {\n            log.debug('Skipping Send message on startup')\n        }\n    }\n    setupKodi.call(this)\n};\n\nKodi.prototype.processCandle = function(candle, done) {\n    this.price = candle.close;\n\n    done();\n};\n\nKodi.prototype.processAdvice = function(advice) {\n    var title = `Gekko: Going ${advice.recommendation} @ ${this.price}`\n    var message = `${this.exchange} ${config.watch.currency}/${config.watch.asset}`;\n    this.mail(title, message);\n};\n\nKodi.prototype.mail = function(title, message, done) {\n    var options = {\n      body: `{\"jsonrpc\":\"2.0\",\"method\":\"GUI.ShowNotification\",\"params\":{\"title\":\"${title}\",\"message\":\"${message}\"},\"id\":1}`,\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      method: 'POST',\n      url: kodiConfig.host\n    }\n\n    request(options, (error, response, body) => {\n        if (!error) {\n            log.info('Kodi message sent')\n        } else {\n            log.debug(`Kodi ${error}`)\n        }\n    })\n}\n\nmodule.exports = Kodi;\n"
  },
  {
    "path": "plugins/mailer.js",
    "content": "var email = require(\"emailjs\");\nvar _ = require('lodash');\nvar log = require('../core/log.js');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar mailConfig = config.mailer;\n\nvar Mailer = function(done) {\n  _.bindAll(this);\n\n  this.server;\n  this.price = 'N/A';\n\n  this.done = done;\n  this.setup();\n};\n\nMailer.prototype.setup = function(done) {\n  var setupMail = function(err, result) {\n    if(result) {\n      console.log('Got it.');\n      mailConfig.password = result.password;\n    }\n\n    if(_.isEmpty(mailConfig.to))\n      mailConfig.to = mailConfig.email;\n    if(_.isEmpty(mailConfig.from))\n      mailConfig.from = mailConfig.email;\n    if(_.isEmpty(mailConfig.user) && mailConfig.smtpauth)\n      mailConfig.user = mailConfig.email;\n\n    this.server = email.server.connect({\n      user: mailConfig.user,\n      password: mailConfig.password,\n      host: mailConfig.server,\n      ssl: mailConfig.ssl,\n      port: mailConfig.port,\n      tls: mailConfig.tls\n    });\n\n    if(mailConfig.sendMailOnStart) {\n      this.mail(\n        \"Gekko has started\",\n        [\n          \"I've just started watching \",\n          config.watch.exchange,\n          ' ',\n          config.watch.currency,\n          '/',\n          config.watch.asset,\n          \". I'll let you know when I got some advice\"\n        ].join(''),\n        _.bind(function(err) {\n          this.checkResults(err);\n          this.done();\n        }, this)\n      );\n    } else\n      this.done();\n\n    log.debug('Setup email adviser.');\n  };\n\n  if(!mailConfig.password) {\n    // ask for the mail password\n    var prompt = require('prompt-lite');\n    prompt.start();\n    var warning = [\n      '\\n\\n\\tYou configured Gekko to mail you advice, Gekko needs your email',\n      'password to send emails (to you). Gekko is an opensource project',\n      '[ http://github.com/askmike/gekko ], you can take my word but always',\n      'check the code yourself.',\n      '\\n\\n\\tWARNING: If you have not downloaded Gekko from the github page above we',\n      'CANNOT guarantuee that your email address & password are safe!\\n'\n    ].join('\\n\\t');\n    log.warn(warning);\n    prompt.get({name: 'password', hidden: true}, _.bind(setupMail, this));\n  } else {\n    setupMail.call(this);\n  }\n};\n\nMailer.prototype.mail = function(subject, content, done) {\n\n  this.server.send({\n    text: content,\n    from: mailConfig.from,\n    to: mailConfig.to,\n    subject: mailConfig.tag + subject\n  }, done || this.checkResults);\n};\n\nMailer.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n\n  done();\n};\n\nMailer.prototype.processAdvice = function(advice) {\n\n  if (advice.recommendation == \"soft\" && mailConfig.muteSoft) return;\n\n  var text = [\n    'Gekko is watching ',\n    config.watch.exchange,\n    ' and has detected a new trend, advice is to go ',\n    advice.recommendation,\n    '.\\n\\nThe current ',\n    config.watch.asset,\n    ' price is ',\n    config.watch.currency,\n    ' ',\n    this.price\n  ].join('');\n\n  var subject = 'New advice: go ' + advice.recommendation;\n\n  this.mail(subject, text);\n};\n\nMailer.prototype.processStratNotification = function({ content }) {\n  const subject = `New notification from ${config.tradingAdvisor.method}`;\n  const text = [\n    'Gekko received new notification :\\n\\n',\n    content\n  ].join('');\n\n  this.mail(subject, text);\n}\n\nMailer.prototype.checkResults = function(err) {\n  if(err)\n    log.warn('error sending email', err);\n  else\n    log.info('Send advice via email.');\n};\n\nmodule.exports = Mailer;\n"
  },
  {
    "path": "plugins/mongodb/handle.js",
    "content": "var mongojs = require('mongojs');\r\nvar mongoUtil = require('./util');\r\n\r\nvar util = require('../../core/util.js');\r\nvar config = util.getConfig();\r\nvar dirs = util.dirs();\r\n\r\n// verify the correct dependencies are installed\r\nvar pluginHelper = require(`${dirs.core}pluginUtil`);\r\nvar pluginMock = {\r\n  slug: 'mongodb adapter',\r\n  dependencies: config.mongodb.dependencies\r\n}\r\n\r\n// exit if plugin couldn't be loaded\r\nvar cannotLoad = pluginHelper.cannotLoad(pluginMock);\r\nif (cannotLoad) {\r\n  util.die(cannotLoad);\r\n}\r\n\r\nvar mode = util.gekkoMode();\r\n\r\nvar collections = [\r\n  mongoUtil.settings.historyCollection,\r\n  mongoUtil.settings.adviceCollection\r\n]\r\n\r\nvar connection = mongojs(config.mongodb.connectionString, collections);\r\nvar collection = connection.collection(mongoUtil.settings.historyCollection);\r\n\r\nif (mode === 'backtest') {\r\n  var pair = mongoUtil.settings.pair.join('_');\r\n\r\n  collection.find({ pair }).toArray((err, docs) => { // check if we've got any records\r\n    if (err) {\r\n      util.die(err);\r\n    }\r\n    if (docs.length === 0) {\r\n      util.die(`History table for ${config.watch.exchange} with pair ${pair} is empty.`);\r\n    }\r\n  })\r\n}\r\n\r\nif(mongoUtil.settings.exchange) {\r\n    collection.createIndex({start: 1, pair: 1}, {unique: true}); // create unique index on \"time\" and \"pair\"\r\n}\r\nmodule.exports = connection;\r\n"
  },
  {
    "path": "plugins/mongodb/reader.js",
    "content": "var _ = require('lodash');\r\nvar util = require('../../core/util.js');\r\nvar log = require(`${util.dirs().core}log`);\r\n\r\nvar handle = require('./handle');\r\nvar mongoUtil = require('./util');\r\n\r\nvar Reader = function Reader () {\r\n  _.bindAll(this);\r\n  this.db = handle;\r\n  this.collection = this.db.collection(mongoUtil.settings.historyCollection);\r\n  this.pair = mongoUtil.settings.pair.join('_');\r\n}\r\n\r\n// returns the furtherst point (up to `from`) in time we have valid data from\r\nReader.prototype.mostRecentWindow = function mostRecentWindow (from, to, next) {\r\n  var mFrom = from.unix();\r\n  var mTo = to.unix();\r\n\r\n  var maxAmount = mTo - mFrom + 1;\r\n\r\n  // Find some documents\r\n  this.collection.find({ pair: this.pair, start: { $gte: mFrom, $lte: mTo } }).sort({ start: -1 }, (err, docs) => {\r\n    if (err) {\r\n      return util.die('DB error at `mostRecentWindow`');\r\n    }\r\n    // no candles are available\r\n    if (docs.length === 0) {\r\n      log.debug('no candles are available');\r\n      return next(false);\r\n    }\r\n\r\n    if (docs.length === maxAmount) {\r\n      // full history is available!\r\n      log.debug('full history is available!');\r\n      return next({\r\n        mFrom,\r\n        mTo\r\n      });\r\n    }\r\n\r\n    // we have at least one gap, figure out where\r\n    var mostRecent = _.first(docs).start;\r\n\r\n    var gapIndex = _.findIndex(docs, (r, i) => r.start !== mostRecent - i * 60);\r\n\r\n    // if there was no gap in the records, but\r\n    // there were not enough records.\r\n    if (gapIndex === -1) {\r\n      var leastRecent = _.last(docs).start;\r\n      return next({\r\n        from: leastRecent,\r\n        to: mostRecent\r\n      });\r\n    }\r\n\r\n    // else return mostRecent and the\r\n    // the minute before the gap\r\n    return next({\r\n      from: docs[gapIndex - 1].start,\r\n      to: mostRecent\r\n    });\r\n  })\r\n}\r\n\r\nReader.prototype.get = function get (from, to, what, next) { // returns all fields in general\r\n  // Find some documents\r\n  this.collection.find({ pair: this.pair, start: { $gte: from, $lte: to } }).sort({ start: 1 }, (err, docs) => {\r\n    if (err) {\r\n      return util.die('DB error at `get`');\r\n    }\r\n    return next(null, docs);\r\n  });\r\n}\r\n\r\nReader.prototype.count = function fCount (from, to, next) {\r\n  this.collection.count({ pair: this.pair, start: { $gte: from, $lte: to } }, (err, count) => {\r\n    if (err) {\r\n      return util.die('DB error at `count`');\r\n    }\r\n    return next(null, count);\r\n  })\r\n}\r\n\r\nReader.prototype.countTotal = function countTotal (next) {\r\n  this.collection.count({ pair: this.pair }, (err, count) => {\r\n    if (err) {\r\n      return util.die('DB error at `countTotal`');\r\n    }\r\n    return next(null, count);\r\n  })\r\n}\r\n\r\nReader.prototype.getBoundry = function getBoundry (next) {\r\n  this.collection.find({ pair: this.pair }, { start: 1 }).sort({ start: 1 }).limit(1, (err, docs) => {\r\n    if (err) {\r\n      return util.die('DB error at `getBoundry`');\r\n    }\r\n    var start = _.first(docs).start;\r\n\r\n    this.collection.find({ pair: this.pair }, { start: 1 }).sort({ start: -1 }).limit(1, (err2, docs2) => {\r\n      if (err2) {\r\n        return util.die('DB error at `getBoundry`');\r\n      }\r\n      var end = _.first(docs2).start;\r\n      return next(null, { first: start, last: end });\r\n    });\r\n    return null;\r\n  });\r\n}\r\n\r\nReader.prototype.tableExists = function(name, next) {\r\n  return next(null, true); // Return true for backtest\r\n}\r\n\r\nReader.prototype.close = function close () {\r\n  this.db = null;\r\n}\r\n\r\nmodule.exports = Reader;\r\n"
  },
  {
    "path": "plugins/mongodb/scanner.js",
    "content": "const async = require('async');\nvar _ = require('lodash');\nvar util = require('../../core/util.js');\nvar log = require(`${util.dirs().core}log`);\n\nvar handle = require('./handle');\n\nmodule.exports = done => {\n    this.db = handle;\n\n    let markets = [];\n    async.waterfall([\n        (cb) => {\n            handle.getCollectionNames(cb)\n        },\n        (collections, cb) => {\n            async.each(collections, (collection, cb) => {\n                let [exchange, type] = collection.split('_');\n                if (type === 'candles') {\n                    handle.collection(collection).distinct('pair', {}, (err, pairs) => {\n                        console.log(exchange);\n                        pairs.forEach((pair) => {\n                            pair = pair.split('_');\n                            markets.push({\n                                exchange: exchange,\n                                currency: _.first(pair),\n                                asset: _.last(pair)\n                            });\n                        });\n                        cb();\n                    })\n                } else {\n                    cb();\n                }\n            }, () => {\n                cb(null, markets)\n            })\n        }\n    ], done)\n}"
  },
  {
    "path": "plugins/mongodb/util.js",
    "content": "var config = require('../../core/util.js').getConfig();\r\n\r\nvar watch = config.watch;\r\nvar exchangeLowerCase = watch ? watch.exchange.toLowerCase() : watch = {}; // Do not crash on this, not needed to read from db\r\n\r\nvar settings = {\r\n  exchange: watch.exchange,\r\n  pair: [watch.currency, watch.asset],\r\n  historyCollection: `${exchangeLowerCase}_candles`,\r\n  adviceCollection: `${exchangeLowerCase}_advices`\r\n};\r\n\r\nmodule.exports = {\r\n  settings\r\n};\r\n"
  },
  {
    "path": "plugins/mongodb/writer.js",
    "content": "var _ = require('lodash');\r\nvar config = require('../../core/util.js').getConfig();\r\n\r\nvar moment = require('moment');\r\nvar util = require('../../core/util.js');\r\nvar log = require(`${util.dirs().core}log`)\r\n\r\nvar handle = require('./handle');\r\nvar mongoUtil = require('./util');\r\n\r\nvar Store = function Store (done) {\r\n  _.bindAll(this);\r\n  this.done = done;\r\n  this.db = handle;\r\n  this.historyCollection = this.db.collection(mongoUtil.settings.historyCollection);\r\n  this.adviceCollection = this.db.collection(mongoUtil.settings.adviceCollection);\r\n\r\n  this.candleCache = [];\r\n\r\n  this.pair = mongoUtil.settings.pair.join('_');\r\n\r\n  this.price = 'N/A';\r\n  this.marketTime = 'N/A';\r\n\r\n  done();\r\n}\r\n\r\nStore.prototype.writeCandles = function writeCandles () {\r\n  if (_.isEmpty(this.candleCache)) { // nothing to do\r\n    return;\r\n  }\r\n\r\n  var candles = [];\r\n  _.each(this.candleCache, candle => {\r\n    var mCandle = {\r\n      time: moment().unix(),\r\n      start: candle.start.unix(),\r\n      open: candle.open,\r\n      high: candle.high,\r\n      low: candle.low,\r\n      close: candle.close,\r\n      vwp: candle.vwp,\r\n      volume: candle.volume,\r\n      trades: candle.trades,\r\n      pair: this.pair\r\n    };\r\n    candles.push(mCandle);\r\n  });\r\n\r\n  // Fix error when whole batch would failed to insert if one or more duplicate candle\r\n  this.historyCollection.insert(candles, { ordered: false }, e => {\r\n    if (e) {\r\n      let msg = 'mongojs insert() ' + e.writeErrors.length + ' of ' + candles.length + ' failed.';\r\n      _.forEach(_.countBy(e.writeErrors, 'code'), (c, k) => {\r\n        msg += ' Code: E' + k + ' count: ' + c;\r\n      });\r\n      log.debug(msg);\r\n    }\r\n  });\r\n\r\n  this.candleCache = [];\r\n}\r\n\r\nvar processCandle = function processCandle (candle, done) {\r\n  // because we might get a lot of candles\r\n  // in the same tick, we rather batch them\r\n  // up and insert them at once at next tick.\r\n  this.price = candle.close; // used in adviceWriter\r\n  this.marketTime = candle.start;\r\n\r\n  this.candleCache.push(candle);\r\n  if (this.candleCache.length >= 100)\r\n    this.writeCandles();\r\n  done();\r\n}\r\n\r\nvar finalize = function(done) {\r\n  this.writeCandles();\r\n  // Fix connection closed before all candles was written to db\r\n  setTimeout( () => {\r\n    this.db = null;\r\n    done();\r\n  }, 1000);\r\n}\r\n\r\nvar processAdvice = function processAdvice (advice) {\r\n  if (config.candleWriter.muteSoft && advice.recommendation === 'soft') {\r\n    return;\r\n  }\r\n\r\n  log.debug(`Writing advice '${advice.recommendation}' to database.`);\r\n  var mAdvice = {\r\n    time: moment().unix(),\r\n    marketTime: this.marketTime,\r\n    pair: this.pair,\r\n    recommendation: advice.recommendation,\r\n    price: this.price,\r\n    portfolio: advice.portfolio\r\n  };\r\n\r\n  this.adviceCollection.insert(mAdvice);\r\n}\r\n\r\nif (config.adviceWriter.enabled) {\r\n  log.debug('Enabling adviceWriter.');\r\n  Store.prototype.processAdvice = processAdvice;\r\n}\r\n\r\nif (config.candleWriter.enabled) {\r\n  log.debug('Enabling candleWriter.');\r\n  Store.prototype.processCandle = processCandle;\r\n  Store.prototype.finalize = finalize;\r\n}\r\n\r\nmodule.exports = Store;\r\n"
  },
  {
    "path": "plugins/paperTrader/paperTrader.js",
    "content": "const _ = require('lodash');\n\nconst util = require('../../core/util');\nconst ENV = util.gekkoEnv();\n\nconst config = util.getConfig();\nconst calcConfig = config.paperTrader;\nconst watchConfig = config.watch;\nconst dirs = util.dirs();\nconst log = require(dirs.core + 'log');\n\nconst TrailingStop = require(dirs.broker + 'triggers/trailingStop');\n\nconst PaperTrader = function() {\n  _.bindAll(this);\n\n  if(calcConfig.feeUsing === 'maker') {\n    this.rawFee = calcConfig.feeMaker;\n  } else {\n    this.rawFee = calcConfig.feeTaker;\n  }\n\n  this.fee = 1 - this.rawFee / 100;\n\n  this.currency = watchConfig.currency;\n  this.asset = watchConfig.asset;\n\n  this.portfolio = {\n    asset: calcConfig.simulationBalance.asset,\n    currency: calcConfig.simulationBalance.currency,\n  }\n\n  this.balance = false;\n\n  if(this.portfolio.asset > 0) {\n    this.exposed = true;\n  }\n\n  this.propogatedTrades = 0;\n  this.propogatedTriggers = 0;\n\n  this.warmupCompleted = false;\n\n  this.warmupCandle;\n}\n\nPaperTrader.prototype.relayPortfolioChange = function() {\n  this.deferredEmit('portfolioChange', {\n    asset: this.portfolio.asset,\n    currency: this.portfolio.currency\n  });\n}\n\nPaperTrader.prototype.relayPortfolioValueChange = function() {\n  this.deferredEmit('portfolioValueChange', {\n    balance: this.getBalance()\n  });\n}\n\nPaperTrader.prototype.extractFee = function(amount) {\n  amount *= 1e8;\n  amount *= this.fee;\n  amount = Math.floor(amount);\n  amount /= 1e8;\n  return amount;\n}\n\nPaperTrader.prototype.setStartBalance = function() {\n  this.balance = this.getBalance();\n}\n\n// after every succesfull trend ride we hopefully end up\n// with more BTC than we started with, this function\n// calculates Gekko's profit in %.\nPaperTrader.prototype.updatePosition = function(what) {\n\n  let cost;\n  let amount;\n\n  // virtually trade all {currency} to {asset}\n  // at the current price (minus fees)\n  if(what === 'long') {\n    cost = (1 - this.fee) * this.portfolio.currency;\n    this.portfolio.asset += this.extractFee(this.portfolio.currency / this.price);\n    amount = this.portfolio.asset;\n    this.portfolio.currency = 0;\n\n    this.exposed = true;\n    this.trades++;\n  }\n\n  // virtually trade all {currency} to {asset}\n  // at the current price (minus fees)\n  else if(what === 'short') {\n    cost = (1 - this.fee) * (this.portfolio.asset * this.price);\n    this.portfolio.currency += this.extractFee(this.portfolio.asset * this.price);\n    amount = this.portfolio.currency / this.price;\n    this.portfolio.asset = 0;\n\n    this.exposed = false;\n    this.trades++;\n  }\n\n  const effectivePrice = this.price * this.fee;\n\n  return { cost, amount, effectivePrice };\n}\n\nPaperTrader.prototype.getBalance = function() {\n  return this.portfolio.currency + this.price * this.portfolio.asset;\n}\n\nPaperTrader.prototype.now = function() {\n  return this.candle.start.clone().add(1, 'minute');\n}\n\nPaperTrader.prototype.processAdvice = function(advice) {\n  let action;\n  if(advice.recommendation === 'short') {\n    action = 'sell';\n\n    // clean up potential old stop trigger\n    if(this.activeStopTrigger) {\n      this.deferredEmit('triggerAborted', {\n        id: this.activeStopTrigger.id,\n        date: advice.date\n      });\n\n      delete this.activeStopTrigger;\n    }\n\n  } else if(advice.recommendation === 'long') {\n    action = 'buy';\n\n    if(advice.trigger) {\n\n      // clean up potential old stop trigger\n      if(this.activeStopTrigger) {\n        this.deferredEmit('triggerAborted', {\n          id: this.activeStopTrigger.id,\n          date: advice.date\n        });\n\n        delete this.activeStopTrigger;\n      }\n\n      this.createTrigger(advice);\n    }\n  } else {\n    return log.warn(\n      `[Papertrader] ignoring unknown advice recommendation: ${advice.recommendation}`\n    );\n  }\n\n  this.tradeId = 'trade-' + (++this.propogatedTrades);\n\n  this.deferredEmit('tradeInitiated', {\n    id: this.tradeId,\n    adviceId: advice.id,\n    action,\n    portfolio: _.clone(this.portfolio),\n    balance: this.getBalance(),\n    date: advice.date,\n  });\n\n  const { cost, amount, effectivePrice } = this.updatePosition(advice.recommendation);\n\n  this.relayPortfolioChange();\n  this.relayPortfolioValueChange();\n\n  this.deferredEmit('tradeCompleted', {\n    id: this.tradeId,\n    adviceId: advice.id,\n    action,\n    cost,\n    amount,\n    price: this.price,\n    portfolio: this.portfolio,\n    balance: this.getBalance(),\n    date: advice.date,\n    effectivePrice,\n    feePercent: this.rawFee\n  });\n}\n\nPaperTrader.prototype.createTrigger = function(advice) {\n  const trigger = advice.trigger;\n\n  if(trigger && trigger.type === 'trailingStop') {\n\n    if(!trigger.trailValue) {\n      return log.warn(`[Papertrader] ignoring trailing stop without trail value`);\n    }\n\n    const triggerId = 'trigger-' + (++this.propogatedTriggers);\n\n    this.deferredEmit('triggerCreated', {\n      id: triggerId,\n      at: advice.date,\n      type: 'trailingStop',\n      proprties: {\n        trail: trigger.trailValue,\n        initialPrice: this.price,\n      }\n    });\n\n    this.activeStopTrigger = {\n      id: triggerId,\n      adviceId: advice.id,\n      instance: new TrailingStop({\n        initialPrice: this.price,\n        trail: trigger.trailValue,\n        onTrigger: this.onStopTrigger\n      })\n    }\n  } else {\n    log.warn(`[Papertrader] Gekko does not know trigger with type \"${trigger.type}\".. Ignoring stop.`);\n  }\n}\n\nPaperTrader.prototype.onStopTrigger = function() {\n\n  const date = this.now();\n\n  this.deferredEmit('triggerFired', {\n    id: this.activeStopTrigger.id,\n    date\n  });\n\n  const { cost, amount, effectivePrice } = this.updatePosition('short');\n\n  this.relayPortfolioChange();\n  this.relayPortfolioValueChange();\n\n  this.deferredEmit('tradeCompleted', {\n    id: this.tradeId,\n    adviceId: this.activeStopTrigger.adviceId,\n    action: 'sell',\n    cost,\n    amount,\n    price: this.price,\n    portfolio: this.portfolio,\n    balance: this.getBalance(),\n    date,\n    effectivePrice,\n    feePercent: this.rawFee\n  });\n\n  delete this.activeStopTrigger;\n}\n\nPaperTrader.prototype.processStratWarmupCompleted = function() {\n  this.warmupCompleted = true;\n  this.processCandle(this.warmupCandle, _.noop);\n}\n\nPaperTrader.prototype.processCandle = function(candle, done) {\n  if(!this.warmupCompleted) {\n    this.warmupCandle = candle;\n    return done();\n  }\n\n  this.price = candle.close;\n  this.candle = candle;\n\n  if(!this.balance) {\n    this.setStartBalance();\n    this.relayPortfolioChange();\n    this.relayPortfolioValueChange();\n  }\n\n  if(this.exposed) {\n    this.relayPortfolioValueChange();\n  }\n\n  if(this.activeStopTrigger) {\n    this.activeStopTrigger.instance.updatePrice(this.price);\n  }\n\n  done();\n}\n\nmodule.exports = PaperTrader;\n"
  },
  {
    "path": "plugins/performanceAnalyzer/logger.js",
    "content": "// log trade performance results\n\nconst _ = require('lodash');\nconst moment = require('moment');\nconst humanizeDuration = require('humanize-duration');\n\nconst util = require('../../core/util.js');\nconst dirs = util.dirs();\nconst mode = util.gekkoMode();\nconst log = require(dirs.core + 'log');\n\nconst Logger = function(watchConfig) {\n  this.currency = watchConfig.currency;\n  this.asset = watchConfig.asset;\n\n  this.roundtrips = [];\n}\n\nLogger.prototype.round = function(amount) {\n  return amount.toFixed(8);\n}\n\n// used for:\n// - realtime logging (per advice)\n// - backtest logging (on finalize)\nLogger.prototype.logReport = function(trade, report) {\n  // ignore the trade\n\n  var start = this.round(report.startBalance);\n  var current = this.round(report.balance);\n\n  log.info(`(PROFIT REPORT) original balance:\\t\\t ${start} ${this.currency}`);\n  log.info(`(PROFIT REPORT) current balance:\\t\\t ${current} ${this.currency}`);\n  log.info(\n    `(PROFIT REPORT) profit:\\t\\t\\t\\t ${this.round(report.profit)} ${this.currency}`,\n    `(${this.round(report.relativeProfit)}%)`\n  );\n}\n\nLogger.prototype.logRoundtripHeading = function() {\n  log.info('(ROUNDTRIP)', 'entry date (UTC)  \\texit date (UTC)  \\texposed duration\\tP&L \\tprofit');\n}\n\nLogger.prototype.logRoundtrip = function(rt) {\n  const display = [\n    rt.entryAt.utc().format('YYYY-MM-DD HH:mm'),\n    rt.exitAt.utc().format('YYYY-MM-DD HH:mm'),\n    (moment.duration(rt.duration).humanize() + \"           \").slice(0, 16),\n    rt.pnl.toFixed(2),\n    rt.profit.toFixed(2)\n  ];\n\n  log.info('(ROUNDTRIP)', display.join('\\t'));\n}\n\nif(mode === 'backtest') {\n  // we only want to log a summarized one line report, like:\n  // 2016-12-19 20:12:00: Paper trader simulated a BUY 0.000 USDT => 1.098 BTC\n  Logger.prototype.handleTrade = function(trade) {\n    if(trade.action !== 'sell' && trade.action !== 'buy')\n      return;\n\n    var at = trade.date.format('YYYY-MM-DD HH:mm:ss');\n\n\n    if(trade.action === 'sell')\n\n        log.info(\n          `${at}: Paper trader simulated a SELL`,\n          `\\t${this.round(trade.portfolio.currency)}`,\n          `${this.currency} <= ${this.round(trade.portfolio.asset)}`,\n          `${this.asset}`\n        );\n\n    else if(trade.action === 'buy')\n\n      log.info(\n        `${at}: Paper trader simulated a BUY`,\n        `\\t${this.round(trade.portfolio.currency)}`,\n        `${this.currency}\\t=> ${this.round(trade.portfolio.asset)}`,\n        `${this.asset}`\n      );\n  }\n\n  Logger.prototype.finalize = function(report) {\n\n    log.info();\n    log.info('(ROUNDTRIP) REPORT:');\n\n    this.logRoundtripHeading();\n    _.each(this.roundtrips, this.logRoundtrip, this);\n\n    log.info()\n    log.info(`(PROFIT REPORT) start time:\\t\\t\\t ${report.startTime}`);\n    log.info(`(PROFIT REPORT) end time:\\t\\t\\t ${report.endTime}`);\n    log.info(`(PROFIT REPORT) timespan:\\t\\t\\t ${report.timespan}`);\n    log.info(`(PROFIT REPORT) exposure:\\t\\t\\t ${report.exposure}`);\n    log.info();\n    log.info(`(PROFIT REPORT) start price:\\t\\t\\t ${report.startPrice} ${this.currency}`);\n    log.info(`(PROFIT REPORT) end price:\\t\\t\\t ${report.endPrice} ${this.currency}`);\n    log.info(`(PROFIT REPORT) Market:\\t\\t\\t\\t ${this.round(report.market)}%`);\n    log.info();\n    log.info(`(PROFIT REPORT) amount of trades:\\t\\t ${report.trades}`);\n\n    this.logReport(null, report);\n\n    log.info(\n      `(PROFIT REPORT) simulated yearly profit:\\t ${report.yearlyProfit}`,\n      `${this.currency} (${report.relativeYearlyProfit}%)`\n    );\n\n    log.info(`(PROFIT REPORT) sharpe ratio:\\t\\t\\t ${report.sharpe}`);\n    log.info(`(PROFIT REPORT) expected downside:\\t\\t ${report.downside}`);\n    log.info(`(PROFIT REPORT) ratio roundtrips:\\t\\t ${report.ratioRoundTrips}%`);\n  }\n\n  Logger.prototype.handleRoundtrip = function(rt) {\n    this.roundtrips.push(rt);\n  }\n\n} else if(mode === 'realtime') {\n  Logger.prototype.handleTrade = Logger.prototype.logReport;\n\n  Logger.prototype.handleRoundtrip = function(rt) {\n    this.logRoundtripHeading();\n    this.logRoundtrip(rt);\n  }\n\n}\n\n\n\n\nmodule.exports = Logger;\n"
  },
  {
    "path": "plugins/performanceAnalyzer/performanceAnalyzer.js",
    "content": "\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst statslite = require('stats-lite');\nconst util = require('../../core/util');\nconst log = require(util.dirs().core + 'log')\nconst ENV = util.gekkoEnv();\n\nconst config = util.getConfig();\nconst perfConfig = config.performanceAnalyzer;\nconst watchConfig = config.watch;\n\nconst Logger = require('./logger');\n\nconst PerformanceAnalyzer = function() {\n  _.bindAll(this);\n\n  this.dates = {\n    start: false,\n    end: false\n  }\n\n  this.startPrice = 0;\n  this.endPrice = 0;\n\n  this.currency = watchConfig.currency;\n  this.asset = watchConfig.asset;\n\n  this.logger = new Logger(watchConfig);\n\n  this.trades = 0;\n\n  this.exposure = 0;\n\n  this.roundTrips = [];\n  this.losses = [];\n  this.roundTrip = {\n    id: 0,\n    entry: false,\n    exit: false\n  }\n\n  this.portfolio = {};\n  this.balance;\n\n  this.start = {};\n  this.openRoundTrip = false;\n\n  this.warmupCompleted = false;\n}\n\nPerformanceAnalyzer.prototype.processPortfolioValueChange = function(event) {\n  if(!this.start.balance) {\n    this.start.balance = event.balance;\n  }\n\n  this.balance = event.balance;\n}\n\nPerformanceAnalyzer.prototype.processPortfolioChange = function(event) {\n  if(!this.start.portfolio) {\n    this.start.portfolio = event;\n  }\n}\n\nPerformanceAnalyzer.prototype.processStratWarmupCompleted = function() {\n  this.warmupCompleted = true;\n  this.processCandle(this.warmupCandle, _.noop);\n}\n\nPerformanceAnalyzer.prototype.processCandle = function(candle, done) {\n  if(!this.warmupCompleted) {\n    this.warmupCandle = candle;\n    return done();\n  }\n\n  this.price = candle.close;\n  this.dates.end = candle.start.clone().add(1, 'minute');\n\n  if(!this.dates.start) {\n    this.dates.start = candle.start;\n    this.startPrice = candle.close;\n  }\n\n  this.endPrice = candle.close;\n\n  if(this.openRoundTrip) {\n    this.emitRoundtripUpdate();\n  }\n\n  done();\n}\n\nPerformanceAnalyzer.prototype.emitRoundtripUpdate = function() {\n  const uPnl = this.price - this.roundTrip.entry.price;\n\n  this.deferredEmit('roundtripUpdate', {\n    at: this.dates.end,\n    duration: this.dates.end.diff(this.roundTrip.entry.date),\n    uPnl,\n    uProfit: uPnl / this.roundTrip.entry.total * 100\n  })\n}\n\nPerformanceAnalyzer.prototype.processTradeCompleted = function(trade) {\n  this.trades++;\n  this.portfolio = trade.portfolio;\n  this.balance = trade.balance;\n\n  this.registerRoundtripPart(trade);\n\n  const report = this.calculateReportStatistics();\n  if(report) {\n    this.logger.handleTrade(trade, report);\n    this.deferredEmit('performanceReport', report);\n  }\n}\n\nPerformanceAnalyzer.prototype.registerRoundtripPart = function(trade) {\n  if(this.trades === 1 && trade.action === 'sell') {\n    // this is not part of a valid roundtrip\n    return;\n  }\n\n  if(trade.action === 'buy') {\n    if (this.roundTrip.exit) {\n      this.roundTrip.id++;\n      this.roundTrip.exit = false\n    }\n\n    this.roundTrip.entry = {\n      date: trade.date,\n      price: trade.price,\n      total: trade.portfolio.currency + (trade.portfolio.asset * trade.price),\n    }\n    this.openRoundTrip = true;\n  } else if(trade.action === 'sell') {\n    this.roundTrip.exit = {\n      date: trade.date,\n      price: trade.price,\n      total: trade.portfolio.currency + (trade.portfolio.asset * trade.price),\n    }\n    this.openRoundTrip = false;\n\n    this.handleCompletedRoundtrip();\n  }\n}\n\nPerformanceAnalyzer.prototype.handleCompletedRoundtrip = function() {\n  var roundtrip = {\n    id: this.roundTrip.id,\n\n    entryAt: this.roundTrip.entry.date,\n    entryPrice: this.roundTrip.entry.price,\n    entryBalance: this.roundTrip.entry.total,\n\n    exitAt: this.roundTrip.exit.date,\n    exitPrice: this.roundTrip.exit.price,\n    exitBalance: this.roundTrip.exit.total,\n\n    duration: this.roundTrip.exit.date.diff(this.roundTrip.entry.date)\n  }\n\n  roundtrip.pnl = roundtrip.exitBalance - roundtrip.entryBalance;\n  roundtrip.profit = (100 * roundtrip.exitBalance / roundtrip.entryBalance) - 100;\n\n  this.roundTrips[this.roundTrip.id] = roundtrip;\n\n  this.logger.handleRoundtrip(roundtrip);\n\n  this.deferredEmit('roundtrip', roundtrip);\n\n  // update cached exposure\n  this.exposure = this.exposure + Date.parse(this.roundTrip.exit.date) - Date.parse(this.roundTrip.entry.date);\n  // track losses separately for downside report\n  if (roundtrip.exitBalance < roundtrip.entryBalance)\n    this.losses.push(roundtrip);\n\n}\n\nPerformanceAnalyzer.prototype.calculateReportStatistics = function() {\n  if(!this.start.balance || !this.start.portfolio) {\n    log.error('Cannot calculate a profit report without having received portfolio data.');\n    log.error('Skipping performanceReport..');\n    return false;\n  }\n\n  // the portfolio's balance is measured in {currency}\n  const profit = this.balance - this.start.balance;\n\n  const timespan = moment.duration(\n    this.dates.end.diff(this.dates.start)\n  );\n  const relativeProfit = this.balance / this.start.balance * 100 - 100;\n  const relativeYearlyProfit = relativeProfit / timespan.asYears();\n\n  const percentExposure = this.exposure / (Date.parse(this.dates.end) - Date.parse(this.dates.start));\n\n  const sharpe = (relativeYearlyProfit - perfConfig.riskFreeReturn)\n    / statslite.stdev(this.roundTrips.map(r => r.profit))\n    / Math.sqrt(this.trades / (this.trades - 2));\n\n  const downside = statslite.percentile(this.losses.map(r => r.profit), 0.25)\n    * Math.sqrt(this.trades / (this.trades - 2));\n\n  const ratioRoundTrips = this.roundTrips.length > 0 ? (this.roundTrips.filter(roundTrip => roundTrip.pnl > 0 ).length / this.roundTrips.length * 100).toFixed(4) : 100;\n\n  const report = {\n    startTime: this.dates.start.utc().format('YYYY-MM-DD HH:mm:ss'),\n    endTime: this.dates.end.utc().format('YYYY-MM-DD HH:mm:ss'),\n    timespan: timespan.humanize(),\n    market: this.endPrice * 100 / this.startPrice - 100,\n\n    balance: this.balance,\n    profit,\n    relativeProfit: relativeProfit,\n\n    yearlyProfit: profit / timespan.asYears(),\n    relativeYearlyProfit,\n\n    startPrice: this.startPrice,\n    endPrice: this.endPrice,\n    trades: this.trades,\n    startBalance: this.start.balance,\n    exposure: percentExposure,\n    sharpe,\n    downside,\n    ratioRoundTrips\n  }\n\n  report.alpha = report.relativeProfit - report.market;\n\n  return report;\n}\n\nPerformanceAnalyzer.prototype.finalize = function(done) {\n  if(!this.trades) {\n    return done();\n  }\n\n  const report = this.calculateReportStatistics();\n  if(report) {\n    this.logger.finalize(report);\n    this.emit('performanceReport', report);\n  }\n  done();\n}\n\n\nmodule.exports = PerformanceAnalyzer;\n"
  },
  {
    "path": "plugins/postgresql/handle.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\n\nconst util = require('../../core/util.js');\nconst config = util.getConfig();\nconst dirs = util.dirs();\n\nconst log = require(util.dirs().core + 'log');\nconst postgresUtil = require('./util');\n\nconst adapter = config.postgresql;\n\n// verify the correct dependencies are installed\nconst pluginHelper = require(dirs.core + 'pluginUtil');\nconst pluginMock = {\n  slug: 'postgresql adapter',\n  dependencies: config.postgresql.dependencies\n}\n\nconst cannotLoad = pluginHelper.cannotLoad(pluginMock);\nif(cannotLoad) {\n  util.die(cannotLoad);\n}\n\nconst pg = require('pg');\n\nconst version = adapter.version;\n\nconst dbName = postgresUtil.database();\n\nconst mode = util.gekkoMode();\n\nconst connectionString = config.postgresql.connectionString;\n\nconst checkClient = new pg.Pool({\n  connectionString: connectionString + '/postgres',\n});\nconst pool = new pg.Pool({\n  connectionString: connectionString + '/' + dbName,\n});\n\n// We need to check if the db exists first.\n// This requires connecting to the default\n// postgres database first. Your postgres\n// user will need appropriate rights.\ncheckClient.connect((err, client, done) => {\n  if(err) {\n    util.die(err);\n  }\n\n  log.debug(\"Check database exists: \" + dbName);\n  client.query(\"select count(*) from pg_catalog.pg_database where datname = $1\", [dbName],\n    (err, res) => {\n      if(err) {\n        util.die(err);\n      }\n\n      if(res.rows[0].count !== '0') {\n        // database exists\n        log.debug(\"Database exists: \" + dbName);\n        log.debug(\"Postgres connection pool is ready, db \" + dbName);\n        upsertTables();\n        done();\n        return;\n      }\n\n      // database dot NOT exist\n\n      if(mode === 'backtest') {\n        // no point in trying to backtest with\n        // non existing data.\n        util.die(`History does not exist for exchange ${config.watch.exchange}.`);\n      }\n\n      createDatabase(client, done);\n    });\n});\n\nconst createDatabase = (client, done) => {\n  client.query(\"CREATE DATABASE \" + dbName, err => {\n    if(err) {\n      util.die(err);\n    }\n\n    log.debug(\"Postgres connection pool is ready, db \" + dbName);\n    done();\n    upsertTables();\n  });\n}\n\nconst upsertTables = () => {\n  const upsertQuery =\n    `CREATE TABLE IF NOT EXISTS\n    ${postgresUtil.table('candles')} (\n      id BIGSERIAL PRIMARY KEY,\n      start integer UNIQUE,\n      open double precision NOT NULL,\n      high double precision NOT NULL,\n      low double precision NOT NULL,\n      close double precision NOT NULL,\n      vwp double precision NOT NULL,\n      volume double precision NOT NULL,\n      trades INTEGER NOT NULL\n    );`;\n\n  pool.query(upsertQuery, (err) => {\n    if(err) {\n      util.die(err);\n    }\n  });\n}\n\n\nmodule.exports = pool;\n"
  },
  {
    "path": "plugins/postgresql/reader.js",
    "content": "var _ = require('lodash');\nvar util = require('../../core/util.js');\nvar config = util.getConfig();\nvar log = require(util.dirs().core + 'log');\n\nvar handle = require('./handle');\nvar postgresUtil = require('./util');\n\nconst { Query } = require('pg');\n\nvar Reader = function() {\n  _.bindAll(this);\n  this.db = handle;\n}\n\n// returns the furthest point (up to `from`) in time we have valid data from\nReader.prototype.mostRecentWindow = function(from, to, next) {\n  to = to.unix();\n  from = from.unix();\n\n  var maxAmount = to - from + 1;\n  \n  this.db.connect((err, client, done) => {\n\n    if(err) {\n      log.error(err);\n      return util.die(err.message);\n    }\n\n    var query = client.query(new Query(`\n      SELECT start from ${postgresUtil.table('candles')}\n      WHERE start <= ${to} AND start >= ${from}\n      ORDER BY start DESC\n    `), function (err, result) {\n      if (err) {\n        // bail out if the table does not exist\n        if (err.message.indexOf(' does not exist') !== -1)\n          return next(false);\n\n        log.error(err);\n        return util.die('DB error while reading mostRecentWindow');\n      }\n    });\n\n    var rows = [];\n    query.on('row', function(row) {\n      rows.push(row);\n    });\n\n    // After all data is returned, close connection and return results\n    query.on('end', function() {\n      done();\n      // no candles are available\n      if(rows.length === 0) {\n        return next(false);\n      }\n\n      if(rows.length === maxAmount) {\n\n        // full history is available!\n\n        return next({\n          from: from,\n          to: to\n        });\n      }\n\n      // we have at least one gap, figure out where\n      var mostRecent = _.first(rows).start;\n\n      var gapIndex = _.findIndex(rows, function(r, i) {\n        return r.start !== mostRecent - i * 60;\n      });\n\n      // if there was no gap in the records, but\n      // there were not enough records.\n      if(gapIndex === -1) {\n        var leastRecent = _.last(rows).start;\n        return next({\n          from: leastRecent,\n          to: mostRecent\n        });\n      }\n\n      // else return mostRecent and the\n      // the minute before the gap\n      return next({\n        from: rows[ gapIndex - 1 ].start,\n        to: mostRecent\n      });\n    });\n  });  \n}\n\nReader.prototype.tableExists = function (name, next) {\n  this.db.connect((err,client,done) => {\n    client.query(`\n      SELECT table_name\n      FROM information_schema.tables\n      WHERE table_schema='${postgresUtil.schema()}'\n        AND table_name='${postgresUtil.table(name)}';\n    `, function(err, result) {\n      done();\n      if (err) {\n        return util.die('DB error at `tableExists`');\n      }\n\n      next(null, result.rows.length === 1);\n    });\n  });  \n}\n\nReader.prototype.get = function(from, to, what, next) {\n  if(what === 'full'){\n    what = '*';\n  }\n  \n  this.db.connect((err,client,done) => {\n    var query = client.query(new Query(`\n    SELECT ${what} from ${postgresUtil.table('candles')}\n    WHERE start <= ${to} AND start >= ${from}\n    ORDER BY start ASC\n    `));\n\n    var rows = [];\n    query.on('row', function(row) {\n      rows.push(row);\n    });\n\n    query.on('end',function(){\n      done();\n      next(null, rows);\n    });\n  });  \n}\n\nReader.prototype.count = function(from, to, next) {\n  this.db.connect((err,client,done) => {\n    if(err) {\n      log.error(err);\n      return util.die(err.message);\n    }\n\n    var query = client.query(new Query(`\n      SELECT COUNT(*) as count from ${postgresUtil.table('candles')}\n      WHERE start <= ${to} AND start >= ${from}\n    `));\n    var rows = [];\n    query.on('row', function(row) {\n      rows.push(row);\n    });\n\n    query.on('end',function(){\n      done();\n      next(null, _.first(rows).count);\n    });\n  });  \n}\n\nReader.prototype.countTotal = function(next) {\n  this.db.connect((err,client,done) => {\n    var query = client.query(new Query(`\n    SELECT COUNT(*) as count from ${postgresUtil.table('candles')}\n    `));\n    var rows = [];\n    query.on('row', function(row) {\n      rows.push(row);\n    });\n\n    query.on('end',function(){\n      done();\n      next(null, _.first(rows).count);\n    });\n  });  \n}\n\nReader.prototype.getBoundry = function(next) {\n  this.db.connect((err,client,done) => {\n    var query = client.query(new Query(`\n    SELECT (\n      SELECT start\n      FROM ${postgresUtil.table('candles')}\n      ORDER BY start LIMIT 1\n    ) as first,\n    (\n      SELECT start\n      FROM ${postgresUtil.table('candles')}\n      ORDER BY start DESC\n      LIMIT 1\n    ) as last\n    `));\n    var rows = [];\n    query.on('row', function(row) {\n      rows.push(row);\n    });\n\n    query.on('end',function(){\n      done();\n      next(null, _.first(rows));\n    });\n  });  \n}\n\nReader.prototype.close = function() {\n  //obsolete due to connection pooling\n  //this.db.end();\n}\n\nmodule.exports = Reader;\n"
  },
  {
    "path": "plugins/postgresql/scanner.js",
    "content": "const _ = require('lodash');\nconst async = require('async');\nvar pg = require('pg');\n\nconst util = require('../../core/util.js');\nconst config = util.getConfig();\nconst dirs = util.dirs();\nvar postgresUtil = require('./util');\n\nvar connectionString = config.postgresql.connectionString;\n\n\nmodule.exports = done => {\n  var scanClient = new pg.Client(connectionString+\"/postgres\");\n\n  let markets = [];\n\n  scanClient.connect(function (err) {\n    if(err){\n      util.die(err);\n    }\n\n    var sql = \"select datname from pg_database\";\n\n    // In single DB setup we don't need to go look into other DBs\n    if (postgresUtil.useSingleDatabase()) {\n      sql = \"select datname from pg_database where datname='\" + postgresUtil.database() + \"'\";\n    }\n\n    var query = scanClient.query(sql, function (err, result) {\n\n      async.each(result.rows, (dbRow, next) => {\n\n        var scanTablesClient = new pg.Client(connectionString + \"/\" + dbRow.datname);\n        var dbName = dbRow.datname;\n\n        scanTablesClient.connect(function (err) {\n          if (err) {\n            return next();\n          }\n\n          var query = scanTablesClient.query(`\n            SELECT table_name\n            FROM information_schema.tables\n            WHERE table_schema='${postgresUtil.schema()}';\n          `, function(err, result) {\n            if (err) {\n              return util.die('DB error at `scanning tables`');\n            }\n\n            _.each(result.rows, table => {\n              let parts = table.table_name.split('_');\n              let first = parts.shift();\n              let exchangeName = dbName;\n\n              /**\n               * If using single database, we need to strip\n               * exchange from table name. See here how tables\n               * are named:\n               *\n               * - in single database setup: poloniex_candles_usdt_btc\n               * - in multi db setup: db = poloniex, table = candles_usdt_btc\n               */\n              if (postgresUtil.useSingleDatabase()) {\n                exchangeName = first;\n                first = parts.shift();\n              }\n\n              if(first === 'candles')\n                markets.push({\n                  exchange: exchangeName,\n                  currency: _.first(parts),\n                  asset: _.last(parts)\n                });\n            });\n\n            scanTablesClient.end();\n\n            next();\n          });\n        });\n\n      },\n      // got all tables!\n      err => {\n        scanClient.end();\n        done(err, markets);\n      });\n\n    });\n\n  });\n}"
  },
  {
    "path": "plugins/postgresql/util.js",
    "content": "var config = require('../../core/util.js').getConfig();\n\nvar watch = config.watch;\nif(watch) {\n  var settings = {\n    exchange: watch.exchange,\n    pair: [watch.currency, watch.asset]\n  }\n}\n\n/**\n * Returns true if we use single database where\n * all our tables are stored. The default is to store\n * every exchange into it's own db.\n *\n * Set config.postgresql.database to use single db setup\n */\nfunction useSingleDatabase() {\n    return !!config.postgresql.database;\n}\n\n/**\n * Postgres has tables in lowercase if you don't\n * escape their names. Which we don't and so let's\n * just lowercase them.\n */\nfunction useLowerCaseTableNames() {\n  return !config.postgresql.noLowerCaseTableName;\n}\n\nmodule.exports = {\n  settings: settings,\n\n  // true if we have single db setup (see postrgesql.database config key)\n  useSingleDatabase: useSingleDatabase,\n\n  // returns DB name (depends on single db setup)\n  database: function () {\n    return useSingleDatabase() ?\n      config.postgresql.database :\n      config.watch.exchange.toLowerCase().replace(/\\-/g,'');\n  },\n\n  // returns table name which can be different if we use\n  // single or multiple db setup.\n  table: function (name) {\n    if (useSingleDatabase()) {\n      name = watch.exchange.replace(/\\-/g,'') + '_' + name;\n    }\n    var fullName = [name, settings.pair.join('_')].join('_');\n    return useLowerCaseTableNames() ? fullName.toLowerCase() : fullName;\n  },\n\n  startconstraint: function (name) {\n    if (useSingleDatabase()) {\n      name = watch.exchange.replace(/\\-/g,'') + '_' + name;\n    }\n    var fullName = [name, settings.pair.join('_')].join('_');\n    return useLowerCaseTableNames() ? fullName.toLowerCase() + '_start_key' : fullName + '_start_key';\n  },\n\n  // postgres schema name. defaults to 'public'\n  schema: function () {\n    return config.postgresql.schema ? config.postgresql.schema : 'public';\n  }\n}\n"
  },
  {
    "path": "plugins/postgresql/writer.js",
    "content": "var _ = require('lodash');\nconst log = require('../../core/log');\nconst util = require('../../core/util');\nconst config = util.getConfig();\n\nvar handle = require('./handle');\nvar postgresUtil = require('./util');\n\nvar Store = function(done, pluginMeta) {\n  _.bindAll(this);\n  this.done = done;\n  this.db = handle;\n  this.cache = [];\n  done();\n}\n\nStore.prototype.writeCandles = function() {\n  if(_.isEmpty(this.cache)){\n    return;\n  }\n\n  //log.debug('Writing candles to DB!');\n  _.each(this.cache, candle => {\n    var stmt =  `\n    BEGIN; \n    LOCK TABLE ${postgresUtil.table('candles')} IN SHARE ROW EXCLUSIVE MODE; \n    INSERT INTO ${postgresUtil.table('candles')} \n    (start, open, high,low, close, vwp, volume, trades) \n    VALUES \n    (${candle.start.unix()}, ${candle.open}, ${candle.high}, ${candle.low}, ${candle.close}, ${candle.vwp}, ${candle.volume}, ${candle.trades}) \n    ON CONFLICT ON CONSTRAINT ${postgresUtil.startconstraint('candles')} \n    DO NOTHING; \n    COMMIT; \n    `;\n\n    this.db.connect((err,client,done) => {\n      if(err) {\n        util.die(err);\n      }\n      client.query(stmt, (err, res) => {\n        done();\n        if (err) {\n          log.debug(err.stack)\n        } else {\n          //log.debug(res)\n        }\n      });\n    });\n  });\n\n  this.cache = [];\n}\n\nvar processCandle = function(candle, done) {\n  this.cache.push(candle);\n  if (this.cache.length > 1)\n    this.writeCandles();\n\n  done();\n};\n\nvar finalize = function(done) {\n  this.writeCandles();\n  this.db = null;\n  done();\n}\n\nif(config.candleWriter.enabled) {\n  Store.prototype.processCandle = processCandle;\n  Store.prototype.finalize = finalize;\n}\n\nmodule.exports = Store;\n"
  },
  {
    "path": "plugins/pushbullet.js",
    "content": "/**\n * Created by rocketman1337345 on 8/14/16.\n * Extended by RJPGriffin (Gryphon) on 30/5/18\n */\n\n\n/**\nRequired Config:\n\nconfig.pushbullet = {\n  // sends pushbullets if true\n  enabled: true,\n  // Send 'Gekko starting' message if true\n  sendMessageOnStart: true,\n  // Send Message for advice? Recommend Flase for paper, true for live\n  sendOnAdvice: true,\n  // Send Message on Trade Completion?\n  sendOnTrade: true,\n  // For Overall P/L calc. Pass in old balance if desired, else leave '0'\n  startingBalance: '0',\n  // your pushbullet API key\n  key: '',\n  // your email\n  email: 'jon_snow@westeros.com',\n  // Messages will start with this tag\n  tag: '[GEKKO]'\n};\n\n\n **/\n\nvar pushbullet = require(\"pushbullet\");\nvar _ = require('lodash');\nconst moment = require('moment');\nconst request = require('request');\nvar log = require('../core/log.js');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar pbConf = config.pushbullet;\n\nvar Pushbullet = function(done) {\n  _.bindAll(this);\n\n  this.pusher;\n  this.price = 'N/A';\n  this.startingBalance = pbConf.startingBalance === undefined ? 0 : Number(pbConf.startingBalance);\n  this.advicePrice = 0;\n  this.adviceTime = moment();\n  this.lastBuyTime = moment();\n  this.lastBuyBalance = 0;\n  this.hasBought = 0;\n\n  this.done = done;\n  this.setup();\n};\n\nPushbullet.prototype.setup = function(done) {\n\n  var setupPushBullet = function(err, result) {\n    if (pbConf.sendMessageOnStart) {\n      var title = pbConf.tag;\n      var exchange = config.watch.exchange;\n      var currency = config.watch.currency;\n      var asset = config.watch.asset;\n      let tradeType = 'watching';\n      if (config.trader.enabled) {\n        tradeType = \"Live Trading\";\n      }\n      if (config.paperTrader.enabled) {\n        tradeType = \"Paper Trading\";\n      }\n\n      var body = `Gekko has started ${tradeType} ${asset}/${currency} on ${exchange}.`;\n\n      //If trading Advisor is enabled, add strategy and candle size information\n      if (config.tradingAdvisor.enabled) {\n        body += `\\n\\nUsing ${config.tradingAdvisor.method} strategy on M${config.tradingAdvisor.candleSize} candles.`\n      }\n\n      this.mail(title, body);\n    } else {\n      log.debug('Skipping Send message on startup')\n    }\n  };\n  setupPushBullet.call(this)\n};\n\nPushbullet.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n\n  done();\n};\n\n\nPushbullet.prototype.processAdvice = function(advice) {\n\n  this.advicePrice = this.price;\n  this.adviceTime = advice.date;\n\n  if (pbConf.sendOnAdvice) {\n\n    var text = [\n      'Gekko has new advice for ',\n      capF(config.watch.exchange),\n      ', advice is to go ',\n      capF(advice.recommendation),\n      '.\\n\\nThe current ',\n      config.watch.asset,\n      ' price is ',\n      this.advicePrice\n    ].join('');\n\n    var subject = pbConf.tag + ' New advice: go ' + advice.recommendation;\n\n    this.mail(subject, text);\n  }\n};\n\nPushbullet.prototype.processTradeCompleted = function(trade) {\n\n  //Check Starting balance is initialized - if 0, initialize it\n  this.startingBalance = this.startingBalance ? this.startingBalance : trade.balance;\n\n  // If config variable doesn't exist (old config) defaults to send\n  let sendOnTrade = pbConf.sendOnTrade === undefined ? 1 : pbConf.sendOnTrade;\n\n  if (sendOnTrade) {\n\n    // Calculate exposure Time\n    let exposureTimeStr = '';\n    let balanceChangeStr = '\\n';\n    let totBalanceChangeStr = '';\n    let subject = `${pbConf.tag} ${capF(trade.action)} complete`;\n\n    if (trade.action === 'buy') {\n      this.hasBought = 1; // Flag to ensure that the following variables have been filled\n      this.lastBuyTime = trade.date;\n      this.lastBuyBalance = trade.balance;\n    } else if (this.hasBought) { //if sell and we have previous buy data\n      exposureTimeStr = `\\nExposure Time: ${moment.duration(trade.date.diff(this.lastBuyTime)).humanize()}`;\n\n      //Calculate balance change\n      let oBal = this.lastBuyBalance; // Old Balance\n      let nBal = trade.balance; // New Balance\n      let diffBal = Math.abs(nBal - oBal); // Balance Difference\n      let percDiffBal = (diffBal / oBal) * 100; // Percentage difference\n\n\n      if (nBal >= oBal) { // profit!\n        balanceChangeStr = `\\n\\nRound trip profit of: \\n${getNumStr(diffBal)}${config.watch.currency} \\n${getNumStr(percDiffBal,2)}%\\n`\n        subject = `${subject}: +${getNumStr(percDiffBal,2)}%`\n      } else if (nBal < oBal) { //  Loss :(\n        balanceChangeStr = `\\n\\nRound trip loss of: \\n-${getNumStr(diffBal)}${config.watch.currency} \\n-${getNumStr(percDiffBal,2)}%\\n`\n        subject = `${subject}: -${getNumStr(percDiffBal,2)}%`\n      }\n\n      //Calculate overall P/l\n      let sBal = this.startingBalance;\n      let tDiffBal = Math.abs(nBal - sBal);\n      let percDiffTotBal = (tDiffBal / sBal) * 100;\n      if (nBal >= sBal) { // profit!\n        totBalanceChangeStr = `\\nOverall gain of: \\n${getNumStr(tDiffBal)}${config.watch.currency} \\n${getNumStr(percDiffTotBal,2)}%\\n`\n      } else if (nBal < sBal) { //  Loss :(\n        totBalanceChangeStr = `\\nOverall loss of \\n-${getNumStr(tDiffBal)}${config.watch.currency} \\n-${getNumStr(percDiffTotBal,2)}%\\n`\n\n      } else if (trade.action === 'sell' && !this.hasBought) {\n        balanceChangeStr = `\\n\\nNot enough data for exposure time, round trip or overall performance yet. This will appear after bot has completed first round trip.`\n      }\n    }\n\n    let costOfTradeStr = `\\nCost of Trade: ${getNumStr(trade.cost)}${config.watch.currency}, ${getNumStr(((trade.cost / (trade.amount*trade.price)) * 100), 2)}%`;\n\n    //build strings that are only sent for Live trading, not paperTrader\n    let orderFillTimeStr = '';\n    let slippageStr = '';\n\n    if (!config.paperTrader.enabled) {\n      let timeToComplete = moment.duration(trade.date.diff(this.adviceTime)).humanize();\n      orderFillTimeStr = `\\nOrder fill Time: ${timeToComplete}`;\n\n      var slip;\n      //Slip direction is opposite for buy and sell\n      if (trade.price === this.advicePrice) {\n        slip = 0;\n      } else if (trade.action === 'buy') {\n        slip = 100 * ((trade.price - this.advicePrice) / this.advicePrice);\n      } else if (trade.action === 'sell') {\n        slip = 100 * ((this.advicePrice - trade.price) / this.advicePrice);\n      }\n      slippageStr = `\\nSlipped ${getNumStr(slip,2)}% from advice @ ${getNumStr(this.advicePrice)}`;\n\n\n    }\n\n    var text = [\n      capF(config.watch.exchange), ' ', config.watch.asset, '/', config.watch.currency,\n      `\\n\\n${config.watch.asset} Trade Price: ${getNumStr(trade.price)}`,\n      `\\n${getPastTense(trade.action)} ${getNumStr(trade.amount)} ${config.watch.asset}`,\n      orderFillTimeStr,\n      slippageStr,\n      costOfTradeStr,\n      exposureTimeStr,\n      balanceChangeStr,\n      totBalanceChangeStr,\n      '\\nBalance: ', getNumStr(trade.balance), config.watch.currency,\n    ].join('');\n\n    this.mail(subject, text);\n  }\n};\n\n\n// A long winded function to make sure numbers aren't displayed with too many decimal places\n// and are a little humanized\nfunction getNumStr(num, fixed = 4) {\n  let numStr = '';\n\n  if (typeof num != \"number\") {\n    num = Number(num);\n    if (isNaN(num)) {\n      // console.log(\"Pushbullet Plugin: Number Conversion Failed\");\n      return \"Conversion Failure\";\n    }\n  }\n\n\n  if (Number.isInteger(num)) {\n    numStr = num.toString();\n  } else {\n\n    //Create modNum Max - Must be a better way...\n    let modNumMax = '1';\n    for (let i = 1; i < fixed; i++) {\n      modNumMax = modNumMax + '0';\n    }\n    modNumMax = Number(modNumMax);\n\n    let i = 0;\n    if (num < 1) {\n      let modNum = num - Math.floor(num);\n      while (modNum < modNumMax && i < 8) {\n        modNum *= 10;\n        i += 1;\n      }\n    } else {\n      i = fixed;\n    }\n    numStr = num.toFixed(i);\n    //Remove any excess zeros\n    while (numStr.charAt(numStr.length - 1) === '0') {\n      numStr = numStr.substring(0, numStr.length - 1);\n    }\n\n    //If last char remaining is a decimal point, remove it\n    if (numStr.charAt(numStr.length - 1) === '.') {\n      numStr = numStr.substring(0, numStr.length - 1);\n    }\n\n  }\n\n  //Add commas for thousands etc\n  let dp = numStr.indexOf('.'); //find deciaml point\n  if (dp < 0) { //no dp found\n    dp = numStr.length;\n  }\n\n  let insPos = dp - 3;\n  insCount = 0;\n  while (insPos > 0) {\n    insCount++;\n    numStr = numStr.slice(0, insPos) + ',' + numStr.slice(insPos);\n    insPos -= 3;\n  }\n\n\n  return (numStr);\n}\n\nfunction capF(inWord) { //Capitalise first letter of string\n  return (inWord.charAt(0).toUpperCase() + inWord.slice(1));\n}\n\nfunction getPastTense(action) {\n  let ret = '';\n  if (action === 'buy') {\n    ret = 'Bought'\n  } else if (action === 'sell') {\n    ret = 'Sold'\n  }\n  return ret;\n}\n\nPushbullet.prototype.mail = function(subject, content, done) {\n  var pusher = new pushbullet(pbConf.key);\n  pusher.note(pbConf.email, subject, content, function(error, response) {\n    if (error || !response) {\n      log.error('Pushbullet ERROR:', error)\n    } else if (response && response.active) {\n      log.info('Pushbullet Message Sent')\n    }\n  });\n};\n\nPushbullet.prototype.checkResults = function(err) {\n  if (err)\n    log.warn('error sending pushbullet message', err);\n  else\n    log.info('Send advice via pushbullet message.');\n};\n\nmodule.exports = Pushbullet;"
  },
  {
    "path": "plugins/pushover.js",
    "content": "var push = require( 'pushover-notifications' );\nvar _ = require('lodash');\nvar log = require('../core/log.js');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar pushoverConfig = config.pushover;\n\nvar Pushover = function() {\n  _.bindAll(this);\n\n  this.p;\n  this.price = 'N/A';\n\n  this.setup();\n}\n\nPushover.prototype.setup = function() {\n  var setupPushover = function() {\n    this.p = new push( {\n        user: pushoverConfig.user,\n        token: pushoverConfig.key,\n    });\n\n    if(pushoverConfig.sendPushoverOnStart) {\n      this.send(\n        \"Gekko has started\",\n        [\n          \"I've just started watching \",\n          config.watch.exchange,\n          ' ',\n          config.watch.currency,\n          '/',\n          config.watch.asset,\n          \". I'll let you know when I got some advice\"\n        ].join('')\n      );\n    } else\n    log.debug('Setup pushover adviser.');\n  }\n    setupPushover.call(this);\n}\n\nPushover.prototype.send = function(subject, content) {\n  var msg = {\n      // These values correspond to the parameters detailed on https://pushover.net/api\n      // 'message' is required. All other values are optional.\n      message: content,\n      title: pushoverConfig.tag + subject,\n      device: 'devicename',\n      priority: 1\n  };\n\n  this.p.send( msg, function( err, result ) {\n      if ( err ) {\n          throw err;\n      }\n\n      console.log( result );\n  });\n\n}\n\nPushover.prototype.processCandle = function(candle, callback) {\n  this.price = candle.close;\n  callback();\n}\n\nPushover.prototype.processAdvice = function(advice) {\n  if (advice.recommendation == 'soft' && pushoverConfig.muteSoft) return;\n  var text = [\n    advice.recommendation,\n    this.price\n  ].join(' ');\n  var subject = text;\n  this.send(subject, text);\n}\n\nPushover.prototype.checkResults = function(err) {\n  if(err)\n    log.warn('error sending pushover', err);\n  else\n    log.info('Send advice via pushover.');\n}\n\nmodule.exports = Pushover;\n"
  },
  {
    "path": "plugins/redisBeacon.js",
    "content": "var log = require('../core/log.js');\nvar util = require('../core/util');\nvar config = util.getConfig();\nvar redisBeacon = config.redisBeacon;\nvar watch = config.watch;\n\nvar subscriptions = require('../subscriptions');\nvar _ = require('lodash');\n\nvar redis = require(\"redis\");\n\nvar Actor = function(done) {\n  _.bindAll(this);\n\n  this.market = [\n    watch.exchange,\n    watch.currency,\n    watch.asset\n  ].join('-');\n\n  this.init(done);\n}\n\n// This actor is dynamically build based on\n// what the config specifies it should emit.\n// \n// This way we limit overhead because Gekko\n// only binds to events redis is going to\n// emit.\n\nvar proto = {};\n_.each(redisBeacon.broadcast, function(e) {\n  // grab the corresponding subscription \n  var subscription = _.find(subscriptions, function(s) { return s.event === e });\n\n  if(!subscription)\n    util.die('Gekko does not know this event:' + e);\n\n  var channel = redisBeacon.channelPrefix + subscription.event\n\n  proto[subscription.handler] = function(message, cb) {\n    if(!_.isFunction(cb))\n      cb = _.noop;\n\n    this.emit(channel, {\n      market: this.market,\n      data: message\n    }, cb);\n  };\n\n}, this)\n\nActor.prototype = proto;\n\nActor.prototype.init = function(done) {\n  this.client = redis.createClient(redisBeacon.port, redisBeacon.host);\n  this.client.on('ready', _.once(done));\n}\n\nActor.prototype.emit = function(channel, message) {\n  log.debug('Going to publish to redis channel:', channel);\n\n  var data = JSON.stringify(message);\n  this.client.publish(channel, data);\n}\n\nmodule.exports = Actor;"
  },
  {
    "path": "plugins/slack.js",
    "content": "const WebClient = require('@slack/client').WebClient;\nconst _ = require('lodash');\nconst log = require('../core/log.js');\nconst util = require('../core/util.js');\nconst config = util.getConfig();\nconst slackConfig = config.slack;\n\nconst Slack = function(done) {\n    _.bindAll(this);\n\n    this.slack;\n    this.price = 'N/A';\n\n    this.done = done;\n    this.setup();\n};\n\nSlack.prototype.setup = function(done) {\n    this.slack = new WebClient(slackConfig.token);\n\n    const setupSlack = function(error, result) {\n        if(slackConfig.sendMessageOnStart){\n          const body = this.createResponse(\"#439FE0\",\"Gekko started!\") ;\n          this.send(body);\n        }else{\n            log.debug('Skipping Send message on startup')\n        }\n    };\n    setupSlack.call(this)\n};\n\nSlack.prototype.processCandle = function(candle, done) {\n    this.price = candle.close;\n\n    done();\n};\n\nSlack.prototype.processAdvice = function(advice) {\n\tif (advice.recommendation == 'soft' && slackConfig.muteSoft) return;\n\n\tconst color = advice.recommendation === \"long\" ? \"good\" : (advice.recommendation === \"short\" ? \"danger\" : \"warning\");\n  const body = this.createResponse(color, \"There is a new trend! The advice is to go `\" + advice.recommendation + \"`! Current price is `\" + this.price + \"`\");\n\n  this.send(body);\n};\n\nSlack.prototype.processStratNotification = function({ content }) {\n  const body = this.createResponse('#909399', content);\n  this.send(body);\n}\n\nSlack.prototype.send = function(content, done) {\n    this.slack.chat.postMessage(slackConfig.channel, \"\", content, (error, response) => {\n      if (error || !response) {\n        log.error('Slack ERROR:', error);\n      } else {\n        log.info('Slack Message Sent');\n      }\n    });\n};\n\nSlack.prototype.checkResults = function(error) {\n    if (error) {\n        log.warn('error sending slack', error);\n    } else {\n        log.info('Send advice via slack.');\n    }\n};\n\nSlack.prototype.createResponse = function(color, message) {\n  const template = {\n    \"username\": this.createUserName(),\n    \"icon_url\": this.createIconUrl(),\n    \"attachments\": [\n      {\n        \"fallback\": \"\",\n        \"color\": color,\n        \"text\": message,\n        \"mrkdwn_in\": [\"text\"]\n      }\n    ]\n  };\n\n  return template;\n};\n\nSlack.prototype.createUserName = function() {\n  return config.watch.exchange[0].toUpperCase() + config.watch.exchange.slice(1) + \" - \" + config.watch.currency + \"/\" + config.watch.asset;\n};\n\nSlack.prototype.createIconUrl = function() {\n  const asset = config.watch.asset === \"XBT\" ? \"btc\" :config.watch.asset.toLowerCase();\n  return \"https://github.com/cjdowner/cryptocurrency-icons/raw/master/128/icon/\" + asset + \".png\";\n};\n\nmodule.exports = Slack;\n"
  },
  {
    "path": "plugins/sqlite/handle.js",
    "content": "var _ = require('lodash');\nvar fs = require('fs');\n\nvar util = require('../../core/util.js');\nvar config = util.getConfig();\nvar dirs = util.dirs();\n\nvar adapter = config.sqlite;\n\n// verify the correct dependencies are installed\nvar pluginHelper = require(dirs.core + 'pluginUtil');\nvar pluginMock = {\n  slug: 'sqlite adapter',\n  dependencies: adapter.dependencies,\n};\n\nvar cannotLoad = pluginHelper.cannotLoad(pluginMock);\nif (cannotLoad) util.die(cannotLoad);\n\n// should be good now\nif (config.debug) var sqlite3 = require('sqlite3').verbose();\nelse var sqlite3 = require('sqlite3');\n\nvar plugins = require(util.dirs().gekko + 'plugins');\n\nvar version = adapter.version;\n\nvar dbName = config.watch.exchange.toLowerCase() + '_' + version + '.db';\nvar dir = dirs.gekko + adapter.dataDirectory;\n\nvar fullPath = [dir, dbName].join('/');\n\nvar mode = util.gekkoMode();\nif (mode === 'realtime' || mode === 'importer') {\n  if (!fs.existsSync(dir)) fs.mkdirSync(dir);\n} else if (mode === 'backtest') {\n  if (!fs.existsSync(dir)) util.die('History directory does not exist.');\n\n  if (!fs.existsSync(fullPath))\n    util.die(\n      `History database does not exist for exchange ${\n        config.watch.exchange\n      } at version ${version}.`\n    );\n}\n\nmodule.exports = {\n  initDB: () => {\n    var journalMode = config.sqlite.journalMode || 'PERSIST';\n    var syncMode = journalMode === 'WAL' ? 'NORMAL' : 'FULL';\n  \n    var db = new sqlite3.Database(fullPath);\n    db.run('PRAGMA synchronous = ' + syncMode);\n    db.run('PRAGMA journal_mode = ' + journalMode);\n    db.configure('busyTimeout', 10000);\n    return db;\n  }\n};\n"
  },
  {
    "path": "plugins/sqlite/reader.js",
    "content": "var _ = require('lodash');\nvar util = require('../../core/util.js');\nvar config = util.getConfig();\nvar log = require(util.dirs().core + 'log');\n\nvar sqlite = require('./handle');\nvar sqliteUtil = require('./util');\n\nvar Reader = function() {\n  _.bindAll(this);\n  this.db = sqlite.initDB(true);\n}\n\n\n// returns the most recent window complete candle\n// windows within `from` and `to`\nReader.prototype.mostRecentWindow = function(from, to, next) {\n  to = to.unix();\n  from = from.unix();\n\n  var maxAmount = to - from + 1;\n\n  this.db.all(`\n    SELECT start from ${sqliteUtil.table('candles')}\n    WHERE start <= ${to} AND start >= ${from}\n    ORDER BY start DESC\n  `, function(err, rows) {\n    if(err) {\n\n      // bail out if the table does not exist\n      if(err.message.split(':')[1] === ' no such table')\n        return next(false);\n\n      log.error(err);\n      return util.die('DB error while reading mostRecentWindow');\n    }\n\n    // no candles are available\n    if(rows.length === 0) {\n      return next(false);\n    }\n\n    if(rows.length === maxAmount) {\n\n      // full history is available!\n\n      return next({\n        from: from,\n        to: to\n      });\n    }\n\n    // we have at least one gap, figure out where\n    var mostRecent = _.first(rows).start;\n\n    var gapIndex = _.findIndex(rows, function(r, i) {\n      return r.start !== mostRecent - i * 60;\n    });\n\n    // if there was no gap in the records, but\n    // there were not enough records.\n    if(gapIndex === -1) {\n      var leastRecent = _.last(rows).start;\n      return next({\n        from: leastRecent,\n        to: mostRecent\n      });\n    }\n\n    // else return mostRecent and the\n    // the minute before the gap\n    return next({\n      from: rows[ gapIndex - 1 ].start,\n      to: mostRecent\n    });\n\n  })\n}\n\nReader.prototype.tableExists = function(name, next) {\n\n  this.db.all(`\n    SELECT name FROM sqlite_master WHERE type='table' AND name='${sqliteUtil.table(name)}';\n  `, function(err, rows) {\n    if(err) {\n      console.error(err);\n      return util.die('DB error at `get`');\n    }\n\n    next(null, rows.length === 1);\n  });\n}\n\nReader.prototype.get = function(from, to, what, next) {\n  if(what === 'full')\n    what = '*';\n\n  this.db.all(`\n    SELECT ${what} from ${sqliteUtil.table('candles')}\n    WHERE start <= ${to} AND start >= ${from}\n    ORDER BY start ASC\n  `, function(err, rows) {\n    if(err) {\n      console.error(err);\n      return util.die('DB error at `get`');\n    }\n\n    next(null, rows);\n  });\n}\n\nReader.prototype.count = function(from, to, next) {\n  this.db.all(`\n    SELECT COUNT(*) as count from ${sqliteUtil.table('candles')}\n    WHERE start <= ${to} AND start >= ${from}\n  `, function(err, res) {\n    if(err) {\n      console.error(err);\n      return util.die('DB error at `get`');\n    }\n\n    next(null, _.first(res).count);\n  });\n}\n\nReader.prototype.countTotal = function(next) {\n  this.db.all(`\n    SELECT COUNT(*) as count from ${sqliteUtil.table('candles')}\n  `, function(err, res) {\n    if(err) {\n      console.error(err);\n      return util.die('DB error at `get`');\n    }\n\n    next(null, _.first(res).count);\n  });\n}\n\nReader.prototype.getBoundry = function(next) {\n\n  this.db.all(`\n    SELECT\n    (\n      SELECT start\n      FROM ${sqliteUtil.table('candles')}\n      ORDER BY start LIMIT 1\n    ) as 'first',\n    (\n      SELECT start\n      FROM ${sqliteUtil.table('candles')}\n      ORDER BY start DESC\n      LIMIT 1\n    ) as 'last'\n  `, function(err, rows) {\n    if(err) {\n      console.error(err);\n      return util.die('DB error at `get`');\n    }\n\n    next(null, _.first(rows));\n  });\n}\n\nReader.prototype.close = function() {\n  this.db.close();\n  this.db = null;\n}\n\nmodule.exports = Reader;"
  },
  {
    "path": "plugins/sqlite/scanner.js",
    "content": "const _ = require('lodash');\nconst async = require('async');\nconst fs = require('fs');\n\nconst util = require('../../core/util.js');\nconst config = util.getConfig();\nconst dirs = util.dirs();\n\nconst sqlite3 = require('sqlite3');\n\n// todo: rewrite with generators or async/await..\nmodule.exports = done => {\n  const dbDirectory = dirs.gekko + config.sqlite.dataDirectory\n\n  if(!fs.existsSync(dbDirectory))\n    return done(null, []);\n\n  const files = fs.readdirSync(dbDirectory);\n\n  const dbs = files\n    .filter(f => {\n      let parts = f.split('.');\n      if(_.last(parts) === 'db')\n        return true;\n    })\n\n  if(!_.size(dbs))\n    return done(null, []);\n\n  let markets = [];\n\n  async.each(dbs, (db, next) => {\n\n    const exchange = _.first(db.split('_'));\n    const handle = new sqlite3.Database(dbDirectory + '/' + db, sqlite3.OPEN_READONLY, err => {\n      if(err)\n        return next(err);\n\n      handle.all(`SELECT name FROM sqlite_master WHERE type='table'`, (err, tables) => {\n        if(err)\n          return next(err);\n        \n        _.each(tables, table => {\n          let parts = table.name.split('_');\n          let first = parts.shift();\n          if(first === 'candles') \n            markets.push({\n              exchange: exchange,\n              currency: _.first(parts),\n              asset: _.last(parts)\n            });\n        });\n\n        next();\n      });\n    });\n\n\n  },\n  // got all tables!\n  err => {\n    done(err, markets);\n  });\n}"
  },
  {
    "path": "plugins/sqlite/util.js",
    "content": "var config = require('../../core/util.js').getConfig();\n\nvar watch = config.watch;\nvar settings = {\n  exchange: watch.exchange,\n  pair: [watch.currency, watch.asset],\n  historyPath: config.sqlite.dataDirectory\n}\n\nmodule.exports = {\n  settings: settings,\n  table: function(name) {\n    return [name, settings.pair.join('_')].join('_');\n  }\n}"
  },
  {
    "path": "plugins/sqlite/writer.js",
    "content": "var _ = require('lodash');\nvar config = require('../../core/util.js').getConfig();\n\nvar sqlite = require('./handle');\nvar sqliteUtil = require('./util');\nvar util = require('../../core/util');\nvar log = require('../../core/log');\n\nvar Store = function(done, pluginMeta) {\n  _.bindAll(this);\n  this.done = done;\n\n  this.db = sqlite.initDB(false);\n  this.db.serialize(this.upsertTables);\n\n  this.cache = [];\n  this.buffered = util.gekkoMode() === \"importer\";\n}\n\nStore.prototype.upsertTables = function() {\n  var createQueries = [\n    `\n      CREATE TABLE IF NOT EXISTS\n      ${sqliteUtil.table('candles')} (\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        start INTEGER UNIQUE,\n        open REAL NOT NULL,\n        high REAL NOT NULL,\n        low REAL NOT NULL,\n        close REAL NOT NULL,\n        vwp REAL NOT NULL,\n        volume REAL NOT NULL,\n        trades INTEGER NOT NULL\n      );\n    `,\n\n    // TODO: create trades\n    // ``\n\n    // TODO: create advices\n    // ``\n  ];\n\n  var next = _.after(_.size(createQueries), this.done);\n\n  _.each(createQueries, function(q) {\n    this.db.run(q, next);\n  }, this);\n}\n\nStore.prototype.writeCandles = function() {\n  if(_.isEmpty(this.cache))\n    return;\n\n  const transaction = () => {\n    this.db.run(\"BEGIN TRANSACTION\");\n\n    var stmt = this.db.prepare(`\n      INSERT OR IGNORE INTO ${sqliteUtil.table('candles')}\n      VALUES (?,?,?,?,?,?,?,?,?)\n    `, function(err, rows) {\n        if(err) {\n          log.error(err);\n          return util.die('DB error at INSERT: '+ err);\n        }\n      });\n\n    _.each(this.cache, candle => {\n      stmt.run(\n        null,\n        candle.start.unix(),\n        candle.open,\n        candle.high,\n        candle.low,\n        candle.close,\n        candle.vwp,\n        candle.volume,\n        candle.trades\n      );\n    });\n\n    stmt.finalize();\n    this.db.run(\"COMMIT\");\n    // TEMP: should fix https://forum.gekko.wizb.it/thread-57279-post-59194.html#pid59194\n    this.db.run(\"pragma wal_checkpoint;\");\n    \n    this.cache = [];\n  }\n\n  this.db.serialize(transaction);\n}\n\nvar processCandle = function(candle, done) {\n  this.cache.push(candle);\n  if (!this.buffered || this.cache.length > 1000) \n    this.writeCandles();\n\n  done();\n};\n\nvar finalize = function(done) {\n  this.writeCandles();\n  this.db.close(() => { done(); });\n  this.db = null;\n}\n\nif(config.candleWriter.enabled) {\n  Store.prototype.processCandle = processCandle;\n  Store.prototype.finalize = finalize;\n}\n\n// TODO: add storing of trades / advice?\n\n// var processTrades = function(candles) {\n//   util.die('NOT IMPLEMENTED');\n// }\n\n// var processAdvice = function(candles) {\n//   util.die('NOT IMPLEMENTED');\n// }\n\n// if(config.tradeWriter.enabled)\n//  Store.prototype.processTrades = processTrades;\n\n// if(config.adviceWriter.enabled)\n//   Store.prototype.processAdvice = processAdvice;\n\nmodule.exports = Store;\n"
  },
  {
    "path": "plugins/telegrambot.js",
    "content": "const log = require('../core/log');\nconst moment = require('moment');\nconst _ = require('lodash');\nconst config = require('../core/util').getConfig();\nconst telegrambot = config.telegrambot;\nconst emitTrades = telegrambot.emitTrades;\nconst utc = moment.utc;\nconst telegram = require(\"node-telegram-bot-api\");\n\nconst Actor = function() {\n  _.bindAll(this);\n\n  this.advice = null;\n  this.adviceTime = utc();\n\n  this.price = 'Dont know yet :(';\n  this.priceTime = utc();\n\n  this.commands = {\n    '/start': 'emitStart',\n    '/advice': 'emitAdvice',\n    '/subscribe': 'emitSubscribe',\n    '/unsubscribe': 'emitUnSubscribe',\n    '/price': 'emitPrice',\n    '/help': 'emitHelp'\n  };\n  if (telegrambot.donate) {\n    this.commands['/donate'] = 'emitDonate';\n  }\n  this.rawCommands = _.keys(this.commands);\n  this.chatId = null;\n  this.subscribers = [];\n  this.bot = new telegram(telegrambot.token, { polling: true });\n  this.bot.onText(/(.+)/, this.verifyQuestion);\n};\n\nActor.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n  this.priceTime = candle.start;\n\n  done();\n};\n\nActor.prototype.processAdvice = function(advice) {\n  if (advice.recommendation === 'soft') return;\n  this.advice = advice.recommendation;\n  this.adviceTime = utc();\n  this.advicePrice = this.price;\n  this.subscribers.forEach(this.emitAdvice, this);\n};\n\nif(emitTrades) {\n  Actor.prototype.processTradeInitiated = function (tradeInitiated) {\n    var message = 'Trade initiated. ID: ' + tradeInitiated.id +\n    '\\nAction: ' + tradeInitiated.action + '\\nPortfolio: ' +\n    tradeInitiated.portfolio + '\\nBalance: ' + tradeInitiated.balance;\n    this.bot.sendMessage(this.chatId, message);\n  }\n  \n  Actor.prototype.processTradeCancelled = function (tradeCancelled) {\n    var message = 'Trade cancelled. ID: ' + tradeCancelled.id;\n    this.bot.sendMessage(this.chatId, message);\n  }\n  \n  Actor.prototype.processTradeAborted = function (tradeAborted) {\n    var message = 'Trade aborted. ID: ' + tradeAborted.id +\n    '\\nNot creating order! Reason: ' + tradeAborted.reason;\n    this.bot.sendMessage(this.chatId, message);\n  }\n  \n  Actor.prototype.processTradeErrored = function (tradeErrored) {\n    var message = 'Trade errored. ID: ' + tradeErrored.id +\n    '\\nReason: ' + tradeErrored.reason;\n    this.bot.sendMessage(this.chatId, message);\n  }\n  \n  Actor.prototype.processTradeCompleted = function (tradeCompleted) {\n    var message = 'Trade completed. ID: ' + tradeCompleted.id + \n    '\\nAction: ' + tradeCompleted.action +\n    '\\nPrice: ' + tradeCompleted.price +\n    '\\nAmount: ' + tradeCompleted.amount +\n    '\\nCost: ' + tradeCompleted.cost +\n    '\\nPortfolio: ' + tradeCompleted.portfolio +\n    '\\nBalance: ' + tradeCompleted.balance +\n    '\\nFee percent: ' + tradeCompleted.feePercent +\n    '\\nEffective price: ' + tradeCompleted.effectivePrice;\n    this.bot.sendMessage(this.chatId, message); \n  }\n}\n\nActor.prototype.verifyQuestion = function(msg, text) {\n  this.chatId = msg.chat.id;\n  if (text[1].toLowerCase() in this.commands) {\n    this[this.commands[text[1].toLowerCase()]]();\n  } else {\n    this.emitHelp();\n  }\n};\n\nActor.prototype.emitStart = function() {\n  this.bot.sendMessage(this.chatId, 'Hello! How can I help you?');\n};\n\nActor.prototype.emitSubscribe = function() {\n  if (this.subscribers.indexOf(this.chatId) === -1) {\n    this.subscribers.push(this.chatId);\n    this.bot.sendMessage(this.chatId, `Success! Got ${this.subscribers.length} subscribers.`);\n  } else {\n    this.bot.sendMessage(this.chatId, \"You are already subscribed.\");\n  }\n};\n\nActor.prototype.emitUnSubscribe = function() {\n  if (this.subscribers.indexOf(this.chatId) > -1) {\n    this.subscribers.splice(this.subscribers.indexOf(this.chatId), 1);\n    this.bot.sendMessage(this.chatId, \"Success!\");\n  } else {\n    this.bot.sendMessage(this.chatId, \"You are not subscribed.\");\n  }\n};\n\nActor.prototype.emitAdvice = function(chatId) {\n  let message = [\n    'Advice for ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' using ',\n    config.tradingAdvisor.method,\n    ' at ',\n    config.tradingAdvisor.candleSize,\n    ' minute candles, is:\\n',\n  ].join('');\n  if (this.advice) {\n    message += this.advice +\n      ' ' +\n      config.watch.asset +\n      ' ' +\n      this.advicePrice +\n      ' (' +\n      this.adviceTime.fromNow() +\n      ')';\n  } else {\n    message += 'None'\n  }\n\n  if (chatId) {\n    this.bot.sendMessage(chatId, message);\n  } else {\n    this.bot.sendMessage(this.chatId, message);\n  }\n};\n\n// sent price over to the last chat\nActor.prototype.emitPrice = function() {\n  const message = [\n    'Current price at ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' is ',\n    this.price,\n    ' ',\n    config.watch.currency,\n    ' (from ',\n    this.priceTime.fromNow(),\n    ')'\n  ].join('');\n\n  this.bot.sendMessage(this.chatId, message);\n};\n\nActor.prototype.emitDonate = function() {\n  this.bot.sendMessage(this.chatId, telegrambot.donate);\n};\n\nActor.prototype.emitHelp = function() {\n  let message = _.reduce(\n    this.rawCommands,\n    function(message, command) {\n      return message + ' ' + command + ',';\n    },\n    'Possible commands are:'\n  );\n  message = message.substr(0, _.size(message) - 1) + '.';\n  this.bot.sendMessage(this.chatId, message);\n};\n\nActor.prototype.logError = function(message) {\n  log.error('Telegram ERROR:', message);\n};\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins/trader/trader.js",
    "content": "const _ = require('lodash');\nconst util = require('../../core/util.js');\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst moment = require('moment');\n\nconst log = require(dirs.core + 'log');\nconst Broker = require(dirs.broker + '/gekkoBroker');\n\nrequire(dirs.gekko + '/exchange/dependencyCheck');\n\nconst Trader = function(next) {\n\n  _.bindAll(this);\n\n  this.brokerConfig = {\n    ...config.trader,\n    ...config.watch,\n    private: true\n  }\n\n  this.propogatedTrades = 0;\n  this.propogatedTriggers = 0;\n\n  try {\n    this.broker = new Broker(this.brokerConfig);\n  } catch(e) {\n    util.die(e.message);\n  }\n\n  if(!this.broker.capabilities.gekkoBroker) {\n    util.die('This exchange is not yet supported');\n  }\n\n  this.sync(() => {\n    log.info('\\t', 'Portfolio:');\n    log.info('\\t\\t', this.portfolio.currency, this.brokerConfig.currency);\n    log.info('\\t\\t', this.portfolio.asset, this.brokerConfig.asset);\n    log.info('\\t', 'Balance:');\n    log.info('\\t\\t', this.balance, this.brokerConfig.currency);\n    log.info('\\t', 'Exposed:');\n    log.info('\\t\\t',\n      this.exposed ? 'yes' : 'no',\n      `(${(this.exposure * 100).toFixed(2)}%)`\n    );\n    next();\n  });\n\n  this.cancellingOrder = false;\n  this.sendInitialPortfolio = false;\n\n  setInterval(this.sync, 1000 * 60 * 10);\n}\n\n// teach our trader events\nutil.makeEventEmitter(Trader);\n\nTrader.prototype.sync = function(next) {\n  log.debug('syncing private data');\n  this.broker.syncPrivateData(() => {\n    if(!this.price) {\n      this.price = this.broker.ticker.bid;\n    }\n\n    const oldPortfolio = this.portfolio;\n\n    this.setPortfolio();\n    this.setBalance();\n\n    if(this.sendInitialPortfolio && !_.isEqual(oldPortfolio, this.portfolio)) {\n      this.relayPortfolioChange();\n    }\n\n    // balance is relayed every minute\n    // no need to do it here.\n\n    if(next) {\n      next();\n    }\n  });\n}\n\nTrader.prototype.relayPortfolioChange = function() {\n  this.deferredEmit('portfolioChange', {\n    asset: this.portfolio.asset,\n    currency: this.portfolio.currency\n  });\n}\n\nTrader.prototype.relayPortfolioValueChange = function() {\n  this.deferredEmit('portfolioValueChange', {\n    balance: this.balance\n  });\n}\n\nTrader.prototype.setPortfolio = function() {\n  this.portfolio = {\n    currency: _.find(\n      this.broker.portfolio.balances,\n      b => b.name === this.brokerConfig.currency\n    ).amount,\n    asset: _.find(\n      this.broker.portfolio.balances,\n      b => b.name === this.brokerConfig.asset\n    ).amount\n  }\n}\n\nTrader.prototype.setBalance = function() {\n  this.balance = this.portfolio.currency + this.portfolio.asset * this.price;\n  this.exposure = (this.portfolio.asset * this.price) / this.balance;\n  // if more than 10% of balance is in asset we are exposed\n  this.exposed = this.exposure > 0.1;\n}\n\nTrader.prototype.processCandle = function(candle, done) {\n  this.price = candle.close;\n  const previousBalance = this.balance;\n  this.setPortfolio();\n  this.setBalance();\n\n  if(!this.sendInitialPortfolio) {\n    this.sendInitialPortfolio = true;\n    this.deferredEmit('portfolioChange', {\n      asset: this.portfolio.asset,\n      currency: this.portfolio.currency\n    });\n  }\n\n  if(this.balance !== previousBalance) {\n    // this can happen because:\n    // A) the price moved and we have > 0 asset\n    // B) portfolio got changed\n    this.relayPortfolioValueChange();\n  }\n\n  done();\n}\n\nTrader.prototype.processAdvice = function(advice) {\n  let direction;\n\n  if(advice.recommendation === 'long') {\n    direction = 'buy';\n  } else if(advice.recommendation === 'short') {\n    direction = 'sell';\n  } else {\n    log.error('ignoring advice in unknown direction');\n    return;\n  }\n\n  const id = 'trade-' + (++this.propogatedTrades);\n\n  if(this.order) {\n    if(this.order.side === direction) {\n      return log.info('ignoring advice: already in the process to', direction);\n    }\n\n    if(this.cancellingOrder) {\n      return log.info('ignoring advice: already cancelling previous', this.order.side, 'order');\n    }\n\n    log.info('Received advice to', direction, 'however Gekko is already in the process to', this.order.side);\n    log.info('Canceling', this.order.side, 'order first');\n    return this.cancelOrder(id, advice, () => this.processAdvice(advice));\n  }\n\n  let amount;\n\n  if(direction === 'buy') {\n\n    if(this.exposed) {\n      log.info('NOT buying, already exposed');\n      return this.deferredEmit('tradeAborted', {\n        id,\n        adviceId: advice.id,\n        action: direction,\n        portfolio: this.portfolio,\n        balance: this.balance,\n        reason: \"Portfolio already in position.\"\n      });\n    }\n\n    amount = this.portfolio.currency / this.price * 0.95;\n\n    log.info(\n      'Trader',\n      'Received advice to go long.',\n      'Buying ', this.brokerConfig.asset\n    );\n\n  } else if(direction === 'sell') {\n\n    if(!this.exposed) {\n      log.info('NOT selling, already no exposure');\n      return this.deferredEmit('tradeAborted', {\n        id,\n        adviceId: advice.id,\n        action: direction,\n        portfolio: this.portfolio,\n        balance: this.balance,\n        reason: \"Portfolio already in position.\"\n      });\n    }\n\n    // clean up potential old stop trigger\n    if(this.activeStopTrigger) {\n      this.deferredEmit('triggerAborted', {\n        id: this.activeStopTrigger.id,\n        date: advice.date\n      });\n\n      this.activeStopTrigger.instance.cancel();\n\n      delete this.activeStopTrigger;\n    }\n\n    amount = this.portfolio.asset;\n\n    log.info(\n      'Trader',\n      'Received advice to go short.',\n      'Selling ', this.brokerConfig.asset\n    );\n  }\n\n  this.createOrder(direction, amount, advice, id);\n}\n\nTrader.prototype.createOrder = function(side, amount, advice, id) {\n  const type = 'sticky';\n\n  // NOTE: this is the best check we can do at this point\n  // with the best price we have. The order won't be actually\n  // created with this.price, but it should be close enough to\n  // catch non standard errors (lot size, price filter) on\n  // exchanges that have them.\n  const check = this.broker.isValidOrder(amount, this.price);\n\n  if(!check.valid) {\n    log.warn('NOT creating order! Reason:', check.reason);\n    return this.deferredEmit('tradeAborted', {\n      id,\n      adviceId: advice.id,\n      action: side,\n      portfolio: this.portfolio,\n      balance: this.balance,\n      reason: check.reason\n    });\n  }\n\n  log.debug('Creating order to', side, amount, this.brokerConfig.asset);\n\n  this.deferredEmit('tradeInitiated', {\n    id,\n    adviceId: advice.id,\n    action: side,\n    portfolio: this.portfolio,\n    balance: this.balance\n  });\n\n  this.order = this.broker.createOrder(type, side, amount);\n\n  this.order.on('fill', f => log.info('[ORDER] partial', side, 'fill, total filled:', f));\n  this.order.on('statusChange', s => log.debug('[ORDER] statusChange:', s));\n\n  this.order.on('error', e => {\n    log.error('[ORDER] Gekko received error from GB:', e.message);\n    log.debug(e);\n    this.order = null;\n    this.cancellingOrder = false;\n\n    this.deferredEmit('tradeErrored', {\n      id,\n      adviceId: advice.id,\n      date: moment(),\n      reason: e.message\n    });\n\n  });\n  this.order.on('completed', () => {\n    this.order.createSummary((err, summary) => {\n      if(!err && !summary) {\n        err = new Error('GB returned an empty summary.')\n      }\n\n      if(err) {\n        log.error('Error while creating summary:', err);\n        return this.deferredEmit('tradeErrored', {\n          id,\n          adviceId: advice.id,\n          date: moment(),\n          reason: err.message\n        });\n      }\n\n      log.info('[ORDER] summary:', summary);\n      this.order = null;\n      this.sync(() => {\n\n        let cost;\n        if(_.isNumber(summary.feePercent)) {\n          cost = summary.feePercent / 100 * summary.amount * summary.price;\n        }\n\n        let effectivePrice;\n        if(_.isNumber(summary.feePercent)) {\n          if(side === 'buy') {\n            effectivePrice = summary.price * (1 + summary.feePercent / 100);\n          } else {\n            effectivePrice = summary.price * (1 - summary.feePercent / 100);\n          }\n        } else {\n          log.warn('WARNING: exchange did not provide fee information, assuming no fees..');\n          effectivePrice = summary.price;\n        }\n\n        this.deferredEmit('tradeCompleted', {\n          id,\n          adviceId: advice.id,\n          action: summary.side,\n          cost,\n          amount: summary.amount,\n          price: summary.price,\n          portfolio: this.portfolio,\n          balance: this.balance,\n          date: summary.date,\n          feePercent: summary.feePercent,\n          effectivePrice\n        });\n\n        if(\n          side === 'buy' &&\n          advice.trigger &&\n          advice.trigger.type === 'trailingStop'\n        ) {\n          const trigger = advice.trigger;\n          const triggerId = 'trigger-' + (++this.propogatedTriggers);\n\n          this.deferredEmit('triggerCreated', {\n            id: triggerId,\n            at: advice.date,\n            type: 'trailingStop',\n            properties: {\n              trail: trigger.trailValue,\n              initialPrice: summary.price,\n            }\n          });\n\n          log.info(`Creating trailingStop trigger \"${triggerId}\"! Properties:`);\n          log.info(`\\tInitial price: ${summary.price}`);\n          log.info(`\\tTrail of: ${trigger.trailValue}`);\n\n          this.activeStopTrigger = {\n            id: triggerId,\n            adviceId: advice.id,\n            instance: this.broker.createTrigger({\n              type: 'trailingStop',\n              onTrigger: this.onStopTrigger,\n              props: {\n                trail: trigger.trailValue,\n                initialPrice: summary.price,\n              }\n            })\n          }\n        }\n      });\n    })\n  });\n}\n\nTrader.prototype.onStopTrigger = function(price) {\n  log.info(`TrailingStop trigger \"${this.activeStopTrigger.id}\" fired! Observed price was ${price}`);\n\n  this.deferredEmit('triggerFired', {\n    id: this.activeStopTrigger.id,\n    date: moment()\n  });\n\n  const adviceMock = {\n    recommendation: 'short',\n    id: this.activeStopTrigger.adviceId\n  }\n\n  delete this.activeStopTrigger;\n\n  this.processAdvice(adviceMock);\n}\n\nTrader.prototype.cancelOrder = function(id, advice, next) {\n\n  if(!this.order) {\n    return next();\n  }\n\n  this.cancellingOrder = true;\n\n  this.order.removeAllListeners();\n  this.order.cancel();\n  this.order.once('completed', () => {\n    this.order = null;\n    this.cancellingOrder = false;\n    this.deferredEmit('tradeCancelled', {\n      id,\n      adviceId: advice.id,\n      date: moment()\n    });\n    this.sync(next);\n  });\n}\n\nmodule.exports = Trader;\n"
  },
  {
    "path": "plugins/tradingAdvisor/asyncIndicatorRunner.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst util = require('../../core/util');\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst log = require(dirs.core + 'log');\n\nconst talib = require(dirs.core + 'talib');\nconst tulind = require(dirs.core + 'tulind');\n\nconst allowedTalibIndicators = _.keys(talib);\nconst allowedTulipIndicators = _.keys(tulind);\n\nconst AsyncIndicatorRunner = function() {\n  this.talibIndicators = {};\n  this.tulipIndicators = {};\n\n  this.candleProps = {\n    open: [],\n    high: [],\n    low: [],\n    close: [],\n    volume: []\n  };\n\n  this.candlePropsCacheSize = 1000;\n\n  this.inflight = false;\n  this.backlog = [];\n  this.age = 0;\n}\n\nAsyncIndicatorRunner.prototype.processCandle = function(candle, next) {\n  if(this.inflight) {\n    return this.backlog.push({candle, next});\n  }\n\n  this.age++;\n  this.inflight = true;  \n\n  this.candleProps.open.push(candle.open);\n  this.candleProps.high.push(candle.high);\n  this.candleProps.low.push(candle.low);\n  this.candleProps.close.push(candle.close);\n  this.candleProps.volume.push(candle.volume);\n\n  if(this.age > this.candlePropsCacheSize) {\n    this.candleProps.open.shift();\n    this.candleProps.high.shift();\n    this.candleProps.low.shift();\n    this.candleProps.close.shift();\n    this.candleProps.volume.shift();\n  }\n\n  this.calculateIndicators(next);\n}\n\nAsyncIndicatorRunner.prototype.calculateIndicators = function(next) {\n  const done = _.after(\n    _.size(this.talibIndicators) + _.size(this.tulipIndicators),\n    this.handlePostFlight(next)\n  );\n\n  // handle result from talib\n  const talibResultHander = name => (err, result) => {\n    if(err)\n      util.die('TALIB ERROR:', err);\n\n    this.talibIndicators[name].result = _.mapValues(result, v => _.last(v));\n    done();\n  }\n\n  // handle result from talib\n  _.each(\n    this.talibIndicators,\n    (indicator, name) => indicator.run(\n      this.candleProps,\n      talibResultHander(name)\n    )\n  );\n\n  // handle result from tulip\n  var tulindResultHander = name => (err, result) => {\n    if(err)\n      util.die('TULIP ERROR:', err);\n\n    this.tulipIndicators[name].result = _.mapValues(result, v => _.last(v));\n    done();\n  }\n\n  // handle result from tulip indicators\n  _.each(\n    this.tulipIndicators,\n    (indicator, name) => indicator.run(\n      this.candleProps,\n      tulindResultHander(name)\n    )\n  );\n}\n\nAsyncIndicatorRunner.prototype.handlePostFlight = function(next) {\n  return () => {\n    next();\n    this.inflight = false;\n\n    if(this.backlog.length) {\n      const { candle, next } = this.backlog.shift();\n      this.processCandle(candle, next);\n    }\n  }\n}\n\nAsyncIndicatorRunner.prototype.addTalibIndicator = function(name, type, parameters) {\n  if(!talib)\n    util.die('Talib is not enabled');\n\n  if(!_.contains(allowedTalibIndicators, type))\n    util.die('I do not know the talib indicator ' + type);\n\n  if(this.setup)\n    util.die('Can only add talib indicators in the init method!');\n\n  var basectx = this;\n\n  this.talibIndicators[name] = {\n    run: talib[type].create(parameters),\n    result: NaN\n  }\n}\n\nAsyncIndicatorRunner.prototype.addTulipIndicator = function(name, type, parameters) {\n  if(!tulind) {\n    util.die('Tulip indicators is not enabled');\n  }\n\n  if(!_.contains(allowedTulipIndicators, type))\n    util.die('I do not know the tulip indicator ' + type);\n\n  if(this.setup)\n    util.die('Can only add tulip indicators in the init method!');\n\n  var basectx = this;\n\n  this.tulipIndicators[name] = {\n    run: tulind[type].create(parameters),\n    result: NaN\n  }\n}\n\nmodule.exports = AsyncIndicatorRunner;"
  },
  {
    "path": "plugins/tradingAdvisor/baseTradingMethod.js",
    "content": "const _ = require('lodash');\nconst fs = require('fs');\nconst util = require('../../core/util');\nconst config = util.getConfig();\nconst dirs = util.dirs();\nconst log = require(dirs.core + 'log');\n\nconst ENV = util.gekkoEnv();\nconst mode = util.gekkoMode();\nconst startTime = util.getStartTime();\n\nconst indicatorsPath = dirs.methods + 'indicators/';\nconst indicatorFiles = fs.readdirSync(indicatorsPath);\nconst Indicators = {};\n\nconst AsyncIndicatorRunner = require('./asyncIndicatorRunner');\n\n_.each(indicatorFiles, function(indicator) {\n  const indicatorName = indicator.split(\".\")[0];\n  if (indicatorName[0] != \"_\")\n    try {\n      Indicators[indicatorName] = require(indicatorsPath + indicator);\n    } catch (e) {\n      log.error(\"Failed to load indicator\", indicatorName);\n    }\n});\n\nconst allowedIndicators = _.keys(Indicators);\n\nvar Base = function(settings) {\n  _.bindAll(this);\n\n  // properties\n  this.age = 0;\n  this.processedTicks = 0;\n  this.setup = false;\n  this.settings = settings;\n  this.tradingAdvisor = config.tradingAdvisor;\n  // defaults\n  this.priceValue = 'close';\n  this.indicators = {};\n  this.asyncTick = false;\n  this.deferredTicks = [];\n\n  this.propogatedAdvices = 0;\n\n  this.completedWarmup = false;\n\n  this.asyncIndicatorRunner = new AsyncIndicatorRunner();\n\n  this._currentDirection;\n\n  // make sure we have all methods\n  _.each(['init', 'check'], function(fn) {\n    if(!this[fn])\n      util.die('No ' + fn + ' function in this strategy found.')\n  }, this);\n\n  if(!this.update)\n    this.update = function() {};\n\n  if(!this.end)\n    this.end = function() {};\n\n  if(!this.onTrade)\n    this.onTrade = function() {};\n\n  // let's run the implemented starting point\n  this.init();\n\n  if(_.isNumber(this.requiredHistory)) {\n    log.debug('Ignoring strategy\\'s required history, using the \"config.tradingAdvisor.historySize\" instead.');\n  }\n  this.requiredHistory = config.tradingAdvisor.historySize;\n\n  if(!config.debug || !this.log)\n    this.log = function() {};\n\n  this.setup = true;\n\n  if(_.size(this.asyncIndicatorRunner.talibIndicators) || _.size(this.asyncIndicatorRunner.tulipIndicators))\n    this.asyncTick = true;\n  else\n    delete this.asyncIndicatorRunner;\n}\n\n// teach our base trading method events\nutil.makeEventEmitter(Base);\n\nBase.prototype.tick = function(candle, done) {\n  this.age++;\n\n  const afterAsync = () => {\n    this.calculateSyncIndicators(candle, done);\n  }\n\n  if(this.asyncTick) {\n    this.asyncIndicatorRunner.processCandle(candle, () => {\n\n      if(!this.talibIndicators) {\n        this.talibIndicators = this.asyncIndicatorRunner.talibIndicators;\n        this.tulipIndicators = this.asyncIndicatorRunner.tulipIndicators;\n      }\n\n      afterAsync();\n    });\n  } else {\n    afterAsync();\n  }\n}\n\nBase.prototype.isBusy = function() {\n  if(!this.asyncTick)\n    return false;\n\n  return this.asyncIndicatorRunner.inflight;\n}\n\nBase.prototype.calculateSyncIndicators = function(candle, done) {\n  // update all indicators\n  var price = candle[this.priceValue];\n  _.each(this.indicators, function(i) {\n    if(i.input === 'price')\n      i.update(price);\n    if(i.input === 'candle')\n      i.update(candle);\n  },this);\n\n  this.propogateTick(candle);\n\n  return done();\n}\n\nBase.prototype.propogateTick = function(candle) {\n  this.candle = candle;\n  this.update(candle);\n\n  this.processedTicks++;\n  var isAllowedToCheck = this.requiredHistory <= this.age;\n\n  if(!this.completedWarmup) {\n\n    // in live mode we might receive more candles\n    // than minimally needed. In that case check\n    // whether candle start time is > startTime\n    var isPremature = false;\n\n    if(mode === 'realtime') {\n      const startTimeMinusCandleSize = startTime\n        .clone()\n        .subtract(this.tradingAdvisor.candleSize, \"minutes\");\n\n      isPremature = candle.start < startTimeMinusCandleSize;\n    }\n\n    if(isAllowedToCheck && !isPremature) {\n      this.completedWarmup = true;\n      this.emit(\n        'stratWarmupCompleted',\n        {start: candle.start.clone()}\n      );\n    }\n  }\n\n  if(this.completedWarmup) {\n    this.log(candle);\n    this.check(candle);\n\n    if(\n      this.asyncTick &&\n      this.hasSyncIndicators &&\n      this.deferredTicks.length\n    ) {\n      return this.tick(this.deferredTicks.shift())\n    }\n  }\n\n  const indicators = {};\n  _.each(this.indicators, (indicator, name) => {\n    indicators[name] = indicator.result;\n  });\n  \n  _.each(this.tulipIndicators, (indicator, name) => {\n    indicators[name] = indicator.result.result\n      ? indicator.result.result\n      : indicator.result;\n  });\n\n  _.each(this.talibIndicators, (indicator, name) => {\n    indicators[name] = indicator.result.outReal\n      ? indicator.result.outReal\n      : indicator.result;\n  });\n\n  this.emit('stratUpdate', {\n    date: candle.start.clone(),\n    indicators\n  });\n\n  // are we totally finished?\n  const completed = this.age === this.processedTicks;\n  if(completed && this.finishCb)\n    this.finishCb();\n}\n\nBase.prototype.processTrade = function(trade) {\n  if(\n    this._pendingTriggerAdvice &&\n    trade.action === 'sell' &&\n    this._pendingTriggerAdvice === trade.adviceId\n  ) {\n    // This trade came from a trigger of the previous advice,\n    // update stored direction\n    this._currentDirection = 'short';\n    this._pendingTriggerAdvice = null;\n  }\n\n  this.onTrade(trade);\n}\n\nBase.prototype.addTalibIndicator = function(name, type, parameters) {\n  this.asyncIndicatorRunner.addTalibIndicator(name, type, parameters);\n}\n\nBase.prototype.addTulipIndicator = function(name, type, parameters) {\n  this.asyncIndicatorRunner.addTulipIndicator(name, type, parameters);\n}\n\nBase.prototype.addIndicator = function(name, type, parameters) {\n  if(!_.contains(allowedIndicators, type))\n    util.die('I do not know the indicator ' + type);\n\n  if(this.setup)\n    util.die('Can only add indicators in the init method!');\n\n  return this.indicators[name] = new Indicators[type](parameters);\n\n  // some indicators need a price stream, others need full candles\n}\n\nBase.prototype.advice = function(newDirection) {\n  // ignore legacy soft advice\n  if(!newDirection) {\n    return;\n  }\n\n  let trigger;\n  if(_.isObject(newDirection)) {\n    if(!_.isString(newDirection.direction)) {\n      log.error('Strategy emitted unparsable advice:', newDirection);\n      return;\n    }\n\n    if(newDirection.direction === this._currentDirection) {\n      return;\n    }\n\n    if(_.isObject(newDirection.trigger)) {\n      if(newDirection.direction !== 'long') {\n        log.warn(\n          'Strategy adviced a stop on not long, this is not supported.',\n          'As such the stop is ignored'\n        );\n      } else {\n\n        // the trigger is implemented in a trader\n        trigger = newDirection.trigger;\n\n        if(trigger.trailPercentage && !trigger.trailValue) {\n          trigger.trailValue = trigger.trailPercentage / 100 * this.candle.close;\n          log.info('[StratRunner] Trailing stop trail value specified as percentage, setting to:', trigger.trailValue);\n        }\n      }\n    }\n\n    newDirection = newDirection.direction;\n  }\n\n  if(newDirection === this._currentDirection) {\n    return;\n  }\n\n  if(newDirection === 'short' && this._pendingTriggerAdvice) {\n    this._pendingTriggerAdvice = null;\n  }\n\n  this._currentDirection = newDirection;\n\n  this.propogatedAdvices++;\n\n  const advice = {\n    id: 'advice-' + this.propogatedAdvices,\n    recommendation: newDirection\n  };\n\n  if(trigger) {\n    advice.trigger = trigger;\n    this._pendingTriggerAdvice = 'advice-' + this.propogatedAdvices;\n  } else {\n    this._pendingTriggerAdvice = null;\n  }\n\n  this.emit('advice', advice);\n\n  return this.propogatedAdvices;\n}\n\nBase.prototype.notify = function(content) {\n  this.emit('stratNotification', {\n    content,\n    date: new Date(),\n  })\n}\n\nBase.prototype.finish = function(done) {\n  // Because the strategy might be async we need\n  // to be sure we only stop after all candles are\n  // processed.\n  if(!this.asyncTick) {\n    this.end();\n    return done();\n  }\n\n  if(this.age === this.processedTicks) {\n    this.end();\n    return done();\n  }\n\n  // we are not done, register cb\n  // and call after we are..\n  this.finishCb = done;\n}\n\nmodule.exports = Base;\n"
  },
  {
    "path": "plugins/tradingAdvisor/tradingAdvisor.js",
    "content": "var util = require('../../core/util');\nvar _ = require('lodash');\nvar fs = require('fs');\nvar toml = require('toml');\n\nvar config = util.getConfig();\nvar dirs = util.dirs();\nvar log = require(dirs.core + 'log');\nvar CandleBatcher = require(dirs.core + 'candleBatcher');\n\nvar moment = require('moment');\nvar isLeecher = config.market && config.market.type === 'leech';\n\nvar Actor = function(done) {\n  _.bindAll(this);\n\n  this.done = done;\n\n  this.batcher = new CandleBatcher(config.tradingAdvisor.candleSize);\n\n  this.strategyName = config.tradingAdvisor.method;\n\n  this.setupStrategy();\n\n  var mode = util.gekkoMode();\n\n  // the stitcher will try to pump in historical data\n  // so that the strat can use this data as a \"warmup period\"\n  //\n  // the realtime \"leech\" market won't use the stitcher\n  if(mode === 'realtime' && !isLeecher) {\n    var Stitcher = require(dirs.tools + 'dataStitcher');\n    var stitcher = new Stitcher(this.batcher);\n    stitcher.prepareHistoricalData(done);\n  } else\n    done();\n}\n\nActor.prototype.setupStrategy = function() {\n\n  if(!fs.existsSync(dirs.methods + this.strategyName + '.js'))\n    util.die('Gekko can\\'t find the strategy \"' + this.strategyName + '\"');\n\n  log.info('\\t', 'Using the strategy: ' + this.strategyName);\n\n  const strategy = require(dirs.methods + this.strategyName);\n\n  // bind all trading strategy specific functions\n  // to the WrappedStrategy.\n  const WrappedStrategy = require('./baseTradingMethod');\n\n  _.each(strategy, function(fn, name) {\n    WrappedStrategy.prototype[name] = fn;\n  });\n\n  let stratSettings;\n  if(config[this.strategyName]) {\n    stratSettings = config[this.strategyName];\n  }\n\n  this.strategy = new WrappedStrategy(stratSettings);\n  this.strategy\n    .on(\n      'stratWarmupCompleted',\n      e => this.deferredEmit('stratWarmupCompleted', e)\n    )\n    .on('advice', this.relayAdvice)\n    .on(\n      'stratUpdate',\n      e => this.deferredEmit('stratUpdate', e)\n    ).on('stratNotification',\n      e => this.deferredEmit('stratNotification', e)\n    )\n\n  this.strategy\n    .on('tradeCompleted', this.processTradeCompleted);\n\n  this.batcher\n    .on('candle', _candle => {\n      const { id, ...candle } = _candle;\n      this.deferredEmit('stratCandle', candle);\n      this.emitStratCandle(candle);\n    });\n}\n\n// HANDLERS\n// process the 1m candles\nActor.prototype.processCandle = function(candle, done) {\n  this.candle = candle;\n  const completedBatch = this.batcher.write([candle]);\n  if(completedBatch) {\n    this.next = done;\n  } else {\n    done();\n    this.next = false;\n  }\n  this.batcher.flush();\n}\n\n// propogate a custom sized candle to the trading strategy\nActor.prototype.emitStratCandle = function(candle) {\n  const next = this.next || _.noop;\n  this.strategy.tick(candle, next);\n}\n\nActor.prototype.processTradeCompleted = function(trade) {\n  this.strategy.processTrade(trade);\n}\n\n// pass through shutdown handler\nActor.prototype.finish = function(done) {\n  this.strategy.finish(done);\n}\n\n// EMITTERS\nActor.prototype.relayAdvice = function(advice) {\n  advice.date = this.candle.start.clone().add(1, 'minute');\n  this.deferredEmit('advice', advice);\n}\n\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins/twitter.js",
    "content": "var _ = require('lodash');\nvar log = require('../core/log.js');\nvar util = require('../core/util.js');\nvar config = util.getConfig();\nvar twitterConfig = config.twitter;\nvar TwitterApi = require('twitter');\n\nrequire('dotenv').config()\n\nvar Twitter = function(done) {\n    _.bindAll(this);\n\n    this.twitter;\n    this.price = 'N/A';\n    this.done = done;\n    this.setup();\n\n};\n\nTwitter.prototype.setup = function(done){\n    var setupTwitter = function (err, result) {\n        this.client = new TwitterApi({\n          consumer_key: twitterConfig.consumer_key,\n          consumer_secret: twitterConfig.consumer_secret,\n          access_token_key: twitterConfig.access_token_key,\n          access_token_secret: twitterConfig.access_token_secret\n        });\n      \n        if(twitterConfig.sendMessageOnStart){\n            var exchange = config.watch.exchange;\n            var currency = config.watch.currency;\n            var asset = config.watch.asset;\n            var body = \"Watching \"\n                +exchange\n                +\" \"\n                +currency\n                +\" \"\n                +asset\n            this.mail(body);\n        }else{\n            log.debug('Skipping Send message on startup')\n        }\n    };\n    setupTwitter.call(this)\n};\n\nTwitter.prototype.processCandle = function(candle, done) {\n    this.price = candle.close;\n\n    done();\n};\n\nTwitter.prototype.processAdvice = function(advice) {\n\tif (advice.recommendation == \"soft\" && twitterConfig.muteSoft) return;\n\tvar text = [\n        'New  ', config.watch.asset, ' trend. Attempting to ',\n        advice.recommendation == \"short\" ? \"sell\" : \"buy\",\n        ' @',\n        this.price,\n    ].join('');\n\n    this.mail(text);\n};\n\nTwitter.prototype.mail = function(content, done) {\n    log.info(\"trying to tweet\");\n    this.client.post('statuses/update', {status: content},  function(error, tweet, response) {\n      if(error || !response) {\n          log.error('Twitter ERROR:', error)\n      } else if(response && response.active){\n          log.info('Twitter Message Sent')\n      }\n    }); \n};\n\nTwitter.prototype.checkResults = function(err) {\n    if(err)\n        log.warn('error sending email', err);\n    else\n        log.info('Send advice via email.');\n};\n\n\nmodule.exports = Twitter;\n"
  },
  {
    "path": "plugins/webserver.js",
    "content": "var log = require('../core/log');\nvar moment = require('moment');\nvar _ = require('lodash');\nvar Server = require('../web/server.js');\n\nvar Actor = function(next) {\n  _.bindAll(this);\n\n  this.server = new Server();\n  this.server.setup(next);\n}\n\nActor.prototype.init = function(data) {\n  this.server.broadcastHistory(data);\n};\n\nActor.prototype.processCandle = function(candle, next) {\n  this.server.broadcastCandle(candle);\n\n  next();\n};\n\nActor.prototype.processAdvice = function(advice) {\n  this.server.broadcastAdvice(advice);\n};\n\nmodule.exports = Actor;"
  },
  {
    "path": "plugins/xmppbot.js",
    "content": "var log = require('../core/log');\nvar moment = require('moment');\nvar _ = require('lodash');\nvar xmpp = require('node-xmpp-client');\nvar config = require('../core/util').getConfig();\nvar xmppbot = config.xmppbot;\nvar utc = moment.utc;\n\n\n\nvar Actor = function() {\n  _.bindAll(this);\n\n  this.bot = new xmpp.Client({ jid: xmppbot.client_id,\n               password: xmppbot.client_pwd,\n               host: xmppbot.client_host,\n               port: xmppbot.client_port\n               });  \n\n  this.advice = 'Dont got one yet :(';\n  this.adviceTime = utc();\n  this.state = xmppbot.status_msg;\n  this.price = 'Dont know yet :(';\n  this.priceTime = utc();\n\n  this.commands = {\n    ';;advice': 'emitAdvice',\n    ';;price': 'emitPrice',\n    ';;donate': 'emitDonation',\n    ';;real advice': 'emitRealAdvice',\n    ';;help': 'emitHelp'\n  };\n\n  this.rawCommands = _.keys(this.commands);\n\n  this.bot.addListener('online', this.setState);\n  this.bot.addListener('stanza', this.rawStanza);\n  this.bot.addListener(\"error\", this.logError);\n  this.bot.connection.socket.setTimeout(0)\n  this.bot.connection.socket.setKeepAlive(true, 10000)\n\n}\n\nActor.prototype.setState = function() {\n    var elem = new xmpp.Element('presence', { }).c('show').t('chat').up().c('status').t(this.state)\n    this.bot.send(elem);\n};\n\nActor.prototype.rawStanza = function(stanza) {\n if (stanza.is('presence') && (stanza.attrs.type == 'subscribe')) {\n            this.bot.send(new xmpp.Element('presence', { to: stanza.attrs.from, type: 'subscribed' }));\n }\n if (stanza.is('message') &&\n     // Important: never reply to errors!\n     stanza.attrs.type !== 'error') {\n\n     // Swap addresses...\n     var from = stanza.attrs.from;\n     var body = stanza.getChild('body');\n     if (!body) {\n       return;\n     }\n\n     var message_recv = body.getText();   //Get Incoming Message\n     this.verifyQuestion(from, message_recv);\t\n  }\n};\n\nActor.prototype.sendMessageTo = function(receiver, message){\n  this.bot.send(new xmpp.Element('message', { to: receiver, type: 'chat' }).\n        c('body').t(message)\n    );\n};\nActor.prototype.sendMessage = function(message) {\n  this.sendMessageTo(this.from, message);\n};\n\nActor.prototype.processCandle = function(candle) {\n  this.price = candle.close;\n  this.priceTime = candle.start;\n};\n\nActor.prototype.processAdvice = function(advice) {\n  if (xmppbot.muteSoft && advice.recommendation === 'soft') return;\n  this.advice = advice.recommendation;\n  this.adviceTime = utc();\n\n  if(xmppbot.emitUpdates)\n    this.newAdvice(xmppbot.receiver);\n};\n\nActor.prototype.verifyQuestion = function(receiver, text) {\n  if(text in this.commands)\n    this[this.commands[text]](receiver);\n}\n\nActor.prototype.newAdvice = function(receiver) {\n  this.sendMessageTo(receiver, 'Important news!');\n  this.emitAdvice(receiver);\n}\n\n// sent advice \nActor.prototype.emitAdvice = function(receiver) {\n  var message = [\n    'Advice for ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' using ',\n    config.tradingAdvisor.method,\n    ' at ',\n    config.tradingAdvisor.candleSize,\n    ' minute candles, is:\\n',\n    this.advice,\n    ' ',\n    config.watch.asset,\n    ' (from ',\n      this.adviceTime.fromNow(),\n    ')'\n  ].join('');\n\n  this.sendMessageTo(receiver, message);\n};\n\n// sent price \nActor.prototype.emitPrice = function(receiver) {\n\n  var message = [\n    'Current price at ',\n    config.watch.exchange,\n    ' ',\n    config.watch.currency,\n    '/',\n    config.watch.asset,\n    ' is ',\n    this.price,\n    ' ',\n    config.watch.currency,\n    ' (from ',\n      this.priceTime.fromNow(),\n    ')'\n  ].join('');\n\n  this.sendMessageTo(receiver, message);\n};\n\n// sent donation info \nActor.prototype.emitDonation = function(receiver) {\n  var message = 'You want to donate? How nice of you! You can send your coins here:';\n  message += '\\nBTC:\\t19UGvmFPfFyFhPMHu61HTMGJqXRdVcHAj3';\n\n  this.sendMessageTo(receiver, message);\n};\n\nActor.prototype.emitHelp = function(receiver) {\n  var message = _.reduce(\n    this.rawCommands,\n    function(message, command) {\n      return message + ' ' + command + ',';\n    },\n    'possible commands are:'\n  );\n\n  message = message.substr(0, _.size(message) - 1) + '.';\n\n  this.sendMessageTo(receiver, message);\n\n}\n\nActor.prototype.emitRealAdvice = function(receiver) {\n  // http://www.examiner.com/article/uncaged-a-look-at-the-top-10-quotes-of-gordon-gekko\n  // http://elitedaily.com/money/memorable-gordon-gekko-quotes/\n  var realAdvice = [\n    'I don\\'t throw darts at a board. I bet on sure things. Read Sun-tzu, The Art of War. Every battle is won before it is ever fought.',\n    'Ever wonder why fund managers can\\'t beat the S&P 500? \\'Cause they\\'re sheep, and sheep get slaughtered.',\n    'If you\\'re not inside, you\\'re outside!',\n    'The most valuable commodity I know of is information.',\n    'It\\'s not a question of enough, pal. It\\'s a zero sum game, somebody wins, somebody loses. Money itself isn\\'t lost or made, it\\'s simply transferred from one perception to another.',\n    'What\\'s worth doing is worth doing for money. (Wait, wasn\\'t I a free and open source bot?)',\n    'When I get a hold of the son of a bitch who leaked this, I\\'m gonna tear his eyeballs out and I\\'m gonna suck his fucking skull.'\n  ];\n\n  this.sendMessageTo(receiver, _.first(_.shuffle(realAdvice)));\n}\n\nActor.prototype.logError = function(message) {\n  log.error('XMPP ERROR:', message);\n};\n\n\nmodule.exports = Actor;\n"
  },
  {
    "path": "plugins.js",
    "content": "// All plugins supported by Gekko.\n//\n//  Required parameters per plugin.\n//\n// name: Name of the plugin\n// slug: name of the plugin mapped to the config key. Expected\n//    filename to exist in `gekko/plugins/` (only if path is not\n//    specified)\n// async: upon creating a new plugin instance, does something async\n//    happen where Gekko needs to wait for? If set to true, the\n//    constructor will be passed a callback which it should execute\n//    as soon as Gekko can continue.\n// modes: a list indicating in what Gekko modes this plugin is\n//    allowed to run. Realtime is during a live market watch and\n//    backtest is during a backtest.\n//\n//\n//  Optional parameters per plugin.\n//\n// description: text describing the plugin.\n// dependencies: a list of external npm modules this plugin requires to\n//    be installed.\n// emits: events emitted by this plugin that other plugins can subscribe to.\n// path: fn that returns path of file of the plugin (overwrites `gekko/plugins/{slug}`)\n//    when given the configuration object (relative from `gekko/plugins/`).\n// greedy: if this plugin wants to subscribe to a lot of events, but can function\n//    properly when some events wont be emitted.\nvar plugins = [\n  {\n    name: 'Candle writer',\n    description: 'Store candles in a database',\n    slug: 'candleWriter',\n    async: true,\n    modes: ['realtime', 'importer'],\n    path: config => config.adapter + '/writer',\n    version: 0.1,\n  },\n  {\n    name: 'Trading Advisor',\n    description: 'Calculate trading advice',\n    slug: 'tradingAdvisor',\n    async: true,\n    modes: ['realtime', 'backtest'],\n    emits: true,\n    path: config => 'tradingAdvisor/tradingAdvisor.js',\n  },\n  {\n    name: 'IRC bot',\n    description: 'IRC module lets you communicate with Gekko on IRC.',\n    slug: 'ircbot',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'irc',\n      version: '0.5.2'\n    }]\n  },\n  {\n    name: 'Telegram bot',\n    description: 'Telegram module lets you communicate with Gekko on Telegram.',\n    slug: 'telegrambot',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'node-telegram-bot-api',\n      version: '0.24.0'\n    }]\n  },\n  {\n    name: 'XMPP bot',\n    description: 'XMPP module lets you communicate with Gekko on Jabber.',\n    slug: 'xmppbot',\n    async: false,\n    silent: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'node-xmpp-client',\n      version: '3.0.2'\n    }]\n  },\n  {\n    name: 'Pushover',\n    description: 'Sends pushover.',\n    slug: 'pushover',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'pushover-notifications',\n      version: '0.2.3'\n    }]\n  },\n  {\n    name: 'Campfire bot',\n    description: 'Lets you communicate with Gekko on Campfire.',\n    slug: 'campfire',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'ranger',\n      version: '0.2.4'\n    }]\n  },\n  {\n    name: 'Mailer',\n    description: 'Sends you an email everytime Gekko has new advice.',\n    slug: 'mailer',\n    async: true,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'emailjs',\n      version: '1.0.5'\n    }, {\n      module: 'prompt-lite',\n      version: '0.1.1'\n    }]\n  },\n  {\n    name: 'Advice logger',\n    description: '',\n    slug: 'adviceLogger',\n    async: false,\n    silent: true,\n    modes: ['realtime']\n  },\n  {\n    name: 'Trader',\n    description: 'Follows the advice and create real orders.',\n    slug: 'trader',\n    async: true,\n    modes: ['realtime'],\n    emits: true,\n    path: config => 'trader/trader.js',\n  },\n  {\n    name: 'Paper Trader',\n    description: 'Paper trader that simulates fake trades.',\n    slug: 'paperTrader',\n    async: false,\n    modes: ['realtime', 'backtest'],\n    emits: true,\n    path: config => 'paperTrader/paperTrader.js',\n  },\n  {\n    name: 'Performance Analyzer',\n    description: 'Analyzes performances of trades',\n    slug: 'performanceAnalyzer',\n    async: false,\n    modes: ['realtime', 'backtest'],\n    emits: true,\n    path: config => 'performanceAnalyzer/performanceAnalyzer.js',\n  },\n  {\n    name: 'Redis beacon',\n    slug: 'redisBeacon',\n    description: 'Publish events over Redis Pub/Sub',\n    async: true,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'redis',\n      version: '0.10.0'\n    }]\n  },\n  {\n    name: 'Pushbullet',\n    description: 'Sends advice to pushbullet.',\n    slug: 'pushbullet',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'pushbullet',\n      version: '1.4.3'\n    }]\n  },\n  {\n    name: 'Kodi',\n    description: 'Sends advice to Kodi.',\n    slug: 'kodi',\n    async: false,\n    modes: ['realtime']\n  },\n  {\n    name: 'Candle Uploader',\n    description: 'Upload candles to an extneral server',\n    slug: 'candleUploader',\n    async: true,\n    modes: ['realtime']\n  },\n  {\n    name: 'Twitter',\n    description: 'Sends trades to twitter.',\n    slug: 'twitter',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'twitter',\n      version: '1.7.1'\n    }]\n  },\n  {\n    name: 'Slack',\n    description: 'Sends trades to slack channel.',\n    slug: 'slack',\n    async: false,\n    modes: ['realtime'],\n    dependencies: [{\n      module: '@slack/client',\n      version: '3.13.0'\n    }]\n  },\n  {\n    name: 'IFTTT',\n    description: 'Sends trades to IFTTT webhook.',\n    slug: 'ifttt',\n    async: false,\n    modes: ['realtime']\n  },\n  {\n    name: 'Event logger',\n    description: 'Logs all gekko events.',\n    slug: 'eventLogger',\n    async: false,\n    modes: ['realtime', 'backtest'],\n    greedy: true\n  },\n  {\n    name: 'Backtest result export',\n    description: 'Exports the results of a gekko backtest',\n    slug: 'backtestResultExporter',\n    async: false,\n    modes: ['backtest']\n  },\n  {\n    name: 'Child to parent',\n    description: 'Relays events from the child to the parent process',\n    slug: 'childToParent',\n    async: false,\n    modes: ['realtime'],\n    greedy: true\n  },\n  {\n    name: 'Candle Uploader',\n    description: 'Upload realtime market candles to an external server',\n    slug: 'candleUploader',\n    async: true,\n    modes: ['realtime'],\n    dependencies: [{\n      module: 'axios',\n      version: '0.18.0'\n    }]\n  },\n  {\n    name: 'Blotter',\n    description: 'Writes all buy/sell trades to a blotter CSV file',\n    slug: 'blotter',\n    async: false,\n    modes: ['realtime'],\n  },\n];\n\nmodule.exports = plugins;\n"
  },
  {
    "path": "sample-config.js",
    "content": "// Everything is explained here:\n// @link https://gekko.wizb.it/docs/commandline/plugins.html\n\nvar config = {};\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                          GENERAL SETTINGS\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.debug = true; // for additional logging / debugging\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                         WATCHING A MARKET\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.watch = {\n\n  // see https://gekko.wizb.it/docs/introduction/supported_exchanges.html\n  exchange: 'binance',\n  currency: 'USDT',\n  asset: 'BTC',\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING TRADING ADVICE\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.tradingAdvisor = {\n  enabled: true,\n  method: 'MACD',\n  candleSize: 60,\n  historySize: 10,\n}\n\n// MACD settings:\nconfig.MACD = {\n  // EMA weight (α)\n  // the higher the weight, the more smooth (and delayed) the line\n  short: 10,\n  long: 21,\n  signal: 9,\n  // the difference between the EMAs (to act as triggers)\n  thresholds: {\n    down: -0.025,\n    up: 0.025,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 1\n  }\n};\n\n// settings for other strategies can be found at the bottom, note that only\n// one strategy is active per gekko, the other settings are ignored.\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING PLUGINS\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n// do you want Gekko to simulate the profit of the strategy's own advice?\nconfig.paperTrader = {\n  enabled: true,\n  // report the profit in the currency or the asset?\n  reportInCurrency: true,\n  // start balance, on what the current balance is compared with\n  simulationBalance: {\n    // these are in the unit types configured in the watcher.\n    asset: 1,\n    currency: 100,\n  },\n  // how much fee in % does each trade cost?\n  feeMaker: 0.15,\n  feeTaker: 0.25,\n  feeUsing: 'maker',\n  // how much slippage/spread should Gekko assume per trade?\n  slippage: 0.05,\n}\n\nconfig.performanceAnalyzer = {\n  enabled: true,\n  riskFreeReturn: 5\n}\n\n// Want Gekko to perform real trades on buy or sell advice?\n// Enabling this will activate trades for the market being\n// watched by `config.watch`.\nconfig.trader = {\n  enabled: false,\n  key: '',\n  secret: '',\n  username: '', // your username, only required for specific exchanges.\n  passphrase: '', // GDAX, requires a passphrase.\n}\n\nconfig.eventLogger = {\n  enabled: false,\n  // optionally pass a whitelist of events to log, if not past\n  // the eventLogger will log _all_ events.\n  // whitelist: ['portfolioChange', 'portfolioValueChange']\n}\n\nconfig.pushover = {\n  enabled: false,\n  sendPushoverOnStart: false,\n  muteSoft: true, // disable advice printout if it's soft\n  tag: '[GEKKO]',\n  key: '',\n  user: ''\n}\n\nconfig.blotter = {\n  enabled: false,\n  filename: 'blotter.csv',\n  dateFormat: 'l LT',\n  timezone: -300, // -300 minutes for EST(-5:00), only used if exchange doesn't provide correct timezone\n}\n\n// want Gekko to send a mail on buy or sell advice?\nconfig.mailer = {\n  enabled: false, // Send Emails if true, false to turn off\n  sendMailOnStart: true, // Send 'Gekko starting' message if true, not if false\n\n  email: '', // Your Gmail address\n  muteSoft: true, // disable advice printout if it's soft\n\n  // You don't have to set your password here, if you leave it blank we will ask it\n  // when Gekko's starts.\n  //\n  // NOTE: Gekko is an open source project < https://github.com/askmike/gekko >,\n  // make sure you looked at the code or trust the maintainer of this bot when you\n  // fill in your email and password.\n  //\n  // WARNING: If you have NOT downloaded Gekko from the github page above we CANNOT\n  // guarantuee that your email address & password are safe!\n\n  password: '', // Your Gmail Password - if not supplied Gekko will prompt on startup.\n\n  tag: '[GEKKO] ', // Prefix all email subject lines with this\n\n  //       ADVANCED MAIL SETTINGS\n  // you can leave those as is if you\n  // just want to use Gmail\n\n  server: 'smtp.gmail.com', // The name of YOUR outbound (SMTP) mail server.\n  smtpauth: true, // Does SMTP server require authentication (true for Gmail)\n  // The following 3 values default to the Email (above) if left blank\n  user: '', // Your Email server user name - usually your full Email address 'me@mydomain.com'\n  from: '', // 'me@mydomain.com'\n  to: '', // 'me@somedomain.com, me@someotherdomain.com'\n  ssl: true, // Use SSL (true for Gmail)\n  port: '', // Set if you don't want to use the default port\n}\n\nconfig.pushbullet = {\n  // sends pushbullets if true\n  enabled: false,\n  // Send 'Gekko starting' message if true\n  sendMessageOnStart: true,\n  // Send Message for advice? Recommend Flase for paper, true for live\n  sendOnAdvice: true,\n  // Send Message on Trade Completion?\n  sendOnTrade: true,\n  // For Overall P/L calc. Pass in old balance if desired, else leave '0'\n  startingBalance: 0,\n  // your pushbullet API key\n  key: '',\n  // your email\n  email: 'jon_snow@westeros.com',\n  // Messages will start with this tag\n  tag: '[GEKKO]'\n};\n\nconfig.kodi = {\n  // if you have a username & pass, add it like below\n  // http://user:pass@ip-or-hostname:8080/jsonrpc\n  host: 'http://ip-or-hostname:8080/jsonrpc',\n  enabled: false,\n  sendMessageOnStart: true,\n}\n\nconfig.ircbot = {\n  enabled: false,\n  emitUpdates: false,\n  muteSoft: true,\n  channel: '#your-channel',\n  server: 'irc.freenode.net',\n  botName: 'gekkobot'\n}\n\nconfig.telegrambot = {\n  enabled: false,\n  // Receive notifications for trades and warnings/errors related to trading\n  emitTrades: false,\n  token: 'YOUR_TELEGRAM_BOT_TOKEN',\n};\n\nconfig.twitter = {\n  // sends pushbullets if true\n  enabled: false,\n  // Send 'Gekko starting' message if true\n  sendMessageOnStart: false,\n  // disable advice printout if it's soft\n  muteSoft: false,\n  tag: '[GEKKO]',\n  // twitter consumer key\n  consumer_key: '',\n  // twitter consumer secret\n  consumer_secret: '',\n  // twitter access token key\n  access_token_key: '',\n  // twitter access token secret\n  access_token_secret: ''\n};\n\nconfig.xmppbot = {\n  enabled: false,\n  emitUpdates: false,\n  client_id: 'jabber_id',\n  client_pwd: 'jabber_pw',\n  client_host: 'jabber_server',\n  client_port: 5222,\n  status_msg: 'I\\'m online',\n  receiver: 'jabber_id_for_updates'\n}\n\nconfig.campfire = {\n  enabled: false,\n  emitUpdates: false,\n  nickname: 'Gordon',\n  roomId: null,\n  apiKey: '',\n  account: ''\n}\n\nconfig.redisBeacon = {\n  enabled: false,\n  port: 6379, // redis default\n  host: '127.0.0.1', // localhost\n  // On default Gekko broadcasts\n  // events in the channel with\n  // the name of the event, set\n  // an optional prefix to the\n  // channel name.\n  channelPrefix: '',\n  broadcast: [\n    'candle'\n  ]\n}\n\nconfig.slack = {\n  enabled: false,\n  token: '',\n  sendMessageOnStart: true,\n  muteSoft: true,\n  channel: '' // #tradebot\n}\n\nconfig.ifttt = {\n  enabled: false,\n  eventName: 'gekko',\n  makerKey: '',\n  muteSoft: true,\n  sendMessageOnStart: true\n}\n\nconfig.candleWriter = {\n  enabled: true\n}\n\nconfig.adviceWriter = {\n  enabled: false,\n  muteSoft: true,\n}\n\nconfig.backtestResultExporter = {\n  enabled: false,\n  writeToDisk: false,\n  data: {\n    stratUpdates: false,\n    portfolioValues: true,\n    stratCandles: true,\n    roundtrips: true,\n    trades: true\n  }\n}\n\nconfig.candleUploader = {\n  enabled: false,\n  url: '',\n  apiKey: ''\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING ADAPTER\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.adapter = 'sqlite';\n\nconfig.sqlite = {\n  path: 'plugins/sqlite',\n\n  dataDirectory: 'history',\n  version: 0.1,\n\n  journalMode: require('./web/isWindows.js') ? 'DELETE' : 'WAL',\n\n  dependencies: []\n}\n\n// Postgres adapter example config (please note: requires postgres >= 9.5):\nconfig.postgresql = {\n  path: 'plugins/postgresql',\n  version: 0.1,\n  connectionString: 'postgres://user:pass@localhost:5432', // if default port\n  database: null, // if set, we'll put all tables into a single database.\n  schema: 'public',\n  dependencies: [{\n    module: 'pg',\n    version: '7.4.3'\n  }]\n}\n\n// Mongodb adapter, requires mongodb >= 3.3 (no version earlier tested)\nconfig.mongodb = {\n  path: 'plugins/mongodb',\n  version: 0.1,\n  connectionString: 'mongodb://localhost/gekko', // connection to mongodb server\n  dependencies: [{\n    module: 'mongojs',\n    version: '2.4.0'\n  }]\n}\n\nconfig.candleUploader = {\n  enabled: false,\n  url: '',\n  apiKey: ''\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING BACKTESTING\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n// Note that these settings are only used in backtesting mode, see here:\n// @link: https://gekko.wizb.it/docs/commandline/backtesting.html\n\nconfig.backtest = {\n  daterange: 'scan',\n  // daterange: {\n  //   from: \"2018-03-01\",\n  //   to: \"2018-04-28\"\n  //},\n  batchSize: 50\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING IMPORTING\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.importer = {\n  daterange: {\n    // NOTE: these dates are in UTC\n    from: \"2017-11-01 00:00:00\",\n    to: \"2017-11-20 00:00:00\"\n  }\n}\n\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                      OTHER STRATEGY SETTINGS\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n// Exponential Moving Averages settings:\nconfig.DEMA = {\n  // EMA weight (α)\n  // the higher the weight, the more smooth (and delayed) the line\n  weight: 21,\n  // amount of candles to remember and base initial EMAs on\n  // the difference between the EMAs (to act as triggers)\n  thresholds: {\n    down: -0.025,\n    up: 0.025\n  }\n};\n\n// PPO settings:\nconfig.PPO = {\n  // EMA weight (α)\n  // the higher the weight, the more smooth (and delayed) the line\n  short: 12,\n  long: 26,\n  signal: 9,\n  // the difference between the EMAs (to act as triggers)\n  thresholds: {\n    down: -0.025,\n    up: 0.025,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 2\n  }\n};\n\n// Uses one of the momentum indicators but adjusts the thresholds when PPO is bullish or bearish\n// Uses settings from the ppo and momentum indicator config block\nconfig.varPPO = {\n  momentum: 'TSI', // RSI, TSI or UO\n  thresholds: {\n    // new threshold is default threshold + PPOhist * PPOweight\n    weightLow: 120,\n    weightHigh: -120,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 0\n  }\n};\n\n// RSI settings:\nconfig.RSI = {\n  interval: 14,\n  thresholds: {\n    low: 30,\n    high: 70,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 1\n  }\n};\n\n// TSI settings:\nconfig.TSI = {\n  short: 13,\n  long: 25,\n  thresholds: {\n    low: -25,\n    high: 25,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 1\n  }\n};\n\n// Ultimate Oscillator Settings\nconfig.UO = {\n  first: {\n    weight: 4,\n    period: 7\n  },\n  second: {\n    weight: 2,\n    period: 14\n  },\n  third: {\n    weight: 1,\n    period: 28\n  },\n  thresholds: {\n    low: 30,\n    high: 70,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 1\n  }\n};\n\n// CCI Settings\nconfig.CCI = {\n  constant: 0.015, // constant multiplier. 0.015 gets to around 70% fit\n  history: 90, // history size, make same or smaller than history\n  thresholds: {\n    up: 100, // fixed values for overbuy upward trajectory\n    down: -100, // fixed value for downward trajectory\n    persistence: 0 // filter spikes by adding extra filters candles\n  }\n};\n\n// StochRSI settings\nconfig.StochRSI = {\n  interval: 3,\n  thresholds: {\n    low: 20,\n    high: 80,\n    // How many candle intervals should a trend persist\n    // before we consider it real?\n    persistence: 3\n  }\n};\n\n\n// custom settings:\nconfig.custom = {\n  my_custom_setting: 10,\n}\n\nconfig['talib-macd'] = {\n  parameters: {\n    optInFastPeriod: 10,\n    optInSlowPeriod: 21,\n    optInSignalPeriod: 9\n  },\n  thresholds: {\n    down: -0.025,\n    up: 0.025,\n  }\n}\n\nconfig['talib-macd'] = {\n  parameters: {\n    optInFastPeriod: 10,\n    optInSlowPeriod: 21,\n    optInSignalPeriod: 9\n  },\n  thresholds: {\n    down: -0.025,\n    up: 0.025,\n  }\n}\n\nconfig['tulip-adx'] = {\n  optInTimePeriod: 10,\n  thresholds: {\n    down: -0.025,\n    up: 0.025,\n  }\n}\n\n\n// set this to true if you understand that Gekko will\n// invest according to how you configured the indicators.\n// None of the advice in the output is Gekko telling you\n// to take a certain position. Instead it is the result\n// of running the indicators you configured automatically.\n//\n// In other words: Gekko automates your trading strategies,\n// it doesn't advice on itself, only set to true if you truly\n// understand this.\n//\n// Not sure? Read this first: https://github.com/askmike/gekko/issues/201\nconfig['I understand that Gekko only automates MY OWN trading strategies'] = false;\n\nmodule.exports = config;"
  },
  {
    "path": "strategies/CCI.js",
    "content": "// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.currentTrend;\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  this.age = 0;\n  this.trend = {\n    direction: 'undefined',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n  this.historySize = this.settings.history;\n  this.ppoadv = 'none';\n  this.uplevel = this.settings.thresholds.up;\n  this.downlevel = this.settings.thresholds.down;\n  this.persisted = this.settings.thresholds.persistence;\n\n  // log.debug(\"CCI started with:\\nup:\\t\", this.uplevel, \"\\ndown:\\t\", this.downlevel, \"\\npersistence:\\t\", this.persisted);\n  // define the indicators we need\n  this.addIndicator('cci', 'CCI', this.settings);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n}\n\n// for debugging purposes: log the last calculated\n// EMAs and diff.\nmethod.log = function(candle) {\n    var cci = this.indicators.cci;\n    if (typeof(cci.result) == 'boolean') {\n        log.debug('Insufficient data available. Age: ', cci.size, ' of ', cci.maxSize);\n        return;\n    }\n\n    log.debug('calculated CCI properties for candle:');\n    log.debug('\\t', 'Price:\\t\\t', candle.close.toFixed(8));\n    log.debug('\\t', 'CCI tp:\\t', cci.tp.toFixed(8));\n    log.debug('\\t', 'CCI tp/n:\\t', cci.avgtp.toFixed(8));\n    log.debug('\\t', 'CCI md:\\t', cci.mean.toFixed(8));\n    if (typeof(cci.result) == 'boolean' )\n        log.debug('\\t In sufficient data available.');\n    else\n        log.debug('\\t', 'CCI:\\t\\t', cci.result.toFixed(2));\n}\n\n/*\n *\n */\nmethod.check = function(candle) {\n\n    var lastPrice = candle.close;\n\n    this.age++;\n    var cci = this.indicators.cci;\n\n    if (typeof(cci.result) == 'number') {\n\n        // overbought?\n        if (cci.result >= this.uplevel && (this.trend.persisted || this.persisted == 0) && !this.trend.adviced && this.trend.direction == 'overbought' ) {\n            this.trend.adviced = true;\n            this.trend.duration++;\n            this.advice('short');\n        } else if (cci.result >= this.uplevel && this.trend.direction != 'overbought') {\n            this.trend.duration = 1;\n            this.trend.direction = 'overbought';\n            this.trend.persisted = false;\n            this.trend.adviced = false;\n            if (this.persisted == 0) {\n                this.trend.adviced = true;\n                this.advice('short');\n            }\n        } else if (cci.result >= this.uplevel) {\n            this.trend.duration++;\n            if (this.trend.duration >= this.persisted) {\n                this.trend.persisted = true;\n            }\n        } else if (cci.result <= this.downlevel && (this.trend.persisted || this.persisted == 0) && !this.trend.adviced && this.trend.direction == 'oversold') {\n            this.trend.adviced = true;\n            this.trend.duration++;\n            this.advice('long');\n        } else if (cci.result <= this.downlevel && this.trend.direction != 'oversold') {\n            this.trend.duration = 1;\n            this.trend.direction = 'oversold';\n            this.trend.persisted = false;\n            this.trend.adviced = false;\n            if (this.persisted == 0) {\n                this.trend.adviced = true;\n                this.advice('long');\n            }\n        } else if (cci.result <= this.downlevel) {\n            this.trend.duration++;\n            if (this.trend.duration >= this.persisted) {\n                this.trend.persisted = true;\n            }\n        } else {\n            if( this.trend.direction != 'nodirection') {\n                this.trend = {\n                    direction: 'nodirection',\n                    duration: 0,\n                    persisted: false,\n                    adviced: false\n                };\n            } else {\n                this.trend.duration++;\n            }\n            this.advice();\n        }\n\n    } else {\n        this.advice();\n    }\n\n    log.debug(\"Trend: \", this.trend.direction, \" for \", this.trend.duration);\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/DEBUG_single-advice.js",
    "content": "var settings = {\n  wait: 0,\n  // advice: 'short'\n  advice: 'long'\n};\n\n// -------\n\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar i = 0;\n\nvar method = {\n  init: _.noop,\n  update: _.noop,\n  log: _.noop,\n  check: function() {\n\n    // log.info('iteration:', i);\n    if(settings.wait === i) {\n      console.log('trigger advice!');\n      this.advice({\n        direction: settings.advice,\n        trigger: {\n          type: 'trailingStop',\n          trailPercentage: 0.5\n        }\n      });\n    }\n\n    i++\n\n  }\n};\n\nmodule.exports = method;"
  },
  {
    "path": "strategies/DEBUG_toggle-advice.js",
    "content": "var settings = {\n  wait: 0,\n  each: 6\n};\n\n// -------\n\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar i = 0;\n\nvar method = {\n  init: _.noop,\n  update: _.noop,\n  log: _.noop,\n  processTrade: function(trade) {\n    log.debug('TRADE RECEIVED BY processTrade:', trade);\n  },\n  check: function(candle) {\n\n    if(settings.wait > i)\n      return;\n\n    log.info('iteration:', i);\n\n    if(i % settings.each === 0) {\n      log.debug('trigger SHORT');\n      this.advice('short');\n    } else if(i % settings.each === settings.each / 2) {\n      log.debug('trigger LONG');\n      this.advice('long');\n    }\n\n    // if(i % 2 === 0)\n    //   this.advice('long');\n    // else if(i % 2 === 1)\n    //   this.advice('short');\n\n    i++;\n\n  }\n};\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/DEMA.js",
    "content": "// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.name = 'DEMA';\n\n  this.currentTrend;\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('dema', 'DEMA', this.settings);\n  this.addIndicator('sma', 'SMA', this.settings.weight);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n// for debugging purposes: log the last calculated\n// EMAs and diff.\nmethod.log = function() {\n  let dema = this.indicators.dema;\n  let sma = this.indicators.sma;\n  \n  log.debug('Calculated DEMA and SMA properties for candle:');\n  log.debug('\\t Inner EMA:', dema.inner.result.toFixed(8));\n  log.debug('\\t Outer EMA:', dema.outer.result.toFixed(8));\n  log.debug('\\t DEMA:', dema.result.toFixed(5));\n  log.debug('\\t SMA:', sma.result.toFixed(5));\n  log.debug('\\t DEMA age:', dema.inner.age, 'candles');\n}\n\nmethod.check = function(candle) {\n  let dema = this.indicators.dema;\n  let sma = this.indicators.sma;\n  let resDEMA = dema.result;\n  let resSMA = sma.result;\n  let price = candle.close;\n  let diff = resSMA - resDEMA;\n\n  let message = '@ ' + price.toFixed(8) + ' (' + resDEMA.toFixed(5) + '/' + diff.toFixed(5) + ')';\n\n  if(diff > this.settings.thresholds.up) {\n    log.debug('we are currently in uptrend', message);\n\n    if(this.currentTrend !== 'up') {\n      this.currentTrend = 'up';\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else if(diff < this.settings.thresholds.down) {\n    log.debug('we are currently in a downtrend', message);\n\n    if(this.currentTrend !== 'down') {\n      this.currentTrend = 'down';\n      this.advice('short');\n    } else\n      this.advice();\n\n  } else {\n    log.debug('we are currently not in an up or down trend', message);\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/MACD.js",
    "content": "/*\n\n  MACD - DJM 31/12/2013\n\n  (updated a couple of times since, check git history)\n\n */\n\n// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  // keep state about the current trend\n  // here, on every new candle we use this\n  // state object to check if we need to\n  // report it.\n  this.trend = {\n    direction: 'none',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n\n  // how many candles do we need as a base\n  // before we can start giving advice?\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('macd', 'MACD', this.settings);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n// for debugging purposes: log the last calculated\n// EMAs and diff.\nmethod.log = function() {\n  var digits = 8;\n  var macd = this.indicators.macd;\n\n  var diff = macd.diff;\n  var signal = macd.signal.result;\n\n  log.debug('calculated MACD properties for candle:');\n  log.debug('\\t', 'short:', macd.short.result.toFixed(digits));\n  log.debug('\\t', 'long:', macd.long.result.toFixed(digits));\n  log.debug('\\t', 'macd:', diff.toFixed(digits));\n  log.debug('\\t', 'signal:', signal.toFixed(digits));\n  log.debug('\\t', 'macdiff:', macd.result.toFixed(digits));\n}\n\nmethod.check = function() {\n  var macddiff = this.indicators.macd.result;\n\n  if(macddiff > this.settings.thresholds.up) {\n\n    // new trend detected\n    if(this.trend.direction !== 'up')\n      // reset the state for the new trend\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'up',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In uptrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else if(macddiff < this.settings.thresholds.down) {\n\n    // new trend detected\n    if(this.trend.direction !== 'down')\n      // reset the state for the new trend\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'down',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In downtrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n  } else {\n\n    log.debug('In no trend');\n\n    // we're not in an up nor in a downtrend\n    // but for now we ignore sideways trends\n    //\n    // read more @link:\n    //\n    // https://github.com/askmike/gekko/issues/171\n\n    // this.trend = {\n    //   direction: 'none',\n    //   duration: 0,\n    //   persisted: false,\n    //   adviced: false\n    // };\n\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/PPO.js",
    "content": "/*\n\n  PPO - cykedev 15/01/2014\n\n  (updated a couple of times since, check git history)\n\n */\n\n// helpers\nvar _ = require('lodash');\nvar log = require('../core/log');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.name = 'PPO';\n\n  this.trend = {\n   direction: 'none',\n   duration: 0,\n   persisted: false,\n   adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('ppo', 'PPO', this.settings);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function() {\n  var digits = 8;\n  var ppo = this.indicators.ppo;\n  var long = ppo.result.longEMA;\n  var short = ppo.result.shortEMA;\n  var macd = ppo.result.macd;\n  var result = ppo.result.ppo;\n  var macdSignal = ppo.result.MACDsignal;\n  var ppoSignal = ppo.result.PPOsignal;\n\n  log.debug('calculated MACD properties for candle:');\n  log.debug('\\t', 'short:', short.toFixed(digits));\n  log.debug('\\t', 'long:', long.toFixed(digits));\n  log.debug('\\t', 'macd:', macd.toFixed(digits));\n  log.debug('\\t', 'macdsignal:', macdSignal.toFixed(digits));\n  log.debug('\\t', 'machist:', (macd - macdSignal).toFixed(digits));\n  log.debug('\\t', 'ppo:', result.toFixed(digits));\n  log.debug('\\t', 'pposignal:', ppoSignal.toFixed(digits));\n  log.debug('\\t', 'ppohist:', (result - ppoSignal).toFixed(digits));\n}\n\nmethod.check = function(candle) {\n  var price = candle.close;\n\n  var ppo = this.indicators.ppo;\n  var long = ppo.result.longEMA;\n  var short = ppo.result.shortEMA;\n  var macd = ppo.result.macd;\n  var result = ppo.result.ppo;\n  var macdSignal = ppo.result.MACDsignal;\n  var ppoSignal = ppo.result.PPOsignal;\n\n  // TODO: is this part of the indicator or not?\n  // if it is it should move there\n  var ppoHist = result - ppoSignal;\n\n  if(ppoHist > this.settings.thresholds.up) {\n\n    // new trend detected\n    if(this.trend.direction !== 'up')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'up',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In uptrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else if(ppoHist < this.settings.thresholds.down) {\n\n    // new trend detected\n    if(this.trend.direction !== 'down')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'down',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In downtrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n\n  } else {\n\n    log.debug('In no trend');\n\n    // we're not in an up nor in a downtrend\n    // but for now we ignore sideways trends\n    //\n    // read more @link:\n    //\n    // https://github.com/askmike/gekko/issues/171\n\n    // this.trend = {\n    //   direction: 'none',\n    //   duration: 0,\n    //   persisted: false,\n    //   adviced: false\n    // };\n\n    this.advice();\n  }\n\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/RSI.js",
    "content": "/*\n\n  RSI - cykedev 14/02/2014\n\n  (updated a couple of times since, check git history)\n\n */\n// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar RSI = require('./indicators/RSI.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.name = 'RSI';\n\n  this.trend = {\n    direction: 'none',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('rsi', 'RSI', this.settings);\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function(candle) {\n  var digits = 8;\n  var rsi = this.indicators.rsi;\n\n  log.debug('calculated RSI properties for candle:');\n  log.debug('\\t', 'rsi:', rsi.result.toFixed(digits));\n  log.debug('\\t', 'price:', candle.close.toFixed(digits));\n}\n\nmethod.check = function() {\n  var rsi = this.indicators.rsi;\n  var rsiVal = rsi.result;\n\n  if(rsiVal > this.settings.thresholds.high) {\n\n    // new trend detected\n    if(this.trend.direction !== 'high')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'high',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In high since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n  } else if(rsiVal < this.settings.thresholds.low) {\n\n    // new trend detected\n    if(this.trend.direction !== 'low')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'low',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In low since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else {\n\n    log.debug('In no trend');\n\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/StochRSI.js",
    "content": "/*\n\n  StochRSI - SamThomp 11/06/2014\n\n  (updated by askmike) @ 30/07/2016\n\n */\n// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar RSI = require('./indicators/RSI.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.interval = this.settings.interval;\n\n  this.trend = {\n    direction: 'none',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('rsi', 'RSI', { interval: this.interval });\n\n\tthis.RSIhistory = [];\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n\tthis.rsi = this.indicators.rsi.result;\n\n\tthis.RSIhistory.push(this.rsi);\n\n\tif(_.size(this.RSIhistory) > this.interval)\n\t\t// remove oldest RSI value\n\t\tthis.RSIhistory.shift();\n\n\tthis.lowestRSI = _.min(this.RSIhistory);\n\tthis.highestRSI = _.max(this.RSIhistory);\n\tthis.stochRSI = ((this.rsi - this.lowestRSI) / (this.highestRSI - this.lowestRSI)) * 100;\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function() {\n  var digits = 8;\n\n  log.debug('calculated StochRSI properties for candle:');\n  log.debug('\\t', 'rsi:', this.rsi.toFixed(digits));\n\tlog.debug(\"StochRSI min:\\t\\t\" + this.lowestRSI.toFixed(digits));\n\tlog.debug(\"StochRSI max:\\t\\t\" + this.highestRSI.toFixed(digits));\n\tlog.debug(\"StochRSI Value:\\t\\t\" + this.stochRSI.toFixed(2));\n}\n\nmethod.check = function() {\n\tif(this.stochRSI > this.settings.thresholds.high) {\n\t\t// new trend detected\n\t\tif(this.trend.direction !== 'high')\n\t\t\tthis.trend = {\n\t\t\t\tduration: 0,\n\t\t\t\tpersisted: false,\n\t\t\t\tdirection: 'high',\n\t\t\t\tadviced: false\n\t\t\t};\n\n\t\tthis.trend.duration++;\n\n\t\tlog.debug('In high since', this.trend.duration, 'candle(s)');\n\n\t\tif(this.trend.duration >= this.settings.thresholds.persistence)\n\t\t\tthis.trend.persisted = true;\n\n\t\tif(this.trend.persisted && !this.trend.adviced) {\n\t\t\tthis.trend.adviced = true;\n\t\t\tthis.advice('short');\n\t\t} else\n\t\t\tthis.advice();\n\n\t} else if(this.stochRSI < this.settings.thresholds.low) {\n\n\t\t// new trend detected\n\t\tif(this.trend.direction !== 'low')\n\t\t\tthis.trend = {\n\t\t\t\tduration: 0,\n\t\t\t\tpersisted: false,\n\t\t\t\tdirection: 'low',\n\t\t\t\tadviced: false\n\t\t\t};\n\n\t\tthis.trend.duration++;\n\n\t\tlog.debug('In low since', this.trend.duration, 'candle(s)');\n\n\t\tif(this.trend.duration >= this.settings.thresholds.persistence)\n\t\t\tthis.trend.persisted = true;\n\n\t\tif(this.trend.persisted && !this.trend.adviced) {\n\t\t\tthis.trend.adviced = true;\n\t\t\tthis.advice('long');\n\t\t} else\n\t\t\tthis.advice();\n\n\t} else {\n\t\t// trends must be on consecutive candles\n\t\tthis.trend.duration = 0;\n\t\tlog.debug('In no trend');\n\n\t\tthis.advice();\n\t}\n\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/TMA.js",
    "content": "var method = {};\n\nmethod.init = function() {\n  this.name = 'Triple Moving Average';\n  this.requiredHistory = this.settings.long;\n\n  this.addIndicator('short', 'SMA', this.settings.short)\n  this.addIndicator('medium', 'SMA', this.settings.medium)\n  this.addIndicator('long', 'SMA', this.settings.long)\n}\n\nmethod.update = function(candle) {\n  this.indicators.short.update(candle.close)\n  this.indicators.medium.update(candle.close)\n  this.indicators.long.update(candle.close)\n}\n\nmethod.check = function() {\n  const short = this.indicators.short.result;\n  const medium = this.indicators.medium.result;\n  const long = this.indicators.long.result;\n\n  if((short > medium) && (medium > long)) {\n    this.advice('long')\n  } else if((short < medium) && (medium > long)) {\n    this.advice('short')\n  } else if(((short > medium) && (medium < long))) {\n    this.advice('short')\n  } else {\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/TSI.js",
    "content": "// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar TSI = require('./indicators/TSI.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.name = 'TSI';\n\n  this.trend = {\n    direction: 'none',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('tsi', 'TSI', this.settings);\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function(candle) {\n  var digits = 8;\n  var tsi = this.indicators.tsi;\n\n  log.debug('calculated TSI properties for candle:');\n  log.debug('\\t', 'tsi:', tsi.tsi.toFixed(digits));\n  log.debug('\\t', 'price:', candle.close.toFixed(digits));\n}\n\nmethod.check = function() {\n  var tsi = this.indicators.tsi;\n  var tsiVal = tsi.tsi;\n\n  if(tsiVal > this.settings.thresholds.high) {\n\n    // new trend detected\n    if(this.trend.direction !== 'high')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'high',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In high since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n  } else if(tsiVal < this.settings.thresholds.low) {\n\n    // new trend detected\n    if(this.trend.direction !== 'low')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'low',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In low since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else {\n\n    log.debug('In no trend');\n\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/UO.js",
    "content": "// helpers\nvar _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar UO = require('./indicators/UO.js');\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.name = 'UO';\n\n  this.trend = {\n    direction: 'none',\n    duration: 0,\n    persisted: false,\n    adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('uo', 'UO', this.settings);\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function(candle) {\n  var digits = 8;\n  var uo = this.indicators.uo;\n\n  log.debug('calculated Ultimate Oscillator properties for candle:');\n  log.debug('\\t', 'UO:', uo.uo.toFixed(digits));\n  log.debug('\\t', 'price:', candle.close.toFixed(digits));\n}\n\nmethod.check = function() {\n  var uo = this.indicators.uo;\n  var uoVal = uo.uo;\n\n  if(uoVal > this.settings.thresholds.high) {\n\n    // new trend detected\n    if(this.trend.direction !== 'high')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'high',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In high since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n  } else if(uoVal < this.settings.thresholds.low) {\n\n    // new trend detected\n    if(this.trend.direction !== 'low')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'low',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In low since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= this.settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else {\n\n    log.debug('In no trend');\n\n    this.advice();\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/custom.js",
    "content": "// This is a basic example strategy for Gekko.\n// For more information on everything please refer\n// to this document:\n//\n// https://gekko.wizb.it/docs/strategies/creating_a_strategy.html\n//\n// The example below is pretty bad investment advice: on every new candle there is\n// a 10% chance it will recommend to change your position (to either\n// long or short).\n\nvar log = require('../core/log');\n\n// Let's create our own strat\nvar strat = {};\n\n// Prepare everything our method needs\nstrat.init = function() {\n  this.input = 'candle';\n  this.currentTrend = 'long';\n  this.requiredHistory = 0;\n}\n\n// What happens on every new candle?\nstrat.update = function(candle) {\n\n  // Get a random number between 0 and 1.\n  this.randomNumber = Math.random();\n\n  // There is a 10% chance it is smaller than 0.1\n  this.toUpdate = this.randomNumber < 0.1;\n}\n\n// For debugging purposes.\nstrat.log = function() {\n  log.debug('calculated random number:');\n  log.debug('\\t', this.randomNumber.toFixed(3));\n}\n\n// Based on the newly calculated\n// information, check if we should\n// update or not.\nstrat.check = function() {\n\n  // Only continue if we have a new update.\n  if(!this.toUpdate)\n    return;\n\n  if(this.currentTrend === 'long') {\n\n    // If it was long, set it to short\n    this.currentTrend = 'short';\n    this.advice('short');\n\n  } else {\n\n    // If it was short, set it to long\n    this.currentTrend = 'long';\n    this.advice('long');\n\n  }\n}\n\nmodule.exports = strat;\n"
  },
  {
    "path": "strategies/indicators/CCI.js",
    "content": "/*\n * CCI\n */\nvar log = require('../../core/log');\n\nvar Indicator = function(settings) {\n  this.input = 'candle';\n  this.tp = 0.0;\n  this.result = false;\n  this.hist = []; // needed for mean?\n  this.mean = 0.0;\n  this.size = 0;\n  this.constant = settings.constant;\n  this.maxSize = settings.history;\n  for (var i = 0; i < this.maxSize; i++)\n      this.hist.push(0.0);\n}\n\nIndicator.prototype.update = function(candle) {\n  \n  // We need sufficient history to get the right result. \n\n  var tp = (candle.high + candle.close + candle.low) / 3;\n  if (this.size < this.maxSize) {\n      this.hist[this.size] = tp;\n      this.size++;\n  } else {\n      for (var i = 0; i < this.maxSize-1; i++) {\n          this.hist[i] = this.hist[i+1];\n      }\n      this.hist[this.maxSize-1] = tp;\n  }\n\n  if (this.size < this.maxSize) {\n      this.result = false;\n  } else {\n      this.calculate(tp);\n  }\n}\n\n/*\n * Handle calculations\n */\nIndicator.prototype.calculate = function(tp) {\n\n   var sumtp = 0.0\n\t\n\t for (var i = 0; i < this.size; i++) {\n     sumtp = sumtp + this.hist[i];\n\t }\n\n    this.avgtp = sumtp / this.size;\n   \n    this.tp = tp;\n\n    var sum = 0.0;\n    // calculate tps\n    for (var i = 0; i < this.size; i++) {\n        \n        var z = (this.hist[i] - this.avgtp);\n        if (z < 0) z = z * -1.0;\n        sum = sum + z;\n\n    }\n\n    this.mean = (sum / this.size);\n    \n\n\n    this.result = (this.tp - this.avgtp) / (this.constant * this.mean);\n\n    // log.debug(\"===\\t\", this.mean, \"\\t\", this.tp, '\\t', this.TP.result, \"\\t\", sum, \"\\t\", avgtp, '\\t', this.result.toFixed(2));\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/DEMA.js",
    "content": "// required indicators\nvar EMA = require('./EMA.js');\n\nvar Indicator = function(config) {\n  this.input = 'price';\n  this.result = false;\n  this.inner = new EMA(config.weight);\n  this.outer = new EMA(config.weight);\n}\n\n// add a price and calculate the EMAs and\n// the result\nIndicator.prototype.update = function(price) {\n  this.inner.update(price);\n  this.outer.update(this.inner.result);\n  this.result = 2 * this.inner.result - this.outer.result;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/EMA.js",
    "content": "﻿// @link http://en.wikipedia.org/wiki/Exponential_moving_average#Exponential_moving_average\n\nvar Indicator = function(weight) {\n  this.input = 'price';\n  this.weight = weight;\n  this.result = false;\n  this.age = 0;\n}\n\nIndicator.prototype.update = function(price) {\n  // The first time we can't calculate based on previous\n  // ema, because we haven't calculated any yet.\n  if(this.result === false)\n    this.result = price;\n\n  this.age++;\n  this.calculate(price);\n\n  return this.result;\n}\n\n//    calculation (based on tick/day):\n//  EMA = Price(t) * k + EMA(y) * (1 – k)\n//  t = today, y = yesterday, N = number of days in EMA, k = 2 / (N+1)\nIndicator.prototype.calculate = function(price) {\n  // weight factor\n  var k = 2 / (this.weight + 1);\n\n  // yesterday\n  var y = this.result;\n  \n  // calculation\n  this.result = price * k + y * (1 - k);\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/LRC.js",
    "content": "/*\n * Linear regression curve\n */\nvar log = require('../../core/log');\n\nvar Indicator = function(settings) {\n  this.input = 'price';\n  this.depth = settings;\n  this.result = false;\n  this.age = 0;\n  this.history = [];\n  this.x = [];\n  /*\n   * Do not use array(depth) as it might not be implemented\n   */\n  for (var i = 0; i < this.depth; i++) {\n      this.history.push(0.0);\n      this.x.push(i);\n  }\n\n  // log.debug(\"Created LRC indicator with h: \", this.depth);\n}\n\nIndicator.prototype.update = function(price) {\n  \n  // We need sufficient history to get the right result. \n  if(this.result === false && this.age < this.depth) {\n\n    this.history[this.age] = price;\n    this.age++;\n    this.result = false;\n     // log.debug(\"Waiting for sufficient age: \", this.age, \" out of \", this.depth); \n    //\n    return;\n  }\n\n  this.age++;\n  // shift history\n  for (var i = 0; i < (this.depth - 1); i++) {\n      this.history[i] = this.history[i+1];\n  }\n  this.history[this.depth-1] = price;\n\n  this.calculate(price);\n\n\n  // log.debug(\"Checking LRC: \", this.result.toFixed(8), \"\\tH: \", this.age);\n  return;\n}\n\n/*\n * Least squares linear regression fitting.\n */\nfunction linreg(values_x, values_y) {\n    var sum_x = 0;\n    var sum_y = 0;\n    var sum_xy = 0;\n    var sum_xx = 0;\n    var count = 0;\n\n    /*\n     * We'll use those variables for faster read/write access.\n     */\n    var x = 0;\n    var y = 0;\n    var values_length = values_x.length;\n\n    if (values_length != values_y.length) {\n        throw new Error('The parameters values_x and values_y need to have same size!');\n    }\n\n    /*\n     * Nothing to do.\n     */\n    if (values_length === 0) {\n        return [ [], [] ];\n    }\n\n    /*\n     * Calculate the sum for each of the parts necessary.\n     */\n    for (var v = 0; v < values_length; v++) {\n        x = values_x[v];\n        y = values_y[v];\n        sum_x += x;\n        sum_y += y;\n        sum_xx += x*x;\n        sum_xy += x*y;\n        count++;\n    }\n\n    /*\n     * Calculate m and b for the formular:\n     * y = x * m + b\n     */\n    var m = (count*sum_xy - sum_x*sum_y) / (count*sum_xx - sum_x*sum_x);\n    var b = (sum_y/count) - (m*sum_x)/count;\n\n    return [m, b];\n}\n\n\n/*\n * Handle calculations\n */\nIndicator.prototype.calculate = function(price) {\n\n    // get the reg\n    var reg = linreg(this.x, this.history);\n\n    // y = a * x + b\n    this.result = ((this.depth-1) * reg[0]) + reg[1];\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/MACD.js",
    "content": "// required indicators\nvar EMA = require('./EMA.js');\n\nvar Indicator = function(config) {\n  this.input = 'price';\n  this.diff = false;\n  this.short = new EMA(config.short);\n  this.long = new EMA(config.long);\n  this.signal = new EMA(config.signal);\n}\n\nIndicator.prototype.update = function(price) {\n  this.short.update(price);\n  this.long.update(price);\n  this.calculateEMAdiff();\n  this.signal.update(this.diff);\n  this.result = this.diff - this.signal.result;\n}\n\nIndicator.prototype.calculateEMAdiff = function() {\n  var shortEMA = this.short.result;\n  var longEMA = this.long.result;\n\n  this.diff = shortEMA - longEMA;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/PPO.js",
    "content": "// required indicators\nvar EMA = require('./EMA.js');\n\nvar Indicator = function(config) {\n  this.result = {};\n  this.input = 'price';\n  this.macd = 0;\n  this.ppo = 0;\n  this.short = new EMA(config.short);\n  this.long = new EMA(config.long);\n  this.MACDsignal = new EMA(config.signal);\n  this.PPOsignal = new EMA(config.signal);\n}\n\nIndicator.prototype.update = function(price) {\n  this.short.update(price);\n  this.long.update(price);\n  this.calculatePPO();\n  this.MACDsignal.update(this.result.macd);\n  this.MACDhist = this.result.macd - this.MACDsignal.result;\n  this.PPOsignal.update(this.result.ppo);\n  this.PPOhist = this.result.ppo - this.PPOsignal.result;\n\n  this.result.MACDsignal = this.MACDsignal.result;\n  this.result.MACDhist = this.MACDhist;\n  this.result.PPOsignal = this.PPOsignal.result;\n  this.result.PPOhist = this.PPOhist;\n}\n\nIndicator.prototype.calculatePPO = function() {\n  this.result.shortEMA = this.short.result;\n  this.result.longEMA = this.long.result;\n  this.result.macd = this.result.shortEMA - this.result.longEMA;\n  this.result.ppo = 100 * (this.result.macd / this.result.longEMA);\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/RSI.js",
    "content": "// required indicators\nvar SMMA = require('./SMMA.js');\n\nvar Indicator = function (settings) {\n  this.input = 'candle';\n  this.lastClose = null;\n  this.weight = settings.interval;\n  this.avgU = new SMMA(this.weight);\n  this.avgD = new SMMA(this.weight);\n  this.u = 0;\n  this.d = 0;\n  this.rs = 0;\n  this.result = 0;\n  this.age = 0;\n}\n\nIndicator.prototype.update = function (candle) {\n  var currentClose = candle.close;\n\n  if (this.lastClose === null) {\n    // Set initial price to prevent invalid change calculation\n    this.lastClose = currentClose;\n\n    // Do not calculate RSI for this reason - there's no change!\n    this.age++;\n    return;\n  }\n\n  if (currentClose > this.lastClose) {\n    this.u = currentClose - this.lastClose;\n    this.d = 0;\n  } else {\n    this.u = 0;\n    this.d = this.lastClose - currentClose;\n  }\n\n  this.avgU.update(this.u);\n  this.avgD.update(this.d);\n\n  this.rs = this.avgU.result / this.avgD.result;\n  this.result = 100 - (100 / (1 + this.rs));\n\n  if (this.avgD.result === 0 && this.avgU.result !== 0) {\n    this.result = 100;\n  } else if (this.avgD.result === 0) {\n    this.result = 0;\n  }\n\n  this.lastClose = currentClose;\n  this.age++;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/SMA.js",
    "content": "// required indicators\n// Simple Moving Average - O(1) implementation \n\nvar Indicator = function(windowLength) {\n  this.input = 'price';\n  this.windowLength = windowLength;\n  this.prices = [];\n  this.result = 0;\n  this.age = 0;\n  this.sum = 0;\n}\n\nIndicator.prototype.update = function(price) {\n  var tail = this.prices[this.age] || 0; // oldest price in window\n  this.prices[this.age] = price;\n  this.sum += price - tail;\n  this.result = this.sum / this.prices.length;\n  this.age = (this.age + 1) % this.windowLength\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/SMMA.js",
    "content": "// required indicators\nvar SMA = require('./SMA');\n\nvar Indicator = function (weight) {\n  this.input = 'price';\n  this.sma = new SMA(weight);\n  this.weight = weight;\n  this.prices = [];\n  this.result = 0;\n  this.age = 0;\n}\n\nIndicator.prototype.update = function (price) {\n  this.prices[this.age] = price;\n\n  if(this.prices.length < this.weight) {\n    this.sma.update(price);\n  } else if(this.prices.length === this.weight) {\n    this.sma.update(price);\n    this.result = this.sma.result;\n  } else {\n    this.result = (this.result * (this.weight - 1) + price) / this.weight;\n  }\n\n  this.age++;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/TSI.js",
    "content": "// required indicators\nvar EMA = require('./EMA.js');\n\nvar Indicator = function(settings) {\n  this.input = 'candle';\n  this.lastClose = null;\n  this.tsi = 0;\n  this.inner = new EMA(settings.long);\n  this.outer = new EMA(settings.short);\n  this.absoluteInner = new EMA(settings.long);\n  this.absoluteOuter = new EMA(settings.short);\n}\n\nIndicator.prototype.update = function(candle) {\n  var close = candle.close;\n  var prevClose = this.lastClose;\n  \n  if (prevClose === null) {\n    // Set initial price to prevent invalid change calculation\n    this.lastClose = close;\n    // Do not calculate TSI on first close\n    return;\n  }\n  \n  var momentum = close - prevClose;\n\n  this.inner.update(momentum);\n  this.outer.update(this.inner.result);\n\n  this.absoluteInner.update(Math.abs(momentum));\n  this.absoluteOuter.update(this.absoluteInner.result);\n\n  this.tsi = 100 * this.outer.result / this.absoluteOuter.result;\n\n  this.lastClose = close;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/indicators/UO.js",
    "content": "// required indicators\nvar SMA = require('./SMA.js');\n\nvar Indicator = function(settings) {\n  this.input = 'candle';\n  this.lastClose = 0;\n  this.uo = 0;\n  this.firstWeight = settings.first.weight;\n  this.secondWeight = settings.second.weight;\n  this.thirdWeight = settings.third.weight;\n  this.firstLow = new SMA(settings.first.period);\n  this.firstHigh = new SMA(settings.first.period);\n  this.secondLow = new SMA(settings.second.period);\n  this.secondHigh = new SMA(settings.second.period);\n  this.thirdLow = new SMA(settings.third.period);\n  this.thirdHigh = new SMA(settings.third.period);\n}\n\nIndicator.prototype.update = function(candle) {\n  var close = candle.close;\n  var prevClose = this.lastClose;\n  var low = candle.low;\n  var high = candle.high;\n\n  var bp = close - Math.min(low, prevClose);\n  var tr = Math.max(high, prevClose) - Math.min(low, prevClose);\n\n  this.firstLow.update(tr);\n  this.secondLow.update(tr);\n  this.thirdLow.update(tr);\n\n  this.firstHigh.update(bp);\n  this.secondHigh.update(bp);\n  this.thirdHigh.update(bp);\n\n  var first = this.firstHigh.result / this.firstLow.result;\n  var second = this.secondHigh.result / this.secondLow.result;\n  var third = this.thirdHigh.result / this.thirdLow.result;\n\n  this.uo = 100 * (this.firstWeight * first + this.secondWeight * second + this.thirdWeight * third) / (this.firstWeight + this.secondWeight + this.thirdWeight);\n\n  this.lastClose = close;\n}\n\nmodule.exports = Indicator;\n"
  },
  {
    "path": "strategies/noop.js",
    "content": "// This method is a noop (it doesn't do anything)\n\nvar _ = require('lodash');\n\n// Let's create our own method\nvar method = {};\n\nmethod.init = _.noop;\nmethod.update = _.noop;\nmethod.log = _.noop;\nmethod.check = _.noop;\n\nmodule.exports = method;"
  },
  {
    "path": "strategies/talib-macd.js",
    "content": "// If you want to use your own trading methods you can\n// write them here. For more information on everything you\n// can use please refer to this document:\n//\n// https://github.com/askmike/gekko/blob/stable/docs/trading_methods.md\n\n// Let's create our own method\nvar method = {};\n\n// Prepare everything our method needs\nmethod.init = function() {\n  this.name = 'talib-macd'\n  this.input = 'candle';\n  // keep state about the current trend\n  // here, on every new candle we use this\n  // state object to check if we need to\n  // report it.\n  this.trend = 'none';\n\n  // how many candles do we need as a base\n  // before we can start giving advice?\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  var customMACDSettings = this.settings.parameters;\n\n  // define the indicators we need\n  this.addTalibIndicator('mymacd', 'macd', customMACDSettings);\n}\n\n// What happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n\nmethod.log = function() {\n  // nothing!\n}\n\n// Based on the newly calculated\n// information, check if we should\n// update or not.\nmethod.check = function(candle) {\n  var price = candle.close;\n  var result = this.talibIndicators.mymacd.result;\n  var macddiff = result['outMACD'] - result['outMACDSignal'];\n\n  if(this.settings.thresholds.down > macddiff && this.trend !== 'short') {\n    this.trend = 'short';\n    this.advice('short');\n\n  } else if(this.settings.thresholds.up < macddiff && this.trend !== 'long'){\n    this.trend = 'long';\n    this.advice('long');\n\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/tulip-adx.js",
    "content": "var method = {};\n// Prepare everything our method needs\nmethod.init = function() {\n  this.name = 'tulip-adx'\n  this.trend = 'none';\n  this.requiredHistory = this.tradingAdvisor.historySize;\n  this.addTulipIndicator('myadx', 'adx', this.settings);\n}\n// What happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\nmethod.log = function() {\n  // nothing!\n}\nmethod.check = function(candle) {\n  var price = candle.close;\n  var adx = this.tulipIndicators.myadx.result.result;\n  // console.dir(adx)\n\n  if(this.settings.thresholds.down > adx && this.trend !== 'short') {\n    this.trend = 'short';\n    this.advice('short');\n  } else if(this.settings.thresholds.up < adx && this.trend !== 'long'){\n    this.trend = 'long';\n    this.advice('long');\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/tulip-macd.js",
    "content": "// If you want to use your own trading methods you can\n// write them here. For more information on everything you\n// can use please refer to this document:\n//\n// https://github.com/askmike/gekko/blob/stable/docs/trading_methods.md\n\n// Let's create our own method\nvar method = {};\n\n// Prepare everything our method needs\nmethod.init = function() {\n  this.name = 'tulip-macd'\n  // keep state about the current trend\n  // here, on every new candle we use this\n  // state object to check if we need to\n  // report it.\n  this.trend = 'none';\n\n  // how many candles do we need as a base\n  // before we can start giving advice?\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  var customMACDSettings = this.settings.parameters;\n\n  // define the indicators we need\n  this.addTulipIndicator('mymacd', 'macd', customMACDSettings);\n}\n\n// What happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n\nmethod.log = function() {\n  // nothing!\n}\n\n// Based on the newly calculated\n// information, check if we should\n// update or not.\nmethod.check = function(candle) {\n  var price = candle.close;\n  var result = this.tulipIndicators.mymacd.result;\n  var macddiff = result['macd'] - result['macdSignal'];\n\n  if(this.settings.thresholds.down > macddiff && this.trend !== 'short') {\n    this.trend = 'short';\n    this.advice('short');\n\n  } else if(this.settings.thresholds.up < macddiff && this.trend !== 'long'){\n    this.trend = 'long';\n    this.advice('long');\n\n  }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/tulip-multi-strat.js",
    "content": "var _ = require('lodash');\nvar log = require('../core/log.js');\n\nvar method = {};\nmethod.init = function() {\n    // strat name\n    this.name = 'tulip-multi-strat';\n    // trend information\n    this.trend = 'none'\n    // tulip indicators use this sometimes\n    this.requiredHistory = this.settings.historySize;\n    // define the indicators we need\n    this.addTulipIndicator('myadx', 'adx', this.settings);\n    this.addTulipIndicator('mymacd', 'macd', this.settings);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n    // tulip results\n    this.adx = this.tulipIndicators.myadx.result.result;\n    this.macd = this.tulipIndicators.mymacd.result.macdHistogram;\n}\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function() {\n    log.debug(\n`---------------------\nTulip ADX: ${this.adx}\nTulip MACD: ${this.macd}\n`);\n}\n\nmethod.check = function() {\n    // just add a long and short to each array when new indicators are used\n    const all_long = [\n        this.adx > this.settings.up && this.trend!=='long',\n        this.settings.macd_up < this.macd && this.trend!=='long',\n    ].reduce((total, long)=>long && total, true)\n    const all_short = [\n        this.adx < this.settings.down && this.trend!=='short',\n        this.settings.macd_down > this.macd && this.trend!=='short',\n    ].reduce((total, long)=>long && total, true)\n\n    // combining all indicators with AND\n    if(all_long){\n        log.debug(`tulip-multi-strat In low`);\n        this.advice('long');\n    }else if(all_short){\n        log.debug(`tulip-multi-strat In high`);\n        this.advice('short');\n    }else{\n        log.debug(`tulip-multi-strat In no trend`);\n        this.advice();\n    }\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "strategies/varPPO.js",
    "content": "// helpers\nvar _ = require('lodash');\nvar log = require('../core/log');\n\n// configuration\nvar config = require('../core/util').getConfig();\nvar settings = config.varPPO;\nvar momentum = settings.momentum;\nvar momentumName = momentum.toLowerCase();\nvar momentumSettings = config[momentum];\n\n// let's create our own method\nvar method = {};\n\n// prepare everything our method needs\nmethod.init = function() {\n  this.trend = {\n   direction: 'none',\n   duration: 0,\n   persisted: false,\n   adviced: false\n  };\n\n  this.requiredHistory = this.tradingAdvisor.historySize;\n\n  // define the indicators we need\n  this.addIndicator('ppo', 'PPO', config.PPO);\n  this.addIndicator(momentumName, momentum, momentumSettings);\n}\n\n// what happens on every new candle?\nmethod.update = function(candle) {\n  // nothing!\n}\n\n// for debugging purposes log the last\n// calculated parameters.\nmethod.log = function(candle) {\n  var digits = 8;\n  var ppo = this.indicators.ppo.result;\n  var result = ppo.ppo;\n  var signal = ppo.PPOsignal;\n  var hist = ppo.PPOhist;\n  var momentumResult = this.indicators[momentumName][momentumName];\n\n  log.debug('\\t', 'PPO:', result.toFixed(digits));\n  log.debug('\\t', 'PPOsignal:', signal.toFixed(digits));\n  log.debug('\\t', 'PPOhist:', hist.toFixed(digits));\n  log.debug('\\t', momentum + ':', momentumResult.toFixed(digits));\n  log.debug('\\t', 'price:', candle.close.toFixed(digits));\n}\n\nmethod.check = function() {\n  var ppo = this.indicators.ppo.result;\n  var hist = ppo.PPOhist;\n\n  var value = this.indicators[momentumName][momentumName];\n\n  var thresholds = {\n    low: momentumSettings.thresholds.low + hist * settings.thresholds.weightLow,\n    high: momentumSettings.thresholds.high + hist * settings.thresholds.weightHigh\n  };\n\n  if(value < thresholds.low) {\n\n    // new trend detected\n    if(this.trend.direction !== 'up')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'up',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In uptrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('long');\n    } else\n      this.advice();\n\n  } else if(value > thresholds.high) {\n\n    // new trend detected\n    if(this.trend.direction !== 'down')\n      this.trend = {\n        duration: 0,\n        persisted: false,\n        direction: 'down',\n        adviced: false\n      };\n\n    this.trend.duration++;\n\n    log.debug('In downtrend since', this.trend.duration, 'candle(s)');\n\n    if(this.trend.duration >= settings.thresholds.persistence)\n      this.trend.persisted = true;\n\n    if(this.trend.persisted && !this.trend.adviced) {\n      this.trend.adviced = true;\n      this.advice('short');\n    } else\n      this.advice();\n\n\n  } else {\n\n    log.debug('In no trend');\n\n    // we're not in an up nor in a downtrend\n    // but for now we ignore sideways trends\n    //\n    // read more @link:\n    //\n    // https://github.com/askmike/gekko/issues/171\n\n    // this.trend = {\n    //   direction: 'none',\n    //   duration: 0,\n    //   persisted: false,\n    //   adviced: false\n    // };\n\n    this.advice();\n  }\n\n}\n\nmodule.exports = method;\n"
  },
  {
    "path": "subscriptions.js",
    "content": "// \n// Subscriptions glue plugins to events\n// flowing through the Gekko.\n// \n\nvar subscriptions = [\n  {\n    emitter: 'market',\n    event: 'candle',\n    handler: 'processCandle'\n  },\n  {\n    emitter: 'market',\n    event: 'marketUpdate',\n    handler: 'processMarketUpdate'\n  },\n  {\n    emitter: 'market',\n    event: 'marketStart',\n    handler: 'processMarketStart'\n  },\n  {\n    emitter: 'tradingAdvisor',\n    event: 'stratWarmupCompleted',\n    handler: 'processStratWarmupCompleted'\n  },\n  {\n    emitter: 'tradingAdvisor',\n    event: 'advice',\n    handler: 'processAdvice'\n  },\n  {\n    emitter: 'tradingAdvisor',\n    event: 'stratCandle',\n    handler: 'processStratCandle'\n  },\n  {\n    emitter: 'tradingAdvisor',\n    event: 'stratUpdate',\n    handler: 'processStratUpdate'\n  },\n  {\n    emitter: 'tradingAdvisor',\n    event: 'stratNotification',\n    handler: 'processStratNotification'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'tradeInitiated',\n    handler: 'processTradeInitiated'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'tradeAborted',\n    handler: 'processTradeAborted'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'tradeCompleted',\n    handler: 'processTradeCompleted'\n  },\n  {\n    emitter: 'trader',\n    event: 'tradeCancelled',\n    handler: 'processTradeCancelled'\n  },\n  {\n    emitter: 'trader',\n    event: 'tradeErrored',\n    handler: 'processTradeErrored'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'portfolioChange',\n    handler: 'processPortfolioChange'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'triggerCreated',\n    handler: 'processTriggerCreated'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'triggerAborted',\n    handler: 'processTriggerAborted'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'triggerFired',\n    handler: 'processTriggerFired'\n  },\n  {\n    emitter: ['trader', 'paperTrader'],\n    event: 'portfolioValueChange',\n    handler: 'processPortfolioValueChange'\n  },\n  {\n    emitter: 'performanceAnalyzer',\n    event: 'performanceReport',\n    handler: 'processPerformanceReport'\n  },\n  {\n    emitter: 'performanceAnalyzer',\n    event: 'roundtripUpdate',\n    handler: 'processRoundtripUpdate'\n  },\n  {\n    emitter: 'performanceAnalyzer',\n    event: 'roundtrip',\n    handler: 'processRoundtrip'\n  },\n];\n\nmodule.exports = subscriptions;"
  },
  {
    "path": "test/_prepare.js",
    "content": "// overwrite config with test-config\n\nvar utils = require(__dirname + '/../core/util');\nvar testConfig = require(__dirname + '/test-config.json');\nutils.setConfig(testConfig);"
  },
  {
    "path": "test/candleBatcher.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nvar utils = require(__dirname + '/../core/util');\n\nvar dirs = utils.dirs();\nvar CandleBatcher = require(dirs.core + 'candleBatcher');\n\nvar candles = [\n  {id: 1, \"start\":moment(\"2015-02-14T23:57:00.000Z\"),\"open\":257.19,\"high\":257.19,\"low\":257.18,\"close\":257.18,\"vwp\":257.18559990418294,\"volume\":0.97206065,\"trades\":2},\n  {id: 2, \"start\":moment(\"2015-02-14T23:58:00.000Z\"),\"open\":257.02,\"high\":257.02,\"low\":256.98,\"close\":256.98,\"vwp\":257.0175849772836,\"volume\":4.1407478,\"trades\":2},\n  {id: 3, \"start\":moment(\"2015-02-14T23:59:00.000Z\"),\"open\":256.85,\"high\":256.99,\"low\":256.85,\"close\":256.99,\"vwp\":256.9376998467,\"volume\":6,\"trades\":6},\n  {id: 4, \"start\":moment(\"2015-02-15T00:00:00.000Z\"),\"open\":256.81,\"high\":256.82,\"low\":256.81,\"close\":256.82,\"vwp\":256.815,\"volume\":4,\"trades\":2},\n  {id: 5, \"start\":moment(\"2015-02-15T00:01:00.000Z\"),\"open\":256.81,\"high\":257.02,\"low\":256.81,\"close\":257.01,\"vwp\":256.94666666666666,\"volume\":6,\"trades\":3},\n  {id: 6, \"start\":moment(\"2015-02-15T00:02:00.000Z\"),\"open\":257.03,\"high\":257.03,\"low\":256.33,\"close\":256.33,\"vwp\":256.74257263558013,\"volume\":6.7551178,\"trades\":6},\n  {id: 7, \"start\":moment(\"2015-02-15T00:03:00.000Z\"),\"open\":257.02,\"high\":257.47,\"low\":257.02,\"close\":257.47,\"vwp\":257.26466004728906,\"volume\":3.7384995300000003,\"trades\":3},\n  {id: 8, \"start\":moment(\"2015-02-15T00:04:00.000Z\"),\"open\":257.47,\"high\":257.48,\"low\":257.37,\"close\":257.38,\"vwp\":257.4277429116875,\"volume\":8,\"trades\":6},\n  {id: 9, \"start\":moment(\"2015-02-15T00:05:00.000Z\"),\"open\":257.38,\"high\":257.45,\"low\":257.38,\"close\":257.45,\"vwp\":257.3975644932184,\"volume\":7.97062564,\"trades\":4},\n  {id: 10, \"start\":moment(\"2015-02-15T00:06:00.000Z\"),\"open\":257.46,\"high\":257.48,\"low\":257.46,\"close\":257.48,\"vwp\":257.47333333333336,\"volume\":7.5,\"trades\":4}\n];\n\ndescribe('core/candleBatcher', function() {\n  var cb;\n\n  it('should throw when not passed a number', function() {\n    expect(function() {\n      new CandleBatcher();\n    }).to.throw('candleSize is not a number');\n  });\n\n  it('should instantiate', function() {\n    cb = new CandleBatcher(2);\n  });\n\n  it('should throw when fed a candle', function() {\n    var candle = _.first(candles);\n    expect(\n      cb.write.bind(cb, candle)\n    ).to.throw('candles is not an array');\n  });\n\n  it('should not emit an event when fed not enough candles', function() {\n    var candle = _.first(candles);\n\n    var spy = sinon.spy();\n    cb.on('candle', spy);\n    cb.write( [candle] );\n    expect(spy.called).to.be.false;\n  });\n\n  it('should not emit an event when not flushed', function() {\n    cb = new CandleBatcher(2);\n\n    var spy = sinon.spy();\n    cb.on('candle', spy);\n    cb.write( candles );\n    expect(spy.called).to.be.false;\n  });\n\n  it('should emit 5 events when fed 10 candles', function() {\n    cb = new CandleBatcher(2);\n\n    var spy = sinon.spy();\n    cb.on('candle', spy);\n    cb.write( candles );\n    cb.flush();\n    expect(spy.callCount).to.equal(5);\n  });\n\n  it('should correctly add two candles together', function() {\n    cb = new CandleBatcher(2);\n    var _candles = _.first(candles, 2);\n    var first = _.first(_candles);\n    var second = _.last(_candles);\n\n    var result = {\n      start: first.start,\n      open: first.open,\n      high: _.max([first.high, second.high]),\n      low: _.min([first.low, second.low]),\n      close: second.close,\n      volume: first.volume + second.volume,\n      vwp: (first.vwp * first.volume) + (second.vwp * second.volume),\n      trades: first.trades + second.trades\n    };\n\n    result.vwp /= result.volume;\n\n    var spy = sinon.spy();\n    cb.on('candle', spy);\n    cb.write( _candles );\n    cb.flush();\n\n    var cbResult = _.first(_.first(spy.args));\n    expect(cbResult).to.deep.equal(result);\n    expect(cbResult.id).to.equal(undefined);\n  });\n\n});"
  },
  {
    "path": "test/exchanges/bitstamp.js",
    "content": "\n// if you need to test Gekko against real mocked data\n// uncomment the following:\n\n// var fs = require('fs');\n// var bitstamp = require('bitstamp');\n// var bs = new bitstamp;\n// bs.transactions('btcusd', (err, data) => {\n//   if(err)\n//     throw err;\n\n//   var json = JSON.stringify(data, null, 4);\n//   fs.writeFileSync('./data/bitstamp_trades.json', json);\n// });\n// return;\n\nvar chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\nvar proxyquire = require('proxyquire');\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nvar util = require(__dirname + '/../../core/util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\n\nvar TRADES = require('./data/bitstamp_trades.json');\n\nreturn; // TEMP\n\nvar FakeExchange = function() {};\nFakeExchange.prototype = {\n  transactions: function(since, handler, descending) {\n    handler(\n      null,\n      TRADES\n    );\n  }\n}\nvar transactionsSpy = sinon.spy(FakeExchange.prototype, 'transactions');\nspoofer = {\n  bitstamp: FakeExchange\n}\n\ndescribe('exchanges/bitstamp', function() {\n  var Bitstamp = proxyquire(dirs.gekko + 'exchange/wrappers/bitstamp', spoofer);\n  var bs;\n\n  it('should instantiate', function() {\n    bs = new Bitstamp(config.watch);\n  });\n\n  it('should correctly fetch historical trades', function() {\n    bs.getTrades(null, _.noop, false);\n\n    expect(transactionsSpy.callCount).to.equal(1);\n\n    var args = transactionsSpy.lastCall.args;\n    expect(args.length).to.equal(2);\n\n    expect(args[0]).to.equal('btcusd');\n  });\n\n  it('should retry on exchange error', function() {\n    var ErrorFakeExchange = function() {};\n    ErrorFakeExchange.prototype = {\n      transactions: function(since, handler, descending) {\n        handler('Auth error');\n      }\n    }\n    spoofer = {\n      bitstamp: ErrorFakeExchange\n    }\n\n    var ErroringBitstamp = proxyquire(dirs.exchanges + 'bitstamp', spoofer);\n    var ebs = new ErroringBitstamp(config.watch);\n\n    ebs.retry = _.noop;\n    var retrySpy = sinon.spy(ebs, 'retry');\n\n    ebs.getTrades(null, _.noop)\n\n    expect(retrySpy.callCount).to.equal(1);\n\n    var args = retrySpy.lastCall.args;\n    expect(args[1].length).to.equal(2);\n    expect(args[1][0]).to.equal(null);\n  })\n\n  it('should correctly parse historical trades', function(done) {\n    var check = function(err, trades) {\n\n      expect(err).to.equal(null);\n\n      expect(trades.length).to.equal(TRADES.length);\n\n      var oldest = _.first(trades);\n      var OLDEST = _.last(TRADES);\n\n      expect(oldest.tid).to.equal(+OLDEST.tid);\n      expect(oldest.price).to.equal(+OLDEST.price);\n      expect(oldest.amount).to.equal(+OLDEST.amount);\n      expect(oldest.date).to.equal(OLDEST.date);\n\n      done();\n    }\n\n    bs.getTrades(null, check, false);\n\n  });\n});"
  },
  {
    "path": "test/exchanges/data/bitstamp_trades.json",
    "content": "[\n    {\n        \"date\": \"1476099635\",\n        \"tid\": \"12166560\",\n        \"price\": \"612.91000\",\n        \"type\": \"1\",\n        \"amount\": \"0.05563331\"\n    },\n    {\n        \"date\": \"1476099613\",\n        \"tid\": \"12166552\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.65581425\"\n    },\n    {\n        \"date\": \"1476099574\",\n        \"tid\": \"12166551\",\n        \"price\": \"612.91000\",\n        \"type\": \"1\",\n        \"amount\": \"0.08348263\"\n    },\n    {\n        \"date\": \"1476099544\",\n        \"tid\": \"12166550\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.05827100\"\n    },\n    {\n        \"date\": \"1476099523\",\n        \"tid\": \"12166548\",\n        \"price\": \"612.91000\",\n        \"type\": \"1\",\n        \"amount\": \"0.05563382\"\n    },\n    {\n        \"date\": \"1476099355\",\n        \"tid\": \"12166542\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.81406708\"\n    },\n    {\n        \"date\": \"1476099246\",\n        \"tid\": \"12166541\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02000000\"\n    },\n    {\n        \"date\": \"1476099156\",\n        \"tid\": \"12166539\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.39384817\"\n    },\n    {\n        \"date\": \"1476099154\",\n        \"tid\": \"12166538\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"0.48832321\"\n    },\n    {\n        \"date\": \"1476099137\",\n        \"tid\": \"12166537\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02000000\"\n    },\n    {\n        \"date\": \"1476099099\",\n        \"tid\": \"12166534\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02300000\"\n    },\n    {\n        \"date\": \"1476099067\",\n        \"tid\": \"12166525\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"0.07519000\"\n    },\n    {\n        \"date\": \"1476099058\",\n        \"tid\": \"12166524\",\n        \"price\": \"612.76000\",\n        \"type\": \"1\",\n        \"amount\": \"0.03708453\"\n    },\n    {\n        \"date\": \"1476099045\",\n        \"tid\": \"12166523\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"0.06303310\"\n    },\n    {\n        \"date\": \"1476098972\",\n        \"tid\": \"12166519\",\n        \"price\": \"614.15000\",\n        \"type\": \"1\",\n        \"amount\": \"0.11617019\"\n    },\n    {\n        \"date\": \"1476098971\",\n        \"tid\": \"12166518\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02300000\"\n    },\n    {\n        \"date\": \"1476098943\",\n        \"tid\": \"12166517\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.28252528\"\n    },\n    {\n        \"date\": \"1476098748\",\n        \"tid\": \"12166497\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.07519000\"\n    },\n    {\n        \"date\": \"1476098707\",\n        \"tid\": \"12166490\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.12971692\"\n    },\n    {\n        \"date\": \"1476098707\",\n        \"tid\": \"12166489\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.06289098\"\n    },\n    {\n        \"date\": \"1476098616\",\n        \"tid\": \"12166487\",\n        \"price\": \"612.73000\",\n        \"type\": \"1\",\n        \"amount\": \"0.47650000\"\n    },\n    {\n        \"date\": \"1476098550\",\n        \"tid\": \"12166482\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.04296970\"\n    },\n    {\n        \"date\": \"1476098544\",\n        \"tid\": \"12166480\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.05113932\"\n    },\n    {\n        \"date\": \"1476098544\",\n        \"tid\": \"12166477\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.09140786\"\n    },\n    {\n        \"date\": \"1476098538\",\n        \"tid\": \"12166474\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.06517154\"\n    },\n    {\n        \"date\": \"1476098538\",\n        \"tid\": \"12166473\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.07737564\"\n    },\n    {\n        \"date\": \"1476098532\",\n        \"tid\": \"12166470\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.14254718\"\n    },\n    {\n        \"date\": \"1476098526\",\n        \"tid\": \"12166466\",\n        \"price\": \"612.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.14254718\"\n    },\n    {\n        \"date\": \"1476098488\",\n        \"tid\": \"12166463\",\n        \"price\": \"612.97000\",\n        \"type\": \"1\",\n        \"amount\": \"0.12971692\"\n    },\n    {\n        \"date\": \"1476098488\",\n        \"tid\": \"12166462\",\n        \"price\": \"612.97000\",\n        \"type\": \"1\",\n        \"amount\": \"0.15700000\"\n    },\n    {\n        \"date\": \"1476098488\",\n        \"tid\": \"12166461\",\n        \"price\": \"612.97000\",\n        \"type\": \"1\",\n        \"amount\": \"0.13047962\"\n    },\n    {\n        \"date\": \"1476098477\",\n        \"tid\": \"12166460\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02701517\"\n    },\n    {\n        \"date\": \"1476098476\",\n        \"tid\": \"12166458\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.09610000\"\n    },\n    {\n        \"date\": \"1476098476\",\n        \"tid\": \"12166457\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15600000\"\n    },\n    {\n        \"date\": \"1476098476\",\n        \"tid\": \"12166456\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.07639355\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166448\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.04128385\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166447\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166446\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166445\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.17900000\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166444\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.41000000\"\n    },\n    {\n        \"date\": \"1476098403\",\n        \"tid\": \"12166443\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.05371615\"\n    },\n    {\n        \"date\": \"1476098318\",\n        \"tid\": \"12166437\",\n        \"price\": \"612.97000\",\n        \"type\": \"1\",\n        \"amount\": \"0.01652038\"\n    },\n    {\n        \"date\": \"1476098176\",\n        \"tid\": \"12166429\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15665000\"\n    },\n    {\n        \"date\": \"1476098173\",\n        \"tid\": \"12166428\",\n        \"price\": \"612.78000\",\n        \"type\": \"1\",\n        \"amount\": \"0.11767740\"\n    },\n    {\n        \"date\": \"1476098173\",\n        \"tid\": \"12166427\",\n        \"price\": \"612.78000\",\n        \"type\": \"1\",\n        \"amount\": \"0.15600000\"\n    },\n    {\n        \"date\": \"1476098172\",\n        \"tid\": \"12166426\",\n        \"price\": \"612.79000\",\n        \"type\": \"1\",\n        \"amount\": \"0.09610000\"\n    },\n    {\n        \"date\": \"1476098104\",\n        \"tid\": \"12166421\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.03001800\"\n    },\n    {\n        \"date\": \"1476098042\",\n        \"tid\": \"12166412\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.01878000\"\n    },\n    {\n        \"date\": \"1476097969\",\n        \"tid\": \"12166408\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.02000000\"\n    },\n    {\n        \"date\": \"1476097943\",\n        \"tid\": \"12166407\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.12783585\"\n    },\n    {\n        \"date\": \"1476097943\",\n        \"tid\": \"12166406\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15900000\"\n    },\n    {\n        \"date\": \"1476097943\",\n        \"tid\": \"12166405\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097942\",\n        \"tid\": \"12166404\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.49381415\"\n    },\n    {\n        \"date\": \"1476097814\",\n        \"tid\": \"12166401\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15080751\"\n    },\n    {\n        \"date\": \"1476097813\",\n        \"tid\": \"12166400\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.23230000\"\n    },\n    {\n        \"date\": \"1476097811\",\n        \"tid\": \"12166399\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.18140000\"\n    },\n    {\n        \"date\": \"1476097803\",\n        \"tid\": \"12166398\",\n        \"price\": \"612.95000\",\n        \"type\": \"1\",\n        \"amount\": \"0.16268000\"\n    },\n    {\n        \"date\": \"1476097643\",\n        \"tid\": \"12166387\",\n        \"price\": \"612.66000\",\n        \"type\": \"1\",\n        \"amount\": \"2.14279194\"\n    },\n    {\n        \"date\": \"1476097643\",\n        \"tid\": \"12166386\",\n        \"price\": \"612.99000\",\n        \"type\": \"1\",\n        \"amount\": \"2.30935500\"\n    },\n    {\n        \"date\": \"1476097643\",\n        \"tid\": \"12166385\",\n        \"price\": \"613.24000\",\n        \"type\": \"1\",\n        \"amount\": \"3.02659541\"\n    },\n    {\n        \"date\": \"1476097643\",\n        \"tid\": \"12166384\",\n        \"price\": \"613.26000\",\n        \"type\": \"1\",\n        \"amount\": \"1.05795023\"\n    },\n    {\n        \"date\": \"1476097642\",\n        \"tid\": \"12166383\",\n        \"price\": \"614.09000\",\n        \"type\": \"1\",\n        \"amount\": \"1.28080550\"\n    },\n    {\n        \"date\": \"1476097618\",\n        \"tid\": \"12166382\",\n        \"price\": \"614.20000\",\n        \"type\": \"0\",\n        \"amount\": \"0.91402550\"\n    },\n    {\n        \"date\": \"1476097617\",\n        \"tid\": \"12166381\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.28027603\"\n    },\n    {\n        \"date\": \"1476097581\",\n        \"tid\": \"12166379\",\n        \"price\": \"614.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.27632529\"\n    },\n    {\n        \"date\": \"1476097567\",\n        \"tid\": \"12166378\",\n        \"price\": \"614.09000\",\n        \"type\": \"1\",\n        \"amount\": \"0.02178692\"\n    },\n    {\n        \"date\": \"1476097540\",\n        \"tid\": \"12166375\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15700000\"\n    },\n    {\n        \"date\": \"1476097540\",\n        \"tid\": \"12166373\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097540\",\n        \"tid\": \"12166372\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097540\",\n        \"tid\": \"12166370\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097540\",\n        \"tid\": \"12166369\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097539\",\n        \"tid\": \"12166368\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.09484126\"\n    },\n    {\n        \"date\": \"1476097536\",\n        \"tid\": \"12166366\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.06315874\"\n    },\n    {\n        \"date\": \"1476097536\",\n        \"tid\": \"12166365\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.14600000\"\n    },\n    {\n        \"date\": \"1476097536\",\n        \"tid\": \"12166364\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.41000000\"\n    },\n    {\n        \"date\": \"1476097536\",\n        \"tid\": \"12166363\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40600000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166362\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40600000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166361\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40600000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166360\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40900000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166359\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40600000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166358\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166357\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097535\",\n        \"tid\": \"12166356\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15900000\"\n    },\n    {\n        \"date\": \"1476097534\",\n        \"tid\": \"12166355\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476097534\",\n        \"tid\": \"12166354\",\n        \"price\": \"614.09000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40600000\"\n    },\n    {\n        \"date\": \"1476097529\",\n        \"tid\": \"12166353\",\n        \"price\": \"613.32000\",\n        \"type\": \"1\",\n        \"amount\": \"2.90000000\"\n    },\n    {\n        \"date\": \"1476097503\",\n        \"tid\": \"12166350\",\n        \"price\": \"612.99000\",\n        \"type\": \"1\",\n        \"amount\": \"1.59260664\"\n    },\n    {\n        \"date\": \"1476097503\",\n        \"tid\": \"12166349\",\n        \"price\": \"613.06000\",\n        \"type\": \"1\",\n        \"amount\": \"0.14700000\"\n    },\n    {\n        \"date\": \"1476097502\",\n        \"tid\": \"12166348\",\n        \"price\": \"613.23000\",\n        \"type\": \"1\",\n        \"amount\": \"4.90000000\"\n    },\n    {\n        \"date\": \"1476097502\",\n        \"tid\": \"12166347\",\n        \"price\": \"613.43000\",\n        \"type\": \"1\",\n        \"amount\": \"0.15600000\"\n    },\n    {\n        \"date\": \"1476097502\",\n        \"tid\": \"12166346\",\n        \"price\": \"613.43000\",\n        \"type\": \"1\",\n        \"amount\": \"0.14700000\"\n    },\n    {\n        \"date\": \"1476097501\",\n        \"tid\": \"12166345\",\n        \"price\": \"613.55000\",\n        \"type\": \"1\",\n        \"amount\": \"0.15700000\"\n    },\n    {\n        \"date\": \"1476097501\",\n        \"tid\": \"12166344\",\n        \"price\": \"613.58000\",\n        \"type\": \"1\",\n        \"amount\": \"4.38220000\"\n    },\n    {\n        \"date\": \"1476097500\",\n        \"tid\": \"12166343\",\n        \"price\": \"614.11000\",\n        \"type\": \"1\",\n        \"amount\": \"0.48351110\"\n    },\n    {\n        \"date\": \"1476097492\",\n        \"tid\": \"12166342\",\n        \"price\": \"614.19000\",\n        \"type\": \"1\",\n        \"amount\": \"0.50000000\"\n    },\n    {\n        \"date\": \"1476097484\",\n        \"tid\": \"12166341\",\n        \"price\": \"614.20000\",\n        \"type\": \"1\",\n        \"amount\": \"31.92160000\"\n    },\n    {\n        \"date\": \"1476097484\",\n        \"tid\": \"12166340\",\n        \"price\": \"614.22000\",\n        \"type\": \"1\",\n        \"amount\": \"0.50000000\"\n    },\n    {\n        \"date\": \"1476097364\",\n        \"tid\": \"12166331\",\n        \"price\": \"614.20000\",\n        \"type\": \"1\",\n        \"amount\": \"1.95240650\"\n    },\n    {\n        \"date\": \"1476097364\",\n        \"tid\": \"12166330\",\n        \"price\": \"614.52000\",\n        \"type\": \"1\",\n        \"amount\": \"1.05521350\"\n    },\n    {\n        \"date\": \"1476097200\",\n        \"tid\": \"12166323\",\n        \"price\": \"614.76000\",\n        \"type\": \"0\",\n        \"amount\": \"0.08845994\"\n    },\n    {\n        \"date\": \"1476097171\",\n        \"tid\": \"12166321\",\n        \"price\": \"614.76000\",\n        \"type\": \"0\",\n        \"amount\": \"0.09385000\"\n    },\n    {\n        \"date\": \"1476097127\",\n        \"tid\": \"12166320\",\n        \"price\": \"614.38000\",\n        \"type\": \"1\",\n        \"amount\": \"0.02178327\"\n    },\n    {\n        \"date\": \"1476097028\",\n        \"tid\": \"12166312\",\n        \"price\": \"615.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.49433382\"\n    },\n    {\n        \"date\": \"1476097028\",\n        \"tid\": \"12166311\",\n        \"price\": \"615.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.28054507\"\n    },\n    {\n        \"date\": \"1476097027\",\n        \"tid\": \"12166310\",\n        \"price\": \"615.17000\",\n        \"type\": \"1\",\n        \"amount\": \"0.04000000\"\n    },\n    {\n        \"date\": \"1476096998\",\n        \"tid\": \"12166308\",\n        \"price\": \"614.11000\",\n        \"type\": \"1\",\n        \"amount\": \"0.01648890\"\n    },\n    {\n        \"date\": \"1476096994\",\n        \"tid\": \"12166307\",\n        \"price\": \"615.17000\",\n        \"type\": \"0\",\n        \"amount\": \"0.01732453\"\n    },\n    {\n        \"date\": \"1476096785\",\n        \"tid\": \"12166297\",\n        \"price\": \"614.15000\",\n        \"type\": \"0\",\n        \"amount\": \"4.36590263\"\n    },\n    {\n        \"date\": \"1476096782\",\n        \"tid\": \"12166295\",\n        \"price\": \"614.17000\",\n        \"type\": \"1\",\n        \"amount\": \"1.62632737\"\n    },\n    {\n        \"date\": \"1476096671\",\n        \"tid\": \"12166286\",\n        \"price\": \"615.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.77605625\"\n    },\n    {\n        \"date\": \"1476096671\",\n        \"tid\": \"12166285\",\n        \"price\": \"615.18000\",\n        \"type\": \"0\",\n        \"amount\": \"1.17641295\"\n    },\n    {\n        \"date\": \"1476096532\",\n        \"tid\": \"12166284\",\n        \"price\": \"615.18000\",\n        \"type\": \"0\",\n        \"amount\": \"0.45000000\"\n    },\n    {\n        \"date\": \"1476096518\",\n        \"tid\": \"12166283\",\n        \"price\": \"614.12000\",\n        \"type\": \"1\",\n        \"amount\": \"0.82273414\"\n    },\n    {\n        \"date\": \"1476096518\",\n        \"tid\": \"12166282\",\n        \"price\": \"614.60000\",\n        \"type\": \"1\",\n        \"amount\": \"0.39143007\"\n    },\n    {\n        \"date\": \"1476096475\",\n        \"tid\": \"12166281\",\n        \"price\": \"615.02000\",\n        \"type\": \"1\",\n        \"amount\": \"9.64860000\"\n    },\n    {\n        \"date\": \"1476096453\",\n        \"tid\": \"12166279\",\n        \"price\": \"614.99000\",\n        \"type\": \"1\",\n        \"amount\": \"4.12628026\"\n    },\n    {\n        \"date\": \"1476096450\",\n        \"tid\": \"12166278\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476096450\",\n        \"tid\": \"12166277\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476096450\",\n        \"tid\": \"12166276\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476096450\",\n        \"tid\": \"12166275\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40900000\"\n    },\n    {\n        \"date\": \"1476096450\",\n        \"tid\": \"12166274\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.30145000\"\n    },\n    {\n        \"date\": \"1476096370\",\n        \"tid\": \"12166265\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.10655000\"\n    },\n    {\n        \"date\": \"1476096370\",\n        \"tid\": \"12166264\",\n        \"price\": \"614.99000\",\n        \"type\": \"0\",\n        \"amount\": \"0.05000000\"\n    },\n    {\n        \"date\": \"1476096292\",\n        \"tid\": \"12166258\",\n        \"price\": \"615.17000\",\n        \"type\": \"0\",\n        \"amount\": \"2.13738013\"\n    },\n    {\n        \"date\": \"1476096292\",\n        \"tid\": \"12166257\",\n        \"price\": \"614.97000\",\n        \"type\": \"0\",\n        \"amount\": \"0.86261987\"\n    },\n    {\n        \"date\": \"1476096172\",\n        \"tid\": \"12166241\",\n        \"price\": \"614.97000\",\n        \"type\": \"0\",\n        \"amount\": \"3.57370278\"\n    },\n    {\n        \"date\": \"1476096171\",\n        \"tid\": \"12166240\",\n        \"price\": \"614.91000\",\n        \"type\": \"0\",\n        \"amount\": \"2.98402000\"\n    },\n    {\n        \"date\": \"1476096171\",\n        \"tid\": \"12166239\",\n        \"price\": \"614.90000\",\n        \"type\": \"0\",\n        \"amount\": \"0.24000000\"\n    },\n    {\n        \"date\": \"1476096171\",\n        \"tid\": \"12166238\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.34034948\"\n    },\n    {\n        \"date\": \"1476096170\",\n        \"tid\": \"12166237\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.11200000\"\n    },\n    {\n        \"date\": \"1476096170\",\n        \"tid\": \"12166236\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476096170\",\n        \"tid\": \"12166235\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15800000\"\n    },\n    {\n        \"date\": \"1476096170\",\n        \"tid\": \"12166234\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.15700000\"\n    },\n    {\n        \"date\": \"1476096169\",\n        \"tid\": \"12166233\",\n        \"price\": \"614.84000\",\n        \"type\": \"0\",\n        \"amount\": \"0.40800000\"\n    },\n    {\n        \"date\": \"1476096154\",\n        \"tid\": \"12166232\",\n        \"price\": \"614.70000\",\n        \"type\": \"1\",\n        \"amount\": \"0.46887000\"\n    }\n]"
  },
  {
    "path": "test/indicators/cci.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// Since there are is no CCI Indicator @ https://github.com/wuhkuh/talib,\n// the precalculated results have been calculated with Excel :D\n\nvar high = [86, 85, 90, 95, 58, 71, 84, 98, 99, 100, 91, 95, 99, 96, 96, 90, 79, 72, 91, 81, 94, 87, 60, 93, 75, 94, 75, 93, 92, 92, 99, 99, 84, 91, 27, 67, 97, 92, 89];\nvar low = [1, 5, 14, 10, 20, 10, 1, 48, 64, 0, 0, 50, 15, 0, 4, 57, 1, 11, 9, 1, 1, 10, 25, 11, 16, 50, 7, 13, 74, 71, 59, 3, 1, 1, 0, 5, 1, 60, 6];\nvar close = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/CCI', function() {\n\n  var CCI = require(INDICATOR_PATH + 'CCI');\n\n  //Had to limit the decimals because of rounding mistakes\n  var verified_cci8results = [0, 0, 0, 0, 0, 0, 0, 165.258216, 137.978495, -78.352249, 23.011844, 66.039216, 11.260054, -110.755556, 2.108795, 60.958054, -79.830149, -40.800225, -42.00627, -103.175918, -58.657244, -37.232704, 12.844037, 31.25, 101.960784, 187.096774, -82.539683, 114.047867, 147.875064, 101.075269, 88.888889, -108.039098, -43.914081, -87.872763, -113.138686, -68.525669, 43.243243, 82.481254, -29.942756];\n  var verified_cci10results = [0, 0, 0, 0, 0, 0, 0, 0, 0, -81.681682, 28.953557, 78.940028, 27.948194, -82.58317, 17.665798, 57.71725, -100.171969, -36.79078, -33.502538, -113.08642, -70.175439, -36.995092, 7.30897, -20.757021, 51.239669, 200, -99.574468, 134.51119, 166.021297, 117.174281, 100.395257, -94.147583, -33.202614, -101.396478, -115.00256, -71.976401, 27.092846, 53.157122, -49.211356];\n  var verified_cci12results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91.97995, 35.138387, -86.288416, 30.06993, 67.713787, -85.863874, -44.274809, -51.105651, -102.536873, -68.659725, -49.02507, -14.705882, -21.217712, 42.461538, 122.124711, -94.10628, 146.91745, 197.464342, 135.599506, 111.925175, -80.55041, -23.476298, -99.837574, -126.229111, -84.671533, 30.350877, 58.954584, -61.147046];\n\n  it('should correctly calculate CCI with period 8', function() {\n    var cci = new CCI({ history: 8, constant: 0.015 });\n\t_.each(close,function(p,i) {\n      cci.update({high: high[i], low: low[i] , close: close[i]});\n\t  //when i<history, cci.results returns false\n\t  if (typeof(cci.result) == 'boolean') cci.result = 0;\n\t  expect(cci.result.toFixed(6)).to.equal(verified_cci8results[i].toFixed(6));\n\t});\n  });\n\n  it('should correctly calculate CCI with period 10', function() {\n     var cci = new CCI({ history: 10, constant: 0.015 });\n\t_.each(close,function(p,i) {\n      cci.update({high: high[i], low: low[i] , close: close[i]});\n\t  if (typeof(cci.result) == 'boolean') cci.result = 0;\n\t  expect(cci.result.toFixed(6)).to.equal(verified_cci10results[i].toFixed(6));\n\t})\n  });\n\n  it('should correctly calculate CCI with period 12', function() {\n     var cci = new CCI({ history: 12, constant: 0.015 });\n\t_.each(close,function(p,i) {\n      cci.update({high: high[i], low: low[i] , close: close[i]});\n\t  if (typeof(cci.result) == 'boolean') cci.result = 0;\n\t  expect(cci.result.toFixed(6)).to.equal(verified_cci12results[i].toFixed(6));\n\t})\n  });\n});\n"
  },
  {
    "path": "test/indicators/dema.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators\n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are already compared\n// to MS Excel results, more info here:\n//\n// https://github.com/askmike/gekko/issues/161\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\n\n\ndescribe('indicators/DEMA', function() {\n\n  var DEMA = require(INDICATOR_PATH + 'DEMA');\n\n  var verified_dema10results = [81,62.157024793388416,65.1412471825695,49.61361928829999,42.570707415663364,34.597495090487996,44.47997295246192,58.6168391922143,71.4979863711489,48.963944850563,60.095241192962106,66.41965473810654,69.77997604557987,49.75572911767095,61.08641574881719,65.56112611350791,54.65374623818491,57.51231851211959,51.73955057939423,36.941596820151815,27.434153499662216,24.890025210750593,33.14097982029734,30.163817870645254,40.330715478873344,45.63811915119551,36.045947422710505,53.12735486322183,64.78921092296176,72.9995704035162,83.22304838955624,58.85287916072168,62.841348382387075,42.93804766689409,36.82301007497254,26.454331684513562,46.374329400503385,53.28360623846342,38.891184741941984];\n  \n  it('should correctly calculate DEMA with weight 10', function() {\n  let dema = new DEMA({weight: 10});\n    _.each(prices, function(p, i) {\n      dema.update(p);\n      expect(dema.result).to.equal(verified_dema10results[i]);\n    });\n  });\n});\n"
  },
  {
    "path": "test/indicators/ema.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are already compared \n// to MS Excel results, more info here:\n// \n// https://github.com/askmike/gekko/issues/161\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/EMA', function() {\n\n  var EMA = require(INDICATOR_PATH + 'EMA');\n\n  var verified_ema10results = [81,70.63636363636363,71.4297520661157,62.26070623591284,57.12239601120141,51.28196037280115,55.04887666865549,61.767262728899944,68.53685132364541,56.43924199207351,61.81392526624197,65.12048430874341,67.09857807079005,56.35338205791913,61.92549441102474,64.30267724538388,58.42946320076862,59.624106255174325,56.2379051178699,47.649195096439,41.349341442541004,38.55855208935173,41.72972443674232,39.233410902789174,43.91824528410023,46.47856432335473,41.118825355472055,50.00631165447713,56.73243680820856,62.053811933988825,68.77130067326358,56.81288236903384,59.21054012011859,48.626805552824294,44.69465908867441,38.204721072551784,47.985680877542364,51.62464799071648,43.874711992404386];\n  var verified_ema12results = [81,72.23076923076923,72.65680473372781,64.709604005462,59.98504954308323,54.602734228762735,57.27923665510693,62.620892554321244,68.2176783151949,58.030343189780304,62.33336731442949,65.05131080451726,66.73572452689922,57.69945921506857,62.20723472044264,64.17535245575915,59.2252982317962,60.11371388844294,57.173142520990176,49.761889825453224,44.10621446769119,41.320643011123316,43.57900562479665,41.182235528674084,44.84650698580115,46.87012129567789,42.27471801941975,49.61706909335518,55.368289232839,60.080860120094535,66.06842010161846,56.365586239831,58.46318835678008,49.62269784035237,46.14228278799047,40.42808543599194,48.36222613814702,51.383422116893634,44.86289563737154];\n  var verified_ema26results = [81,76.77777777777777,76.64609053497942,72.52415790275873,69.67051657662846,66.36158942280413,66.77924946555937,68.64745320885127,70.89579000819562,65.79239815573669,67.28925755160805,68.2307940292667,68.80629076783954,64.30212108133291,65.98344544567863,66.65133837562836,64.08457257002625,64.15238200928357,62.43739074933664,58.479065508645036,55.11024584133799,52.95393133457221,53.17956605052982,51.314413009749835,52.32816019421281,52.748296476122974,50.10027451492868,53.05580973604507,55.57019420004173,57.82425388892753,60.874309156414384,56.58732329297628,57.58085490090396,53.38968046379996,51.4348893183333,48.29156418364194,51.52922609596476,52.74928342218959,49.50859576128666];\n\n  it('should correctly calculate EMAs with weight 10', function() {\n    var ema = new EMA(10);\n    _.each(prices, function(p, i) {\n      ema.update(p);\n      expect(ema.result).to.equal(verified_ema10results[i]);\n    });\n  });\n\n  it('should correctly calculate EMAs with weight 12', function() {\n    var ema = new EMA(12);\n    _.each(prices, function(p, i) {\n      ema.update(p);\n      expect(ema.result).to.equal(verified_ema12results[i]);\n    });\n  });\n\n  it('should correctly calculate EMAs with weight 26', function() {\n    var ema = new EMA(26);\n    _.each(prices, function(p, i) {\n      ema.update(p);\n      expect(ema.result).to.equal(verified_ema26results[i]);\n    });\n  });\n\n});"
  },
  {
    "path": "test/indicators/macd.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are already compared \n// to MS Excel results, more info here:\n// \n// https://github.com/askmike/gekko/issues/161\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/MACD', function() {\n\n  var MACD = require(INDICATOR_PATH + 'MACD');\n\n  var verified_macd12v26v9diff = [0,-4.547008547008545,-3.9892858012516115,-7.814553897296733,-9.68546703354523,-11.758855194041395,-9.500012810452446,-6.02656065453003,-2.678111693000716,-7.762054965956388,-4.955890237178558,-3.179483224749447,-2.070566240940323,-6.6026618662643415,-3.776210725235984,-2.4759859198692027,-4.859274338230051,-4.038668120840633,-5.264248228346467,-8.717175683191812,-11.004031373646804,-11.633288323448895,-9.600560425733171,-10.13217748107575,-7.4816532084116645,-5.8781751804450835,-7.825556495508927,-3.4387406426898934,-0.20190496720273643,2.256606231167005,5.1941109452040735,-0.2217370531452758,0.8823334558761218,-3.766982623447589,-5.29260653034283,-7.863478747649999,-3.166999957817737,-1.365861305295958,-4.64570012391512];\n  var verified_macd12v26v9signal = [0,-0.9094017094017091,-1.5253785277716898,-2.7832136016766986,-4.163664288050406,-5.6827024692486034,-6.446164537489373,-6.362243760897504,-5.625417347318147,-6.052744871045796,-5.833373944272349,-5.30259580036777,-4.65618988848228,-5.045484284038693,-4.791629572278152,-4.328500841796362,-4.4346555410831,-4.355458057034607,-4.537216091296979,-5.373208009675945,-6.499372682470117,-7.526155810665873,-7.941036733679333,-8.379264883158616,-8.199742548209226,-7.735429074656398,-7.753454558826904,-6.890511775599502,-5.55279041392015,-3.990911084902719,-2.153906678881361,-1.767472753734144,-1.2375115118120907,-1.7434057341391904,-2.4532458933799184,-3.535292464233935,-3.4616339629506956,-3.0424794314197485,-3.363123569918823];\n  var verified_macd12v26v9result = [0,-3.6376068376068362,-2.4639072734799217,-5.031340295620034,-5.521802745494824,-6.076152724792792,-3.053848272963074,0.33568310636747434,2.9473056543174314,-1.7093100949105917,0.8774837070937913,2.1231125756183227,2.585623647541957,-1.5571775822256484,1.0154188470421683,1.8525149219271597,-0.42461879714695083,0.3167899361939739,-0.7270321370494885,-3.3439676735158663,-4.504658691176687,-4.107132512783021,-1.6595236920538383,-1.7529125979171347,0.7180893397975616,1.8572538942113148,-0.07210193668202258,3.4517711329096086,5.350885446717413,6.247517316069724,7.3480176240854345,1.5457357005888681,2.1198449676882127,-2.0235768893083987,-2.839360636962912,-4.3281862834160645,0.2946340051329588,1.6766181261237905,-1.2825765539962966];\n\n  it('should correctly calculate MACD diffs with 12/26/9', function() {\n    var macd = new MACD({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      macd.update(p);\n      expect(macd.diff).to.equal(verified_macd12v26v9diff[i]);\n    });\n  });\n\n  it('should correctly calculate MACD signals with 12/26/9', function() {\n    var macd = new MACD({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      macd.update(p);\n      expect(macd.signal.result).to.equal(verified_macd12v26v9signal[i]);\n    });\n  });\n\n  it('should correctly calculate MACD results with 12/26/9', function() {\n    var macd = new MACD({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      macd.update(p);\n      expect(macd.result).to.equal(verified_macd12v26v9result[i]);\n    });\n  });\n\n});\n\ndescribe('indicators/PPO', function() {\n\n  var PPO = require(INDICATOR_PATH + 'PPO');\n\n  var verified_ppo12v26v9 = [0,-5.922297673383055,-5.204813152773915,-10.775104631720897,-13.901816018390623,-17.719369436924076,-14.22599518036208,-8.779001074074772,-3.7775327599722406,-11.79779911287454,-7.3650541223130555,-4.659894802610166,-3.0092688006197794,-10.268186733549467,-5.72296687408477,-3.714833010426942,-7.582596159036941,-6.295429716477546,-8.431243146403258,-14.906489369094212,-19.9673059077387,-21.968696242678835,-18.053100351760996,-19.745285752660987,-14.297565938958984,-11.143819939485432,-15.619787658403148,-6.481364924591247,-0.3633332042639952,3.9025254618963814,8.5325172756507,-0.3918493405267646,1.5323382353294481,-7.05563807597937,-10.289915270521151,-16.28333826120637,-6.14602662946988,-2.589345706109427,-9.383623293044062];\n  var verified_ppo12v26v9signal = [0,-1.184459534676611,-1.9885302582960718,-3.745845132981037,-5.777039310062954,-8.16550533543518,-9.37760330442056,-9.257882858351403,-8.161812838675571,-8.889010093515365,-8.584218899274903,-7.799354079941956,-6.8413370240775215,-7.526706965971911,-7.165958947594484,-6.475733760160976,-6.697106239936169,-6.616770935244445,-6.979665377476208,-8.565030175799809,-10.845485322187589,-13.07012750628584,-14.066722075380872,-15.202434810836897,-15.021461036461314,-14.245932817066137,-14.52070378533354,-12.912836013185082,-10.402935451400865,-7.541843268741416,-4.3269711598629925,-3.539946795995747,-2.5254897897307083,-3.431519446980441,-4.8031986116885825,-7.099226541592141,-6.908586559167689,-6.044738388556036,-6.712515369453642];\n  var verified_ppo12v26v9hist = [0,-4.737838138706444,-3.2162828944778434,-7.02925949873986,-8.12477670832767,-9.553864101488896,-4.84839187594152,0.47888178427663064,4.3842800787033305,-2.9087890193591743,1.2191647769618479,3.13945927733179,3.832068223457742,-2.7414797675775553,1.4429920735097133,2.760900749734034,-0.8854899191007712,0.32134121876689914,-1.4515777689270495,-6.341459193294403,-9.121820585551113,-8.898568736392996,-3.9863782763801243,-4.54285094182409,0.7238950975023304,3.102112877580705,-1.099083873069608,6.431471088593835,10.03960224713687,11.444368730637798,12.859488435513693,3.1480974554689825,4.057828025060156,-3.6241186289989296,-5.486716658832568,-9.18411171961423,0.762559929697809,3.455392682446609,-2.6711079235904203];\n\n  it('should correctly calculate PPOs with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.ppo).to.equal(verified_ppo12v26v9[i]);\n    });\n  });\n\n  it('should correctly calculate PPO signals with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.PPOsignal).to.equal(verified_ppo12v26v9signal[i]);\n    });\n  });\n\n\n  it('should correctly calculate PPO hists with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.PPOhist).to.equal(verified_ppo12v26v9hist[i]);\n    });\n  });\n});\n\nxdescribe('indicators/DEMA', function() {\n\n  var DEMA = require(INDICATOR_PATH + 'DEMA');\n\n  xit('should correctly calculate DEMAs', function() {\n    // TODO!\n  });\n\n\n});\n"
  },
  {
    "path": "test/indicators/ppo.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are already compared \n// to MS Excel results, more info here:\n// \n// https://github.com/askmike/gekko/issues/161\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/PPO', function() {\n\n  var PPO = require(INDICATOR_PATH + 'PPO');\n\n  var verified_ppo12v26v9 = [0,-5.922297673383055,-5.204813152773915,-10.775104631720897,-13.901816018390623,-17.719369436924076,-14.22599518036208,-8.779001074074772,-3.7775327599722406,-11.79779911287454,-7.3650541223130555,-4.659894802610166,-3.0092688006197794,-10.268186733549467,-5.72296687408477,-3.714833010426942,-7.582596159036941,-6.295429716477546,-8.431243146403258,-14.906489369094212,-19.9673059077387,-21.968696242678835,-18.053100351760996,-19.745285752660987,-14.297565938958984,-11.143819939485432,-15.619787658403148,-6.481364924591247,-0.3633332042639952,3.9025254618963814,8.5325172756507,-0.3918493405267646,1.5323382353294481,-7.05563807597937,-10.289915270521151,-16.28333826120637,-6.14602662946988,-2.589345706109427,-9.383623293044062];\n  var verified_ppo12v26v9signal = [0,-1.184459534676611,-1.9885302582960718,-3.745845132981037,-5.777039310062954,-8.16550533543518,-9.37760330442056,-9.257882858351403,-8.161812838675571,-8.889010093515365,-8.584218899274903,-7.799354079941956,-6.8413370240775215,-7.526706965971911,-7.165958947594484,-6.475733760160976,-6.697106239936169,-6.616770935244445,-6.979665377476208,-8.565030175799809,-10.845485322187589,-13.07012750628584,-14.066722075380872,-15.202434810836897,-15.021461036461314,-14.245932817066137,-14.52070378533354,-12.912836013185082,-10.402935451400865,-7.541843268741416,-4.3269711598629925,-3.539946795995747,-2.5254897897307083,-3.431519446980441,-4.8031986116885825,-7.099226541592141,-6.908586559167689,-6.044738388556036,-6.712515369453642];\n  var verified_ppo12v26v9hist = [0,-4.737838138706444,-3.2162828944778434,-7.02925949873986,-8.12477670832767,-9.553864101488896,-4.84839187594152,0.47888178427663064,4.3842800787033305,-2.9087890193591743,1.2191647769618479,3.13945927733179,3.832068223457742,-2.7414797675775553,1.4429920735097133,2.760900749734034,-0.8854899191007712,0.32134121876689914,-1.4515777689270495,-6.341459193294403,-9.121820585551113,-8.898568736392996,-3.9863782763801243,-4.54285094182409,0.7238950975023304,3.102112877580705,-1.099083873069608,6.431471088593835,10.03960224713687,11.444368730637798,12.859488435513693,3.1480974554689825,4.057828025060156,-3.6241186289989296,-5.486716658832568,-9.18411171961423,0.762559929697809,3.455392682446609,-2.6711079235904203];\n\n  it('should correctly calculate PPOs with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.ppo).to.equal(verified_ppo12v26v9[i]);\n    });\n  });\n\n  it('should correctly calculate PPO signals with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.PPOsignal).to.equal(verified_ppo12v26v9signal[i]);\n    });\n  });\n\n\n  it('should correctly calculate PPO hists with 12/26/9', function() {\n    var ppo = new PPO({short: 12, long: 26, signal: 9});\n    _.each(prices, function(p, i) {\n      ppo.update(p);\n      expect(ppo.result.PPOhist).to.equal(verified_ppo12v26v9hist[i]);\n    });\n  });\n});\n"
  },
  {
    "path": "test/indicators/rsi.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are compared to the Talib repository at\n// https://github.com/wuhkuh/talib\n// (shameless plug, sorry guys ;))\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/RSI', function() {\n\n  var RSI = require(INDICATOR_PATH + 'RSI');\n\n  var verified_rsi2results = [0, 0, 47.22222222222223, 23.611111111111114, 38.43283582089553, 30.294117647058826, 78.2967032967033, 86.31639722863741, 89.12844036697248, 13.311866264730071, 64.95013850415512, 59.85653017461453, 54.19016363132106, 12.8454188854557, 68.56748255340673, 57.41553886370404, 26.512530826658676, 59.75774345724092, 36.04149739852744, 17.51008036340795, 26.905774699598737, 58.00044863973779, 85.82728624443239, 38.371227493966536, 74.96090570884536, 61.21019495608749, 19.438903652597787, 76.51344601664712, 72.30324117451528, 69.74473974944168, 84.24228523539779, 10.429850167468388, 59.707866801087974, 27.99023519523047, 48.57675474701421, 34.80106793288934, 81.96579567492182, 57.78953245436237, 23.585658801479056];\n  var verified_rsi12results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49.44320712694878, 42.432667245873155, 51.2017782300719, 49.94116787991835, 45.55663590860508, 49.284333951746184, 46.74501674557244, 43.4860123510052, 44.01823674189631, 45.82704797004994, 49.90209564896179, 46.351969981868436, 51.34208640997234, 50.37501845071388, 44.96351306736635, 54.464714123844956, 54.04642006918241, 53.895901697369816, 55.6476477612053, 42.60631369413207, 51.2964732419777, 43.83906729252931, 47.00600661743475, 45.08586375053323, 54.44633399991266, 51.6681674437389, 45.44886082103851];\n  var verified_rsi26results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46.44444444444444, 50.61070579555701, 50.44298978067838, 50.385107396174675, 51.143071170125296, 45.77270174725033, 49.6130641968312, 46.115177339098764, 47.56394036014283, 46.660676933508505, 51.11283316502063, 49.861270146262456, 46.92369439491447];\n\n  it('should correctly calculate RSI with period 2', function() {\n    var rsi = new RSI({ interval: 2 });\n    _.each(prices, function(p, i) {\n      rsi.update({ close: p });\n      expect(rsi.result).to.equal(verified_rsi2results[i]);\n    });\n  });\n\n  it('should correctly calculate RSI with period 12', function() {\n    var rsi = new RSI({ interval: 12 });\n    _.each(prices, function(p, i) {\n      rsi.update({ close: p });\n      expect(rsi.result).to.equal(verified_rsi12results[i]);\n    });\n  });\n\n  it('should correctly calculate RSI with period 26', function() {\n    var rsi = new RSI({ interval: 26 });\n    _.each(prices, function(p, i) {\n      rsi.update({ close: p });\n      expect(rsi.result).to.equal(verified_rsi26results[i]);\n    });\n  });\n});\n"
  },
  {
    "path": "test/indicators/sma.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/SMA', function() {\n\n  var SMA = require(INDICATOR_PATH + 'SMA');\n\n  var verified_SMA10results = [ 81, 52.5, 60, 50.25, 47, 43.333333333333336, 47.42857142857143, 53, 58.111111111111114, 52.5, 53, 58.6, 58.7, 57.4, 62.7, 67.7, 63.7, 61, 55.2, 55.9, 48.6, 43.2, 41.2, 43.2, 41, 39.3, 37.8, 40.3, 44.9, 52.6, 61.2, 58.9, 60.3, 57.6, 53.8, 48.9, 56.4, 54.2, 46.4 ];\n  var verified_SMA12results = [ 81, 52.5, 60, 50.25, 47, 43.333333333333336, 47.42857142857143, 53, 58.111111111111114, 52.5, 55.54545454545455, 57.583333333333336, 57.166666666666664, 55.833333333333336, 56.833333333333336, 61.333333333333336, 61.166666666666664, 64.5, 61.916666666666664, 55, 47.833333333333336, 49.833333333333336, 47.333333333333336, 43, 42.083333333333336, 46.25, 40.416666666666664, 41.666666666666664, 46.25, 48, 52.833333333333336, 52.333333333333336, 57.083333333333336, 55, 52.583333333333336, 51, 53.25, 54.083333333333336, 53.416666666666664 ];\n  var verified_SMA26results = [ 81, 52.5, 60, 50.25, 47, 43.333333333333336, 47.42857142857143, 53, 58.111111111111114, 52.5, 55.54545454545455, 57.583333333333336, 59, 55.357142857142854, 57.46666666666667, 58.5625, 57, 57.44444444444444, 56.578947368421055, 54.2, 52.23809523809524, 51.04545454545455, 51.26086956521739, 50.291666666666664, 50.88, 51.15384615384615, 48.69230769230769, 51.23076923076923, 51.69230769230769, 54.19230769230769, 56.69230769230769, 55.84615384615385, 55.76923076923077, 52.26923076923077, 49.5, 49.76923076923077, 50, 49.53846153846154, 46.96153846153846 ];\n  \n  it('should correctly calculate SMAs with window length 10', function() {\n    var sma = new SMA(10);\n    _.each(prices, function(p, i) {\n      sma.update(p);\n      expect(sma.result).to.equal(verified_SMA10results[i]);\n    });\n  });\n\n  it('should correctly calculate SMAs with window length 12', function() {\n    var sma = new SMA(12);\n    _.each(prices, function(p, i) {\n      sma.update(p);\n      expect(sma.result).to.equal(verified_SMA12results[i]);\n    });\n  });\n\n  it('should correctly calculate SMAs with window length 26', function() {\n    var sma = new SMA(26);\n    _.each(prices, function(p, i) {\n      sma.update(p);\n      expect(sma.result).to.equal(verified_SMA26results[i]);\n    });\n  });\n\n});"
  },
  {
    "path": "test/indicators/smma.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\n\nvar util = require('../../core/util');\nvar dirs = util.dirs();\nvar INDICATOR_PATH = dirs.indicators;\n\n// Fake input prices to verify all indicators \n// are working correctly by comparing fresh\n// calculated results to pre calculated results.\n\n// The precalculated results are compared to the Talib repository at\n// https://github.com/wuhkuh/talib\n// (shameless plug, sorry guys ;))\n\nvar prices = [81, 24, 75, 21, 34, 25, 72, 92, 99, 2, 86, 80, 76, 8, 87, 75, 32, 65, 41, 9, 13, 26, 56, 28, 65, 58, 17, 90, 87, 86, 99, 3, 70, 1, 27, 9, 92, 68, 9];\n\ndescribe('indicators/SMMA', function() {\n\n  var SMMA = require(INDICATOR_PATH + 'SMMA');\n\n  var verified_smma2results = [0, 52.5, 63.75, 42.375, 38.1875, 31.59375, 51.796875, 71.8984375, 85.44921875, 43.724609375, 64.8623046875, 72.43115234375, 74.215576171875, 41.1077880859375, 64.05389404296875, 69.52694702148438, 50.76347351074219, 57.881736755371094, 49.44086837768555, 29.220434188842773, 21.110217094421387, 23.555108547210693, 39.77755427360535, 33.88877713680267, 49.44438856840134, 53.72219428420067, 35.361097142100334, 62.68054857105017, 74.84027428552508, 80.42013714276254, 89.71006857138127, 46.355034285690635, 58.17751714284532, 29.58875857142266, 28.29437928571133, 18.647189642855665, 55.32359482142783, 61.661797410713916, 35.33089870535696];\n  var verified_smma12results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57.583333333333336, 59.118055555555564, 54.8582175925926, 57.53669945987655, 58.991974504886834, 56.74264329614626, 57.43075635480074, 56.061526658567345, 52.1397327703534, 48.878088372823946, 46.97158100842196, 47.72394925772013, 46.08028681957679, 47.656929584612065, 48.518852119227724, 45.89228110929208, 49.5679243501844, 52.687263987669034, 55.46332532202995, 59.09138154519412, 54.41709974976127, 55.7156747706145, 51.15603520639663, 49.14303227253024, 45.797779583152725, 49.64796461788999, 51.177300899732494, 47.66252582475479];\n  var verified_smma26results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51.15384615384615, 49.84023668639053, 51.384842967683205, 52.75465669969539, 54.0333237497071, 55.76281129779529, 53.73347240172624, 54.35910807858292, 52.30683469094512, 51.33349489513954, 49.70528355301879, 51.33200341636422, 51.973080208042525, 50.32026943081012];\n\n  it('should correctly calculate SMMAs with weight 2', function() {\n    var smma = new SMMA(2);\n    _.each(prices, function(p, i) {\n      smma.update(p);\n      expect(smma.result).to.equal(verified_smma2results[i]);\n    });\n  });\n\n  it('should correctly calculate SMMAs with weight 12', function() {\n    var smma = new SMMA(12);\n    _.each(prices, function(p, i) {\n      smma.update(p);\n      expect(smma.result).to.equal(verified_smma12results[i]);\n    });\n  });\n\n  it('should correctly calculate SMMAs with weight 26', function() {\n    var smma = new SMMA(26);\n    _.each(prices, function(p, i) {\n      smma.update(p);\n      expect(smma.result).to.equal(verified_smma26results[i]);\n    });\n  });\n});\n"
  },
  {
    "path": "test/marketFetcher.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar assert = chai.assert;\nvar sinon = require('sinon');\nvar proxyquire = require('proxyquire');\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nvar util = require(__dirname + '/../core/util');\nvar config = util.getConfig();\nvar dirs = util.dirs();\n\nvar providerName = config.watch.exchange.toLowerCase();\nvar providerPath = util.dirs().gekko + 'exchanges/' + providerName;\n\nreturn; // TEMP\n\nvar mf;\n\nvar spoofer = {};\n\nvar TRADES = [\n  { tid: 1, amount: 1, price: 100, date: 1475837937 },\n  { tid: 2, amount: 1, price: 100, date: 1475837938 }\n];\n\n// stub the exchange\nvar FakeProvider = function() {};\nvar getTrades = function(since, handler, descending) {\n  handler(\n    null,\n    TRADES\n  );\n}\nFakeProvider.prototype = {\n  getTrades: getTrades\n}\n\nspoofer[providerPath] = FakeProvider;\nvar getTradesSpy = sinon.spy(FakeProvider.prototype, 'getTrades');\n\n// stub the tradebatcher\nvar TradeBatcher = require(util.dirs().budfox + 'tradeBatcher');\nvar tradeBatcherSpy = sinon.spy(TradeBatcher.prototype, 'write');\nspoofer[util.dirs().budfox + 'tradeBatcher'] = TradeBatcher;\n\nvar MarketFetcher = proxyquire(dirs.budfox + 'marketFetcher', spoofer);\n\ndescribe('budfox/marketFetcher', function() {\n  it('should throw when not passed a config', function() {\n    expect(function() {\n      new MarketFetcher();\n    }).to.throw('TradeFetcher expects a config');\n  });\n\n  it('should instantiate', function() {\n    mf = new MarketFetcher(config);\n  });\n\n  it('should fetch with correct arguments', function() {\n\n    // mf.fetch should call the DataProvider like:\n    // provider.getTrades(since, callback, descending)\n\n    mf.fetch();\n    expect(getTradesSpy.callCount).to.equal(1);\n    \n    var args = getTradesSpy.firstCall.args;\n    \n    // test-config uses NO `tradingAdvisor`\n    var since = args[0];\n    expect(since).to.equal(undefined);\n\n    var handler = args[1];\n    assert.isFunction(handler);\n\n    var descending = args[2];\n    expect(descending).to.equal(false);\n  });\n\n  xit('should retry on error', function() {\n    // todo\n  });\n\n  it('should pass the data to the tradebatcher', function() {\n    mf.fetch();\n    expect(getTradesSpy.callCount).to.equal(2);\n\n    expect(tradeBatcherSpy.lastCall.args[0]).to.deep.equal(TRADES);\n  });\n\n  xit('should relay trades', function() {\n    // todo\n  });\n\n});"
  },
  {
    "path": "test/plugins/portfolioManager.js",
    "content": ""
  },
  {
    "path": "test/test-config.json",
    "content": "{\n  \"silent\": true,\n  \"watch\": {\n    \"exchange\": \"Bitstamp\",\n    \"currency\": \"USD\",\n    \"asset\": \"BTC\"\n  },\n  \"tradingAdvisor\": {\n    \"enabled\": false\n  },\n  \"trader\": {\n    \"enabled\": false\n  },\n  \"adviceLogger\": {\n    \"enabled\": false\n  },\n  \"profitSimulator\": {\n    \"enabled\": false,\n    \"reportInCurrency\": true,\n    \"simulationBalance\": {\n      \"asset\": 1,\n      \"currency\": 100\n    },\n    \"feeMaker\": 0.15,\n    \"feeTaker\": 0.25,\n    \"feeUsing\": \"maker\",\n    \"slippage\": 0.05\n  },\n  \"pushover\": {\n    \"enabled\": false,\n    \"sendPushoverOnStart\": false,\n    \"muteSoft\": true,\n    \"tag\": \"[GEKKO]\",\n    \"key\": \"\",\n    \"user\": \"\"\n  },\n  \"mailer\": {\n    \"enabled\": false,\n    \"sendMailOnStart\": true,\n    \"email\": \"\",\n    \"muteSoft\": true,\n    \"password\": \"\",\n    \"tag\": \"[GEKKO] \",\n    \"server\": \"smtp.gmail.com\",\n    \"smtpauth\": true,\n    \"user\": \"\",\n    \"from\": \"\",\n    \"to\": \"\",\n    \"ssl\": true,\n    \"port\": \"\"\n  },\n  \"pushbullet\": {\n    \"enabled\": false,\n    \"sendMessageOnStart\": true,\n    \"key\": \"xxx\",\n    \"email\": \"jon_snow@westeros.org\",\n    \"tag\": \"[GEKKO]\"\n  },\n  \"ircbot\": {\n    \"enabled\": false,\n    \"emitUpdates\": false,\n    \"channel\": \"#your-channel\",\n    \"server\": \"irc.freenode.net\",\n    \"botName\": \"gekkobot\"\n  },\n  \"xmppbot\": {\n    \"enabled\": false,\n    \"emitUpdates\": false,\n    \"client_id\": \"jabber_id\",\n    \"client_pwd\": \"jabber_pw\",\n    \"client_host\": \"jabber_server\",\n    \"client_port\": 5222,\n    \"status_msg\": \"I'm online\",\n    \"receiver\": \"jabber_id_for_updates\"\n  },\n  \"campfire\": {\n    \"enabled\": false,\n    \"emitUpdates\": false,\n    \"nickname\": \"Gordon\",\n    \"roomId\": null,\n    \"apiKey\": \"\",\n    \"account\": \"\"\n  },\n  \"redisBeacon\": {\n    \"enabled\": false,\n    \"port\": 6379,\n    \"host\": \"127.0.0.1\",\n    \"channelPrefix\": \"\",\n    \"broadcast\": [\n      \"candle\"\n    ]\n  },\n  \"candleWriter\": {\n    \"adapter\": \"sqlite\",\n    \"enabled\": true\n  },\n  \"adapters\": {\n    \"sqlite\": {\n      \"path\": \"plugins/sqlite\",\n      \"dataDirectory\": \"./history\",\n      \"version\": 0.1,\n      \"dependencies\": [\n        {\n          \"module\": \"sqlite3\",\n          \"version\": \"3.1.4\"\n        }\n      ]\n    },\n    \"postgresql\": {\n      \"path\": \"plugins/postgresql\",\n      \"version\": 0.1,\n      \"connectionString\": \"postgres://user:pass@localhost:5432\",\n      \"dependencies\": [\n        {\n          \"module\": \"pg\",\n          \"version\": \"6.1.0\"\n        }\n      ]\n    }\n  },\n  \"backtest\": {\n    \"adapter\": \"sqlite\",\n    \"daterange\": \"scan\",\n    \"batchSize\": 50\n  },\n  \"importer\": {\n    \"daterange\": {\n      \"from\": \"2015-09-09 12:00:00\"\n    }\n  },\n  \"I understand that Gekko only automates MY OWN trading strategies\": false\n}\n"
  },
  {
    "path": "test/tradeBatcher.js",
    "content": "var chai = require('chai');\nvar expect = chai.expect;\nvar should = chai.should;\nvar sinon = require('sinon');\n\nvar _ = require('lodash');\nvar moment = require('moment');\n\nvar utils = require(__dirname + '/../core/util');\nvar dirs = utils.dirs();\nvar TradeBatcher = require(dirs.budfox + 'tradeBatcher');\n\nvar trades_tid_1 = [\n  {tid: 1, price: 10, amount: 1, date: 1466115793},\n  {tid: 2, price: 10, amount: 1, date: 1466115794},\n  {tid: 3, price: 10, amount: 1, date: 1466115795}\n];\n\nvar trades_tid_2 = [\n  {tid: 2, price: 10, amount: 1, date: 1466115794},\n  {tid: 3, price: 10, amount: 1, date: 1466115795},\n  {tid: 4, price: 10, amount: 1, date: 1466115796},\n  {tid: 5, price: 10, amount: 1, date: 1466115797}\n];\n\nvar empty_trades = [\n  {tid: 2, price: 10, amount: 0, date: 1466115794},\n  {tid: 3, price: 10, amount: 0, date: 1466115795},\n  {tid: 4, price: 10, amount: 0, date: 1466115796},\n  {tid: 5, price: 10, amount: 0, date: 1466115797}\n];\n\ndescribe('budfox/tradeBatcher', function() {\n  var tb;\n\n  it('should throw when not passed a number', function() {\n    expect(function() {\n      new TradeBatcher()\n    }).to.throw('tid is not a string');\n  });\n\n  it('should instantiate', function() {\n    tb = new TradeBatcher('tid');\n  });\n\n  it('should throw when not fed an array', function() {\n    var trade = _.first(trades_tid_1);\n    expect(\n      tb.write.bind(tb, trade)\n    ).to.throw('batch is not an array');\n  });\n\n  it('should emit an event when fed trades', function() {\n    tb = new TradeBatcher('tid');\n\n    var spy = sinon.spy();\n    tb.on('new batch', spy);\n    tb.write( trades_tid_1 );\n    expect(spy.callCount).to.equal(1);\n  });\n\n  it('should only emit once when fed the same trades twice', function() {\n    tb = new TradeBatcher('tid');\n\n    var spy = sinon.spy();\n    tb.on('new batch', spy);\n    tb.write( trades_tid_1 );\n    tb.write( trades_tid_1 );\n    expect(spy.callCount).to.equal(1);\n  });\n\n  it('should correctly set meta data', function() {\n    tb = new TradeBatcher('tid');\n\n    var spy = sinon.spy();\n    tb.on('new batch', spy);\n\n    tb.write( trades_tid_1 );\n\n    var transformedTrades = _.map(_.cloneDeep(trades_tid_1), function(trade) {\n      trade.date = moment.unix(trade.date).utc();\n      return trade;\n    });\n\n    var result = {\n      data: transformedTrades,\n      amount: _.size(transformedTrades),\n      start: _.first(transformedTrades).date,\n      end: _.last(transformedTrades).date,\n      first: _.first(transformedTrades),\n      last: _.last(transformedTrades)\n    }\n\n    var tbResult = _.first(_.first(spy.args));\n    expect(tbResult.amount).to.equal(result.amount);\n    expect(tbResult.start.unix()).to.equal(result.start.unix());\n    expect(tbResult.end.unix()).to.equal(result.end.unix());\n    expect(tbResult.data.length).to.equal(result.data.length);\n\n    _.each(tbResult.data, function(t, i) {\n      expect(tbResult.data[i].tid).to.equal(result.data[i].tid);      \n      expect(tbResult.data[i].price).to.equal(result.data[i].price);      \n      expect(tbResult.data[i].amount).to.equal(result.data[i].amount);      \n    });\n  });\n\n  it('should correctly filter trades', function() {\n    tb = new TradeBatcher('tid');\n\n    var spy = sinon.spy();\n    tb.on('new batch', spy);\n\n    tb.write( trades_tid_1 );\n    tb.write( trades_tid_2 );\n\n    expect(spy.callCount).to.equal(2);\n\n    var tbResult = _.first(_.last(spy.args));\n\n    expect(tbResult.amount).to.equal(2);\n    expect(tbResult.start.unix()).to.equal(1466115796);\n    expect(tbResult.end.unix()).to.equal(1466115797);\n    expect(tbResult.data.length).to.equal(2);\n  });\n\n  // see @link\n  // https://github.com/askmike/gekko/issues/486\n  it('should filter out empty trades', function() {\n    tb = new TradeBatcher('tid');\n\n    var spy = sinon.spy();\n    tb.on('new batch', spy);\n\n    tb.write(empty_trades);\n\n    expect(spy.callCount).to.equal(0);\n  }); \n\n});"
  },
  {
    "path": "test/triggers/trailingStop.js",
    "content": "const chai = require('chai');\nconst expect = chai.expect;\nconst should = chai.should;\nconst sinon = require('sinon');\n\nconst _ = require('lodash');\nconst moment = require('moment');\n\nconst utils = require(__dirname + '/../../core/util');\n\nconst dirs = utils.dirs();\nconst TrailingStop = require(dirs.broker + 'triggers/trailingStop');\n\ndescribe('exchange/triggers/trailingStop', () => {\n  let cb;\n\n  it('should instantiate a trailing stop loss trigger', () => {\n    expect(() => {\n      const ts = new TrailingStop({\n        trail: 10,\n        initialPrice: 100,\n        onTrigger: () => {}\n      })\n    }).to.not.throw()\n  })\n\n  it('should call onTrigger when the stop hits', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(50);\n\n    expect(spy.called).to.be.true;\n  });\n\n  it('should emit a trigger event when the stop hits', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100\n    });\n\n    ts.on('trigger', spy);\n\n    ts.updatePrice(50);\n\n    expect(spy.called).to.be.true;\n  });\n\n  it('should not trigger when the the price does not go down', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(100);\n    ts.updatePrice(101);\n    ts.updatePrice(102);\n    ts.updatePrice(103);\n    ts.updatePrice(104);\n\n    expect(spy.called).to.be.false;\n  });\n\n  it('should not trigger when the the price goes down but above the offset', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(99);\n    ts.updatePrice(98);\n    ts.updatePrice(97);\n    ts.updatePrice(96);\n    ts.updatePrice(95);\n    ts.updatePrice(94);\n    ts.updatePrice(93);\n    ts.updatePrice(92);\n    ts.updatePrice(91);\n\n    expect(spy.called).to.be.false;\n  });\n\n  it('should trigger when the the price equals the offset', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(99);\n    ts.updatePrice(98);\n    ts.updatePrice(92);\n\n    expect(spy.called).to.be.false;\n\n    ts.updatePrice(90);\n\n    expect(spy.called).to.be.true;\n  });\n\n  it('should trigger when the the price goes up and down', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(101);\n    ts.updatePrice(102);\n    ts.updatePrice(103);\n    ts.updatePrice(104);\n    ts.updatePrice(105);\n\n    expect(spy.called).to.be.false;\n\n    ts.updatePrice(95);\n\n    expect(spy.called).to.be.true;\n  });\n\n  it('should only trigger once', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(90);\n    expect(spy.called).to.be.true;\n\n    const spy2 = sinon.spy();\n    ts.on('trigger', spy2);\n    ts.updatePrice(80);\n    expect(spy2.called).to.be.false;\n  });\n\n    it('should not trigger when the the price swings above the trail', () => {\n    const spy = sinon.spy();\n\n    const ts = new TrailingStop({\n      trail: 10,\n      initialPrice: 100,\n      onTrigger: spy\n    });\n\n    ts.updatePrice(110);\n    ts.updatePrice(101);\n    ts.updatePrice(111);\n    ts.updatePrice(102);\n    ts.updatePrice(112);\n    ts.updatePrice(103);\n    ts.updatePrice(113);\n    ts.updatePrice(104);\n\n    expect(spy.called).to.be.false;\n\n    ts.updatePrice(103);\n\n    expect(spy.called).to.be.true;\n  });\n\n});"
  },
  {
    "path": "web/apiKeyManager.js",
    "content": "const fs = require('fs');\nconst _ = require('lodash');\nconst cache = require('./state/cache');\nconst broadcast = cache.get('broadcast');\n\nconst apiKeysFile = __dirname + '/../SECRET-api-keys.json';\n\n// on init:\nconst noApiKeysFile = !fs.existsSync(apiKeysFile);\n\nif(noApiKeysFile)\n  fs.writeFileSync(\n    apiKeysFile,\n    JSON.stringify({})\n  );\n\nconst apiKeys = JSON.parse( fs.readFileSync(apiKeysFile, 'utf8') );\n\nmodule.exports = {\n  get: () => _.keys(apiKeys),\n\n  // note: overwrites if exists\n  add: (exchange, props) => {\n    apiKeys[exchange] = props;\n    fs.writeFileSync(apiKeysFile, JSON.stringify(apiKeys));\n\n    broadcast({\n      type: 'apiKeys',\n      exchanges: _.keys(apiKeys)\n    });\n  },\n  remove: exchange => {\n    if(!apiKeys[exchange])\n      return;\n\n    delete apiKeys[exchange];\n    fs.writeFileSync(apiKeysFile, JSON.stringify(apiKeys));\n\n    broadcast({\n      type: 'apiKeys',\n      exchanges: _.keys(apiKeys)\n    });\n  },\n\n  // retrieve api keys\n  // this cannot touch the frontend for security reaons.\n  _getApiKeyPair: key => apiKeys[key]\n}"
  },
  {
    "path": "web/baseUIconfig.js",
    "content": "// Note: this file gets copied around, make sure you edit\n// the UIconfig located at `gekko/web/vue/dist/UIconfig.js`.\n\n// This config is used by both the frontend as well as the web server.\n// see https://gekko.wizb.it/docs/installation/installing_gekko_on_a_server.html#Configuring-Gekko\n\nconst CONFIG = {\n  headless: false,\n  api: {\n    host: '127.0.0.1',\n    port: 3000,\n    timeout: 120000 // 2 minutes\n  },\n  ui: {\n    ssl: false,\n    host: 'localhost',\n    port: 3000,\n    path: '/'\n  },\n  adapter: 'sqlite'\n}\n\nif(typeof window === 'undefined')\n  module.exports = CONFIG;\nelse\n  window.CONFIG = CONFIG;\n"
  },
  {
    "path": "web/isWindows.js",
    "content": "const os = require('os');\n\nvar isWindows = (\n    os.platform() == 'win32' // true evenon 64 bit archs\n    || os.release().indexOf('Microsoft') > -1 // bash on Windows 10 scenario\n);\n\nmodule.exports = isWindows;\n\n"
  },
  {
    "path": "web/routes/apiKeys.js",
    "content": "const cache = require('../state/cache');\nconst manager = cache.get('apiKeyManager');\n\nmodule.exports = {\n  get: function *() {\n    this.body = manager.get();\n  },\n  add: function *() {\n    const content = this.request.body;\n\n    manager.add(content.exchange, content.values);\n\n    this.body = {\n      status: 'ok'\n    };\n  },\n  remove: function *() {\n    const exchange = this.request.body.exchange;\n\n    manager.remove(exchange);\n\n    this.body = {\n      status: 'ok'\n    };\n  }\n}"
  },
  {
    "path": "web/routes/backtest.js",
    "content": "// simple POST request that returns the backtest result\n\nconst _ = require('lodash');\nconst promisify = require('tiny-promisify');\nconst pipelineRunner = promisify(require('../../core/workers/pipeline/parent'));\n\n// starts a backtest\n// requires a post body like:\n//\n// {\n//   gekkoConfig: {watch: {exchange: \"poloniex\", currency: \"USDT\", asset: \"BTC\"},…},…}\n//   data: {\n//     candleProps: [\"close\", \"start\"],\n//     indicatorResults: true,\n//     report: true,\n//     roundtrips: true\n//   }\n// }\nmodule.exports = function *() {\n  var mode = 'backtest';\n\n  var config = {};\n\n  var base = require('./baseConfig');\n\n  var req = this.request.body;\n\n  _.merge(config, base, req);\n\n  this.body = yield pipelineRunner(mode, config);\n}"
  },
  {
    "path": "web/routes/baseConfig.js",
    "content": "var UIconfig = require('../vue/dist/UIconfig');\n\nvar config = {};\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                          GENERAL SETTINGS\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.silent = false;\nconfig.debug = true;\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING TRADING ADVICE\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nconfig.tradingAdvisor = {\n}\n\nconfig.candleWriter = {\n  enabled: false\n}\n\nconfig.backtestResultExporter = {\n  enabled: false,\n  writeToDisk: false,\n  data: {\n    stratUpdates: false,\n    roundtrips: true,\n    stratCandles: true,\n    trades: true\n  }\n}\n\nconfig.childToParent = {\n  enabled: false,\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING ADAPTER\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n// configurable in the UIconfig\nconfig.adapter = UIconfig.adapter;\n\nconfig.sqlite = {\n  path: 'plugins/sqlite',\n  version: 0.1,\n  dataDirectory: 'history',\n  journalMode: require('../isWindows.js') ? 'PERSIST' : 'WAL',\n  dependencies: [{\n    module: 'sqlite3',\n    version: '3.1.4'\n  }]\n}\n\n  // Postgres adapter example config (please note: requires postgres >= 9.5):\nconfig.postgresql = {\n  path: 'plugins/postgresql',\n  version: 0.1,\n  connectionString: 'postgres://user:pass@localhost:5432', // if default port\n  database: null, // if set, we'll put all tables into a single database.\n  schema: 'public',\n  dependencies: [{\n    module: 'pg',\n    version: '7.4.3'\n  }]\n}\n\n// Mongodb adapter, requires mongodb >= 3.3 (no version earlier tested)\nconfig.mongodb = {\n  path: 'plugins/mongodb',\n  version: 0.1,\n  connectionString: 'mongodb://mongodb/gekko', // connection to mongodb server\n  dependencies: [{\n    module: 'mongojs',\n    version: '2.4.0'\n  }]\n}\n\nconfig.adviceWriter = {\n  enabled: false,\n  muteSoft: true,\n}\n\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//                       CONFIGURING BACKTESTING\n// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n// Note that these settings are only used in backtesting mode, see here:\n// @link: https://github.com/askmike/gekko/blob/stable/docs/Backtesting.md\n\nconfig.backtest = {\n  daterange: 'scan',\n  batchSize: 50\n}\n\nconfig.importer = {\n  daterange: {\n    // NOTE: these dates are in UTC\n    from: \"2016-06-01 12:00:00\"\n  }\n}\n\nmodule.exports = config;\n"
  },
  {
    "path": "web/routes/configPart.js",
    "content": "const _ = require('lodash');\nconst fs = require('co-fs');\n\nconst parts = {\n  paperTrader: 'config/plugins/paperTrader',\n  candleWriter: 'config/plugins/candleWriter',\n  performanceAnalyzer: 'config/plugins/performanceAnalyzer'\n}\n\nconst gekkoRoot = __dirname + '/../../';\n\nmodule.exports = function *() {\n  if(!_.has(parts, this.params.part))\n    return this.body = 'error :(';\n\n  const fileName = gekkoRoot + '/' + parts[this.params.part] + '.toml';\n  this.body = {\n    part: yield fs.readFile(fileName, 'utf8') \n  }\n}"
  },
  {
    "path": "web/routes/deleteGekko.js",
    "content": "const cache = require('../state/cache');\nconst gekkoManager = cache.get('gekkos');\n\n// Deletes a gekko\n// requires a post body with an id\nmodule.exports = function *() {\n\n  let id = this.request.body.id;\n\n  if(!id) {\n    this.body = { status: 'not ok' }\n    return;\n  }\n\n  try {\n    gekkoManager.delete(id);\n  } catch(e) {\n    this.body = { status: e.message }\n  }\n\n  this.body = { status: 'ok' };\n}"
  },
  {
    "path": "web/routes/exchanges.js",
    "content": "const _ = require('lodash');\nconst fs = require('co-fs');\n\nconst gekkoRoot = __dirname + '/../../';\nvar util = require(__dirname + '/../../core/util');\n\nvar config = {};\n\nconfig.debug = false;\nconfig.silent = false;\n\nutil.setConfig(config);\n\nmodule.exports = function *() {\n  const exchangesDir = yield fs.readdir(gekkoRoot + 'exchange/wrappers/');\n  const exchanges = exchangesDir\n    .filter(f => _.last(f, 3).join('') === '.js')\n    .map(f => f.slice(0, -3));\n\n  let allCapabilities = [];\n\n  exchanges.forEach(function (exchange) {\n    let Trader = null;\n\n    try {\n      Trader = require(gekkoRoot + 'exchange/wrappers/' + exchange);\n    } catch (e) {\n      return;\n    }\n\n    if (!Trader || !Trader.getCapabilities) {\n      return;\n    }\n\n    allCapabilities.push(Trader.getCapabilities());\n  });\n\n  this.body = allCapabilities;\n}"
  },
  {
    "path": "web/routes/getCandles.js",
    "content": "// simple POST request that returns the candles requested\n\n// expects a config like:\n\n// let config = {\n//   watch: {\n//     exchange: 'poloniex',\n//     currency: 'USDT',\n//     asset: 'BTC'\n//   },\n//   daterange: {\n//     from: '2016-05-22 11:22',\n//     to: '2016-06-03 19:56'\n//   },\n//   adapter: 'sqlite',\n//   sqlite: {\n//     path: 'plugins/sqlite',\n\n//     dataDirectory: 'history',\n//     version: 0.1,\n\n//     dependencies: [{\n//       module: 'sqlite3',\n//       version: '3.1.4'\n//     }]\n//   },\n//   candleSize: 100\n// }\n\nconst _ = require('lodash');\nconst promisify = require('tiny-promisify');\nconst candleLoader = promisify(require('../../core/workers/loadCandles/parent'));\nconst base = require('./baseConfig');\n\nmodule.exports = function *() {\n\n  config = {};\n  _.merge(config, base, this.request.body);\n  this.body = yield candleLoader(config);\n}"
  },
  {
    "path": "web/routes/import.js",
    "content": "const _ = require('lodash');\nconst promisify = require('tiny-promisify');\nconst pipelineRunner = promisify(require('../../core/workers/pipeline/parent'));\n\nconst cache = require('../state/cache');\nconst broadcast = cache.get('broadcast');\nconst importManager = cache.get('imports');\n\nconst base = require('./baseConfig');\n\n// starts an import\n// requires a post body with a config object\nmodule.exports = function *() {\n  let mode = 'importer';\n\n  let config = {}\n\n  _.merge(config, base, this.request.body);\n\n  let importId = (Math.random() + '').slice(3);\n\n  let errored = false;\n\n  console.log('Import', importId, 'started');\n\n  pipelineRunner(mode, config, (err, event) => {\n    if(errored)\n      return;\n\n    if(err) {\n      errored = true;\n      console.error('RECEIVED ERROR IN IMPORT', importId);\n      console.error(err);\n      importManager.delete(importId);\n      return broadcast({\n        type: 'import_error',\n        import_id: importId,\n        error: err\n      });\n    }\n\n    if(!event)\n      return;\n\n    // update local cache\n    importManager.update(importId, {\n      latest: event.latest,\n      done: event.done\n    });\n\n    // emit update over ws\n    let wsEvent = {\n      type: 'import_update',\n      import_id: importId,\n      updates: {\n        latest: event.latest,\n        done: event.done\n      }\n    }\n    broadcast(wsEvent);\n  });\n\n  let daterange = this.request.body.importer.daterange;\n\n  const _import = {\n    watch: config.watch,\n    id: importId,\n    latest: '',\n    from: daterange.from,\n    to: daterange.to\n  }\n\n  importManager.add(_import);\n  this.body = _import;\n}"
  },
  {
    "path": "web/routes/info.js",
    "content": "const p = require('../../package.json');\n\n// Retrieves API information\nmodule.exports = function *() {\n  this.body = {\n    version: p.version\n  }\n}"
  },
  {
    "path": "web/routes/list.js",
    "content": "const cache = require('../state/cache');\n\nmodule.exports = function(name) {\n  return function *() {\n    this.body = cache.get(name).list();\n  }\n}"
  },
  {
    "path": "web/routes/scanDatasets.js",
    "content": "const _ = require('lodash');\nconst promisify = require('promisify-node');\n\nconst scan = promisify(require('../../core/workers/datasetScan/parent'));\n\n// starts a scan\n// requires a post body with configuration of:\n// \n// - config.watch\nconst route = function *() {\n\n  var config = require('./baseConfig');\n\n  _.merge(config, this.request.body);\n\n  this.body = yield scan(config);\n};\n\nmodule.exports = route;"
  },
  {
    "path": "web/routes/scanDateRange.js",
    "content": "const _ = require('lodash');\nconst promisify = require('promisify-node');\n\nconst scan = promisify(require('../../core/workers/dateRangeScan/parent'));\n\n// starts a scan\n// requires a post body with configuration of:\n// \n// - config.watch\nconst route = function *() {\n\n  var config = require('./baseConfig');\n\n  _.merge(config, this.request.body);\n\n  this.body = yield scan(config);\n};\n\nmodule.exports = route;"
  },
  {
    "path": "web/routes/startGekko.js",
    "content": "const _ = require('lodash');\n\nconst cache = require('../state/cache');\nconst Logger = require('../state/logger');\nconst apiKeyManager= cache.get('apiKeyManager');\nconst gekkoManager = cache.get('gekkos');\n\nconst base = require('./baseConfig');\n\n// starts an import\n// requires a post body with a config object\nmodule.exports = function *() {\n  const mode = this.request.body.mode;\n\n  let config = {};\n\n  _.merge(config, base, this.request.body);\n\n  // Attach API keys\n  if(config.trader && config.trader.enabled && !config.trader.key) {\n\n    const keys = apiKeyManager._getApiKeyPair(config.watch.exchange);\n\n    if(!keys) {\n      this.body = 'No API keys found for this exchange.';\n      return;\n    }\n\n    _.merge(\n      config.trader,\n      keys\n    );\n  }\n\n  const state = gekkoManager.add({config, mode});\n\n  this.body = state;\n}\n"
  },
  {
    "path": "web/routes/stopGekko.js",
    "content": "const cache = require('../state/cache');\nconst gekkoManager = cache.get('gekkos');\n\n// stops a Gekko\n// requires a post body with an id\nmodule.exports = function *() {\n\n  let id = this.request.body.id;\n\n  if(!id) {\n    this.body = { status: 'not ok' }\n    return;\n  }\n\n  let stopped = gekkoManager.stop(id);\n\n  if(!stopped) {\n    this.body = { status: 'not ok' }\n    return; \n  }\n\n  this.body = { status: 'ok' };\n}"
  },
  {
    "path": "web/routes/strategies.js",
    "content": "const _ = require('lodash');\nconst fs = require('co-fs');\n\nconst gekkoRoot = __dirname + '/../../';\n\nmodule.exports = function *() {\n  const strategyDir = yield fs.readdir(gekkoRoot + 'strategies');\n  const strats = strategyDir\n    .filter(f => _.last(f, 3).join('') === '.js')\n    .map(f => {\n      return { name: f.slice(0, -3) }\n    });\n\n  // for every strat, check if there is a config file and add it\n  const stratConfigPath = gekkoRoot + 'config/strategies';\n  const strategyParamsDir = yield fs.readdir(stratConfigPath);\n\n  for(let i = 0; i < strats.length; i++) {\n    let strat = strats[i];\n    if(strategyParamsDir.indexOf(strat.name + '.toml') !== -1)\n      strat.params = yield fs.readFile(stratConfigPath + '/' + strat.name + '.toml', 'utf8')\n    else\n      strat.params = '';\n  }\n\n  this.body = strats;\n}"
  },
  {
    "path": "web/server.js",
    "content": "const config = require('./vue/dist/UIconfig');\n\nconst koa = require('koa');\nconst serve = require('koa-static');\nconst cors = require('koa-cors');\nconst _ = require('lodash');\nconst bodyParser = require('koa-bodyparser');\n\nconst opn = require('opn');\nconst server = require('http').createServer();\nconst router = require('koa-router')();\nconst ws = require('ws');\nconst app = koa();\n\nconst WebSocketServer = require('ws').Server;\nconst wss = new WebSocketServer({ server: server });\n\nconst cache = require('./state/cache');\n\nconst nodeCommand = _.last(process.argv[1].split('/'));\nconst isDevServer = nodeCommand === 'server' || nodeCommand === 'server.js';\n\nwss.on('connection', ws => {\n  ws.isAlive = true;\n  ws.on('pong', () => {\n    ws.isAlive = true;\n  });\n  ws.ping(_.noop);\n  ws.on('error', e => {\n    console.error(new Date, '[WS] connection error:', e);\n  });\n});\n\n\nsetInterval(() => {\n  wss.clients.forEach(ws => {\n    if(!ws.isAlive) {\n      console.log(new Date, '[WS] stale websocket client, terminiating..');\n      return ws.terminate();\n    }\n\n    ws.isAlive = false;\n    ws.ping(_.noop);\n  });\n}, 10 * 1000);\n\n// broadcast function\nconst broadcast = data => {\n  if(_.isEmpty(data)) {\n    return;\n  }\n\n  const payload = JSON.stringify(data);\n\n  wss.clients.forEach(ws => {\n    ws.send(payload, err => {\n      if(err) {\n        console.log(new Date, '[WS] unable to send data to client:', err);\n      }\n    });\n  }\n  );\n}\ncache.set('broadcast', broadcast);\n\n\nconst ListManager = require('./state/listManager');\nconst GekkoManager = require('./state/gekkoManager');\n\n// initialize lists and dump into cache\ncache.set('imports', new ListManager);\ncache.set('gekkos', new GekkoManager);\ncache.set('apiKeyManager', require('./apiKeyManager'));\n\n// setup API routes\n\nconst WEBROOT = __dirname + '/';\nconst ROUTE = n => WEBROOT + 'routes/' + n;\n\n// attach routes\nconst apiKeys = require(ROUTE('apiKeys'));\nrouter.get('/api/info', require(ROUTE('info')));\nrouter.get('/api/strategies', require(ROUTE('strategies')));\nrouter.get('/api/configPart/:part', require(ROUTE('configPart')));\nrouter.get('/api/apiKeys', apiKeys.get);\n\nconst listWraper = require(ROUTE('list'));\nrouter.get('/api/imports', listWraper('imports'));\nrouter.get('/api/gekkos', listWraper('gekkos'));\nrouter.get('/api/exchanges', require(ROUTE('exchanges')));\n\nrouter.post('/api/addApiKey', apiKeys.add);\nrouter.post('/api/removeApiKey', apiKeys.remove);\nrouter.post('/api/scan', require(ROUTE('scanDateRange')));\nrouter.post('/api/scansets', require(ROUTE('scanDatasets')));\nrouter.post('/api/backtest', require(ROUTE('backtest')));\nrouter.post('/api/import', require(ROUTE('import')));\nrouter.post('/api/startGekko', require(ROUTE('startGekko')));\nrouter.post('/api/stopGekko', require(ROUTE('stopGekko')));\nrouter.post('/api/deleteGekko', require(ROUTE('deleteGekko')));\nrouter.post('/api/getCandles', require(ROUTE('getCandles')));\n\n\n// incoming WS:\n// wss.on('connection', ws => {\n//   ws.on('message', _.noop);\n// });\n\napp\n  .use(cors())\n  .use(serve(WEBROOT + 'vue/dist'))\n  .use(bodyParser())\n  .use(require('koa-logger')())\n  .use(router.routes())\n  .use(router.allowedMethods());\n\nserver.timeout = config.api.timeout || 120000;\nserver.on('request', app.callback());\nserver.listen(config.api.port, config.api.host, '::', () => {\n  const host = `${config.ui.host}:${config.ui.port}${config.ui.path}`;\n\n  if(config.ui.ssl) {\n    var location = `https://${host}`;\n  } else {\n    var location = `http://${host}`;\n  }\n\n  console.log('Serving Gekko UI on ' + location +  '\\n');\n\n\n  // only open a browser when running `node gekko`\n  // this prevents opening the browser during development\n  if(!isDevServer && !config.headless) {\n    opn(location)\n      .catch(err => {\n        console.log('Something went wrong when trying to open your web browser. UI is running on ' + location + '.');\n    });\n  }\n});\n"
  },
  {
    "path": "web/state/cache.js",
    "content": "const _ = require('lodash');\n\nconst cache = {};\n\nmodule.exports = {\n  set: (name, val) => {\n    cache[name] = val;\n    return true;\n  },\n  get: name => {\n    if(_.has(cache, name))\n      return cache[name];\n  }\n}"
  },
  {
    "path": "web/state/gekkoManager.js",
    "content": "const _ = require('lodash');\nconst moment = require('moment');\n\nconst broadcast = require('./cache').get('broadcast');\nconst Logger = require('./logger');\nconst pipelineRunner = require('../../core/workers/pipeline/parent');\nconst reduceState = require('./reduceState.js');\nconst now = () => moment().format('YYYY-MM-DD HH:mm');\n\nconst GekkoManager = function() {\n  this.gekkos = {};\n  this.instances = {};\n  this.loggers = {};\n\n  this.archivedGekkos = {};\n}\n\nGekkoManager.prototype.add = function({mode, config}) {\n  // set type\n  let type;\n  if(mode === 'realtime') {\n    if(config.market && config.market.type)\n      type = config.market.type;\n    else\n      type = 'watcher';\n  } else {\n    type = '';\n  }\n\n  let logType = type;\n  if(logType === 'leech') {\n    if(config.trader && config.trader.enabled)\n      logType = 'tradebot';\n    else\n      logType = 'papertrader';\n  }\n\n  const date = now().replace(' ', '-').replace(':', '-');\n  const n = (Math.random() + '').slice(3);\n  const id = `${date}-${logType}-${n}`;\n\n  // make sure we catch events happening inside te gekko instance\n  config.childToParent.enabled = true;\n\n  const state = {\n    mode,\n    config,\n    id,\n    type,\n    logType,\n    active: true,\n    stopped: false,\n    errored: false,\n    errorMessage: false,\n    events: {\n      initial: {},\n      latest: {}\n    },\n    start: moment()\n  }\n\n  this.gekkos[id] = state;\n\n  this.loggers[id] = new Logger(id);\n\n  // start the actual instance\n  this.instances[id] = pipelineRunner(mode, config, this.handleRawEvent(id));\n\n  // after passing API credentials to the actual instance we mask them\n  if(logType === 'trader') {\n    config.trader.key = '[REDACTED]';\n    config.trader.secret = '[REDACTED]';\n  }\n\n  console.log(`${now()} Gekko ${id} started.`);\n\n  broadcast({\n    type: 'gekko_new',\n    id,\n    state\n  });\n\n  return state;\n}\n\nGekkoManager.prototype.handleRawEvent = function(id) {\n  const logger = this.loggers[id];\n\n  return (err, event) => {\n    if(err) {\n      return this.handleFatalError(id, err);\n    }\n\n    if(!event) {\n      return;\n    }\n\n    if(event.log) {\n      return logger.write(event.message);\n    }\n\n    if(event.type) {\n      this.handleGekkoEvent(id, event);\n    }\n  }\n}\n\nGekkoManager.prototype.handleGekkoEvent = function(id, event) {\n  this.gekkos[id] = reduceState(this.gekkos[id], event);\n  broadcast({\n    type: 'gekko_event',\n    id,\n    event\n  });\n}\n\nGekkoManager.prototype.handleFatalError = function(id, err) {\n  const state = this.gekkos[id];\n\n  if(!state || state.errored || state.stopped)\n    return;\n\n  state.errored = true;\n  state.errorMessage = err;\n  console.error('RECEIVED ERROR IN GEKKO INSTANCE', id);\n  console.error(err);\n  broadcast({\n    type: 'gekko_error',\n    id,\n    error: err\n  });\n\n  this.archive(id);\n\n  if(state.logType === 'watcher') {\n    this.handleWatcherError(state, id);\n  }\n}\n\n// There might be leechers depending on this watcher, if so\n// figure out it we can safely start a new watcher without\n// the leechers noticing.\nGekkoManager.prototype.handleWatcherError = function(state, id) {\n  console.log(`${now()} A gekko watcher crashed.`);\n  if(!state.events.latest.candle) {\n    console.log(`${now()} was unable to start.`);\n  }\n\n  let latestCandleTime = moment.unix(0);\n  if(state.events.latest && state.events.latest.candle) {\n    latestCandleTime = state.events.latest.candle.start;\n  }\n  const leechers = _.values(this.gekkos)\n    .filter(gekko => {\n      if(gekko.type !== 'leech') {\n        return false;\n      }\n\n      if(_.isEqual(gekko.config.watch, state.config.watch)) {\n        return true;\n      }\n    });\n\n  if(leechers.length) {\n    console.log(`${now()} ${leechers.length} leecher(s) were depending on this watcher.`);\n    if(moment().diff(latestCandleTime, 'm') < 60) {\n      console.log(`${now()} Watcher had recent data, starting a new one in a minute.`);\n      // after a minute try to start a new one again..\n      setTimeout(() => {\n        const mode = 'realtime';\n        const config = state.config;\n        this.add({mode, config});\n      }, 1000 * 60);\n    } else {\n      console.log(`${now()} Watcher did not have recent data, killing its leechers.`);\n      leechers.forEach(leecher => this.stop(leecher.id));\n    }\n\n  }\n}\n\nGekkoManager.prototype.stop = function(id) {\n  if(!this.gekkos[id])\n    return false;\n\n  console.log(`${now()} stopping Gekko ${id}`);\n\n  this.gekkos[id].stopped = true;\n  this.gekkos[id].active = false;\n\n  // todo: graceful shutdown (via gekkoStream's\n  // finish function).\n  this.instances[id].kill();\n\n  broadcast({\n    type: 'gekko_stopped',\n    id\n  });\n\n  this.archive(id);\n\n  return true;\n}\n\nGekkoManager.prototype.archive = function(id) {\n  this.archivedGekkos[id] = this.gekkos[id];\n  this.archivedGekkos[id].stopped = true;\n  this.archivedGekkos[id].active = false;\n  delete this.gekkos[id];\n\n  broadcast({\n    type: 'gekko_archived',\n    id\n  });\n}\n\nGekkoManager.prototype.delete = function(id) {\n  if(this.gekkos[id]) {\n    throw new Error('Cannot delete a running Gekko, stop it first.');\n  }\n\n  if(!this.archivedGekkos[id]) {\n    throw new Error('Cannot delete unknown Gekko.');\n  }\n\n  console.log(`${now()} deleting Gekko ${id}`);\n\n  broadcast({\n    type: 'gekko_deleted',\n    id\n  });\n\n  delete this.archivedGekkos[id];\n\n  return true;\n}\n\nGekkoManager.prototype.archive = function(id) {\n  this.archivedGekkos[id] = this.gekkos[id];\n  this.archivedGekkos[id].stopped = true;\n  this.archivedGekkos[id].active = false;\n  delete this.gekkos[id];\n\n  broadcast({\n    type: 'gekko_archived',\n    id\n  });\n}\n\nGekkoManager.prototype.list = function() {\n  return { live: this.gekkos, archive: this.archivedGekkos };\n}\n\nmodule.exports = GekkoManager;"
  },
  {
    "path": "web/state/listManager.js",
    "content": "// manages a list of things that change over time\n// used for:\n// - The currently running imports\n// - etc..\nconst _ = require('lodash');\n\nvar ListManager = function() {\n  this._list = [];\n}\n\n// add an item to the list\nListManager.prototype.add = function(obj) {\n  if(!obj.id)\n    return false;\n  this._list.push(_.clone(obj));\n  return true;\n}\n\n// update some properties on an item\nListManager.prototype.update = function(id, updates) {\n  let item = this._list.find(i => i.id === id);\n  if(!item)\n    return false;\n  _.merge(item, updates);\n  return true;\n}\n\n// get an item from the list\nListManager.prototype.get = function(id) {\n  return this._list.find(i => i.id === id);\n}\n\n// push a value to a array property of an item\nListManager.prototype.push = function(id, prop, value) {\n  let item = this._list.find(i => i.id === id);\n  if(!item)\n    return false;\n\n  item[prop].push(value);\n  return true;\n}\n\n// delete an item from the list\nListManager.prototype.delete = function(id) {\n  let wasThere = this._list.find(i => i.id === id);\n  this._list = this._list.filter(i => i.id !== id);\n\n  if(wasThere)\n    return true;\n  else\n    return false;\n}\n\n// getter\nListManager.prototype.list = function() {\n  return this._list;\n}\n\nmodule.exports = ListManager;"
  },
  {
    "path": "web/state/logger.js",
    "content": "const fs = require('fs');\nconst _ = require('lodash');\n\nconst BASEPATH = __dirname + '/../../logs/';\n\nconst Logger = function(id) {\n\n  this.fileName = `${id}.log`;\n\n  this.writing = false;\n  this.queue = [];\n\n  _.bindAll(this);\n}\n\nLogger.prototype.write = function(line) {\n  if(!this.writing) {\n    this.writing = true;\n    fs.appendFile(\n      BASEPATH + this.fileName,\n      line + '\\n',\n      this.handleWriteCallback\n    );\n  } else\n    this.queue.push(line);\n}\n\nLogger.prototype.handleWriteCallback = function(err) {\n  if(err)\n    console.error(`ERROR WRITING LOG FILE ${this.fileName}:`, err);\n\n  this.writing = false;\n\n  if(_.size(this.queue))\n    this.write(this.queue.shift())\n}\n\nmodule.exports = Logger;"
  },
  {
    "path": "web/state/reduceState.js",
    "content": "// Redux/vuex inspired reducer, reduces an event into a gekko state.\n// NOTE: this is used by the backend as well as the frontend.\n\nconst skipInitialEvents = ['marketUpdate'];\nconst skipLatestEvents = ['marketStart', 'stratWarmupCompleted'];\nconst trackAllEvents = ['tradeCompleted', 'advice', 'roundtrip'];\n\nconst reduce = (state, event) => {\n  const type = event.type;\n  const payload = event.payload;\n\n  state = {\n    ...state,\n    latestUpdate: new Date()\n  }\n\n  if(trackAllEvents.includes(type)) {\n    if(!state.events[type]) {\n      state = {\n        ...state,\n        events: {\n          ...state.events,\n          [type]: [ payload ]\n        }\n      }\n    } else {\n      state = {\n        ...state,\n        events: {\n          ...state.events,\n          [type]: [ ...state.events[type], payload ]\n        }\n      }\n    }\n  }\n\n  if(!state.events.initial[type] && !skipInitialEvents.includes(type)) {\n    state = {\n      ...state,\n      events: {\n        ...state.events,\n        initial: {\n          ...state.events.initial,\n          [type]: payload\n        }\n      }\n    }\n  }\n\n  if(!skipLatestEvents.includes(type)) {\n    state = {\n      ...state,\n      events: {\n        ...state.events,\n        latest: {\n          ...state.events.latest,\n          [type]: payload\n        }\n      }\n    }\n  }\n\n  return state;\n}\n\n// export default reduce;\nmodule.exports = reduce;"
  },
  {
    "path": "web/vue/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/app'\n  ],\n  ignore: [\n    'node_modules',\n  ],\n  plugins : [\"transform-commonjs-es2015-modules\"]\n}\n"
  },
  {
    "path": "web/vue/dist/UIconfig.js",
    "content": "// Note: this file gets copied around, make sure you edit\n// the UIconfig located at `gekko/web/vue/dist/UIconfig.js`.\n\n// This config is used by both the frontend as well as the web server.\n// see https://gekko.wizb.it/docs/installation/installing_gekko_on_a_server.html#Configuring-Gekko\n\nconst CONFIG = {\n  headless: false,\n  api: {\n    host: '127.0.0.1',\n    port: 3000,\n    timeout: 120000 // 2 minutes\n  },\n  ui: {\n    ssl: false,\n    host: 'localhost',\n    port: 3000,\n    path: '/'\n  },\n  adapter: 'sqlite'\n}\n\nif(typeof window === 'undefined')\n  module.exports = CONFIG;\nelse\n  window.CONFIG = CONFIG;\n"
  },
  {
    "path": "web/vue/dist/app.5e99ecf7.js",
    "content": "(function(t){function e(e){for(var n,s,o=e[0],c=e[1],u=e[2],d=0,f=[];d<o.length;d++)s=o[d],r[s]&&f.push(r[s][0]),r[s]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(t[n]=c[n]);l&&l(e);while(f.length)f.shift()();return i.push.apply(i,u||[]),a()}function a(){for(var t,e=0;e<i.length;e++){for(var a=i[e],n=!0,o=1;o<a.length;o++){var c=a[o];0!==r[c]&&(n=!1)}n&&(i.splice(e--,1),t=s(s.s=a[0]))}return t}var n={},r={1:0},i=[];function s(e){if(n[e])return n[e].exports;var a=n[e]={i:e,l:!1,exports:{}};return t[e].call(a.exports,a,a.exports,s),a.l=!0,a.exports}s.m=t,s.c=n,s.d=function(t,e,a){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},s.r=function(t){\"undefined\"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(t,\"__esModule\",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&\"object\"===typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(s.r(a),Object.defineProperty(a,\"default\",{enumerable:!0,value:t}),2&e&&\"string\"!=typeof t)for(var n in t)s.d(a,n,function(e){return t[e]}.bind(null,n));return a},s.n=function(t){var e=t&&t.__esModule?function(){return t[\"default\"]}:function(){return t};return s.d(e,\"a\",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p=\"\";var o=window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[],c=o.push.bind(o);o.push=e,o=o.slice();for(var u=0;u<o.length;u++)e(o[u]);var l=c;i.push([26,0]),a()})({\"/Dpa\":function(t,e,a){\"use strict\";var n=a(\"VZpO\"),r=a.n(n);r.a},\"/vJE\":function(t,e,a){\"use strict\";var n=a(\"yuKf\"),r=a.n(n);r.a},\"0Bu0\":function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"table\",{staticClass:\"p1\"},[a(\"tr\",[a(\"th\",[t._v(\"amount of trades\")]),a(\"td\",[t._v(t._s(t.report.trades))])]),a(\"tr\",[a(\"th\",[t._v(\"sharpe ratio\")]),a(\"td\",[t._v(t._s(t.round2(t.report.sharpe)))])]),a(\"tr\",[a(\"th\",[t._v(\"start balance\")]),a(\"td\",[t._v(t._s(t.round(t.report.startBalance))+\" \"+t._s(t.report.currency))])]),a(\"tr\",[a(\"th\",[t._v(\"final balance\")]),a(\"td\",[t._v(t._s(t.round(t.report.balance))+\" \"+t._s(t.report.currency))])]),t._m(0)]),a(\"div\",{staticClass:\"big txt--right price\",class:t.profitClass},[t._v(t._s(t.round(t.report.relativeProfit))+\"%\")])])},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"tr\",[a(\"th\",[t._v(\"simulated profit\")])])}],i={props:[\"report\"],methods:{round2:function(t){return(+t).toFixed(2)},round:function(t){return(+t).toFixed(5)}},computed:{profitClass:function(){return this.report.relativeProfit>0?\"profit\":\"loss\"}}},s=i,o=(a(\"tr8z\"),a(\"KHd+\")),c=Object(o[\"a\"])(s,n,r,!1,null,null,null);e[\"a\"]=c.exports},\"0zrD\":function(t,e,a){\"use strict\";var n=a(\"jf14\"),r=a.n(n);r.a},26:function(t,e,a){t.exports=a(\"Vtdi\")},\"2A8w\":function(t,e,a){\"use strict\";var n=a(\"TDb6\"),r=a.n(n);r.a},\"2Yda\":function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain my2\"},[a(\"h3\",[t._v(\"Start a new gekko\")]),a(\"gekko-config-builder\",{on:{config:t.updateConfig}}),a(\"div\",{staticClass:\"hr\"}),t.config.valid?a(\"div\",{staticClass:\"txt--center\"},[t.pendingStratrunner?t._e():a(\"a\",{staticClass:\"w100--s my1 btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.start(e)}}},[t._v(\"Start\")]),t.pendingStratrunner?a(\"spinner\"):t._e()],1):t._e()],1)},r=[],i=(a(\"Z2Ku\"),a(\"L9s1\"),a(\"dRSK\"),a(\"LvDl\")),s=a.n(i),o=a(\"Kw5r\"),c=a(\"wiDz\"),u=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd contain\"},[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"h3\",[t._v(\"Market\")]),a(\"market-picker\",{attrs:{\"only-tradable\":t.isTradebot},on:{market:t.updateMarketConfig}})],1),a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"type-picker\",{on:{type:t.updateType}})],1)]),\"market watcher\"!==t.type?[a(\"div\",{staticClass:\"hr\"}),a(\"strat-picker\",{staticClass:\"contain my2\",on:{stratConfig:t.updateStrat}}),\"paper trader\"===t.type?a(\"div\",{staticClass:\"hr\"}):t._e(),\"paper trader\"===t.type?a(\"paper-trader\",{on:{settings:t.updatePaperTrader}}):t._e()]:t._e()],2)},l=[],d=(a(\"91GP\"),a(\"6BxS\")),f=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"h3\",[t._v(\"Type\")]),[a(\"label\",{staticClass:\"wrapper\",attrs:{for:\"type\"}},[t._v(\"What do you want to do with gekko?\")]),a(\"form\",{staticClass:\"radio grd\"},t._l(t.types,function(e,n){return a(\"div\",{staticClass:\"grd-row m1\"},[a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.selectedTypeIndex,expression:\"selectedTypeIndex\"}],staticClass:\"grd-row-col-1-6\",attrs:{type:\"radio\"},domProps:{value:n,checked:t._q(t.selectedTypeIndex,n)},on:{change:function(e){t.selectedTypeIndex=n}}}),a(\"label\",{staticClass:\"grd-row-col-5-6\",attrs:{for:n}},[t._v(t._s(e))])])}))]],2)},h=[],m={created:function(){this.emitType()},data:function(){return{types:[\"paper trader\",\"market watcher\",\"tradebot\"],selectedTypeIndex:0}},methods:{emitType:function(){this.$emit(\"type\",this.type)}},watch:{type:function(){this.emitType()}},computed:{type:function(){return this.types[this.selectedTypeIndex]}}},v=m,p=(a(\"wVPO\"),a(\"KHd+\")),g=Object(p[\"a\"])(v,f,h,!1,null,null,null),_=g.exports,k=a(\"6Wkr\"),y=a(\"rloZ\"),w={created:function(){var t=this;Object(c[\"a\"])(\"configPart/candleWriter\",function(e,a){t.candleWriter=toml.parse(a.part)}),Object(c[\"a\"])(\"configPart/performanceAnalyzer\",function(e,a){t.performanceAnalyzer=toml.parse(a.part),t.performanceAnalyzer.enabled=!0})},data:function(){return{market:{},range:{},type:\"\",strat:{},paperTrader:{},candleWriter:{},performanceAnalyzer:{}}},components:{marketPicker:d[\"a\"],typePicker:_,stratPicker:k[\"a\"],paperTrader:y[\"a\"]},computed:{isTradebot:function(){return\"tradebot\"===this.type},config:function(){var t={};return Object.assign(t,this.market,this.strat,{paperTrader:this.paperTrader},{candleWriter:this.candleWriter},{type:this.type},{performanceAnalyzer:this.performanceAnalyzer}),this.isTradebot&&(delete t.paperTrader,t.trader={enabled:!0}),t.valid=this.validConfig(t),t}},methods:{validConfig:function(t){if(\"market watcher\"===t.type)return!0;if(!t.tradingAdvisor)return!1;if(s.a.isNaN(t.tradingAdvisor.candleSize))return!1;if(0==t.tradingAdvisor.candleSize)return!1;var e=t.tradingAdvisor.method;return!s.a.isEmpty(t[e])},updateMarketConfig:function(t){this.market=t,this.emitConfig()},updateType:function(t){this.type=t,this.emitConfig()},updateStrat:function(t){this.strat=t,this.emitConfig()},updatePaperTrader:function(t){this.paperTrader=t,this.paperTrader.enabled=!0,this.emitConfig()},emitConfig:function(){this.$emit(\"config\",this.config)}}},b=w,C=(a(\"YEdZ\"),Object(p[\"a\"])(b,u,l,!1,null,null,null)),x=C.exports,S=a(\"MB/c\"),T={components:{gekkoConfigBuilder:x,spinner:S[\"a\"]},data:function(){return{pendingStratrunner:!1,config:{}}},computed:{gekkos:function(){return this.$store.state.gekkos},watchConfig:function(){var t=s.a.pick(this.config,\"watch\",\"candleWriter\"),e=o[\"a\"].util.extend({},t);return e.type=\"market watcher\",e.mode=\"realtime\",e},requiredHistoricalData:function(){if(this.config.tradingAdvisor&&this.config.valid){var t=this.config.tradingAdvisor;return t.candleSize*t.historySize}},gekkoConfig:function(){var t;if(this.existingMarketWatcher){if(this.requiredHistoricalData){var e=moment().utc().startOf(\"minute\").subtract(this.requiredHistoricalData,\"minutes\").unix(),a=moment.utc(this.existingMarketWatcher.events.initial.candle.start).unix();t=moment.unix(Math.max(e,a)).utc().format()}else t=moment().utc().startOf(\"minute\").format();var n=o[\"a\"].util.extend({market:{type:\"leech\",from:t},mode:\"realtime\"},this.config);return n}},existingMarketWatcher:function(){var t=o[\"a\"].util.extend({},this.watchConfig.watch);return s.a.find(this.gekkos,{config:{watch:t}})},exchange:function(){return this.watchConfig.watch.exchange},existingTradebot:function(){var t=this;return s.a.find(this.gekkos,function(e){return\"tradebot\"===e.logType&&e.config.watch.exchange===t.exchange})},availableApiKeys:function(){return this.$store.state.apiKeys}},watch:{existingMarketWatcher:function(t,e){var a=this;if(this.pendingStratrunner){var n=this.existingMarketWatcher;n.events.latest.candle&&(this.pendingStratrunner=!1,this.startGekko(function(t,e){a.$router.push({path:\"/live-gekkos/\".concat(e.id)})}))}}},methods:{updateConfig:function(t){this.config=t},start:function(){var t=this;if(\"tradebot\"===this.config.type){if(this.existingTradebot){var e=\"You already have a tradebot running on this exchange\";return e+=\", you can only run one tradebot per exchange.\",alert(e)}if(!this.availableApiKeys.includes(this.exchange))return alert(\"Please first configure API keys for this exchange in the config page.\")}\"market watcher\"===this.config.type?this.existingMarketWatcher?(alert(\"This market is already being watched, redirecting you now...\"),this.$router.push({path:\"/live-gekkos/\".concat(this.existingMarketWatcher.id)})):this.startWatcher(function(e,a){t.$router.push({path:\"/live-gekkos/\".concat(a.id)})}):this.existingMarketWatcher?this.startGekko(this.routeToGekko):this.startWatcher(function(e,a){t.pendingStratrunner=a.id})},routeToGekko:function(t,e){if(t||e.error)return console.error(t,e.error);this.$router.push({path:\"/live-gekkos/\".concat(e.id)})},startWatcher:function(t){Object(c[\"b\"])(\"startGekko\",this.watchConfig,t)},startGekko:function(t){Object(c[\"b\"])(\"startGekko\",this.gekkoConfig,t)}}},E=T,P=(a(\"2A8w\"),Object(p[\"a\"])(E,n,r,!1,null,null,null));e[\"a\"]=P.exports},\"2rY9\":function(t,e,a){\"use strict\";var n=a(\"SWS5\"),r=a.n(n);r.a},\"5/bm\":function(t,e,a){},\"5shn\":function(t,e,a){\"use strict\";var n=a(\"DlQD\"),r=a.n(n),i=r.a,s=new i.Renderer;s.link=function(t,e,a){var n,r,i;return n=/^https?:\\/\\/.+$/.test(t),r=n||\"newWindow\"===e,i='<a href=\"'+t+'\"',r&&(i+=' target=\"_blank\"'),e&&\"newWindow\"!==e&&(i+=' title=\"'+e+'\"'),i+\">\"+a+\"</a>\"},i.setOptions({renderer:s}),e[\"a\"]=i},\"6BxS\":function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"div\",{staticClass:\"mx1\"},[a(\"label\",{staticClass:\"wrapper\",attrs:{for:\"exchange\"}},[t._v(\"Exchange:\")]),a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.exchange,expression:\"exchange\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.exchange=e.target.multiple?a:a[0]}}},t._l(t.exchanges,function(e,n){return a(\"option\",[t._v(t._s(n))])}))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"label\",{attrs:{for:\"currency\"}},[t._v(\"Currency:\")]),a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.currency,expression:\"currency\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.currency=e.target.multiple?a:a[0]}}},t._l(t.currencies,function(e){return a(\"option\",[t._v(t._s(e))])}))])]),a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"label\",{attrs:{for:\"asset\"}},[t._v(\"Asset:\")]),a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.asset,expression:\"asset\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.asset=e.target.multiple?a:a[0]}}},t._l(t.assets,function(e){return a(\"option\",[t._v(t._s(e))])}))])])])])},r=[],i=(a(\"rGqo\"),a(\"yt8O\"),a(\"f3/d\"),a(\"91GP\"),a(\"LvDl\")),s=a.n(i),o=(a(\"YIjs\"),a(\"FhOJ\"),a(\"wiDz\"),{props:[\"onlyTradable\",\"onlyImportable\"],data:function(){return{exchange:\"poloniex\",currency:\"USDT\",asset:\"BTC\"}},created:function(){this.emitConfig()},computed:{exchanges:function(){var t=Object.assign({},this.$store.state.exchanges);return!s.a.isEmpty(t)&&(this.onlyTradable&&s.a.each(t,function(e,a){e.tradable||delete t[a]}),this.onlyImportable&&s.a.each(t,function(e,a){e.importable||delete t[a]}),t)},markets:function(){return this.exchanges?this.exchanges[this.exchange]:null},assets:function(){return this.exchanges?this.exchanges[this.exchange].markets[this.currency]:null},currencies:function(){return this.exchanges?s.a.keys(this.exchanges[this.exchange].markets):null},watchConfig:function(){return{watch:{exchange:this.exchange,currency:this.currency,asset:this.asset}}}},watch:{currency:function(){this.emitConfig()},asset:function(){this.emitConfig()},market:function(){this.emitConfig()},exchanges:function(){this.emitConfig()},exchange:function(){this.emitConfig()}},methods:{emitConfig:function(){this.$emit(\"market\",this.watchConfig)}}}),c=o,u=a(\"KHd+\"),l=Object(u[\"a\"])(c,n,r,!1,null,null,null);e[\"a\"]=l.exports},\"6Wkr\":function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd\"},[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6 px1\"},[a(\"h3\",[t._v(\"Strategy\")]),a(\"div\",[a(\"label\",{staticClass:\"wrapper\",attrs:{for:\"strat\"}},[t._v(\"Strategy:\")]),a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.strategy,expression:\"strategy\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.strategy=e.target.multiple?a:a[0]}}},t._l(t.strategies,function(e){return a(\"option\",[t._v(t._s(e.name))])}))])]),a(\"div\",[a(\"label\",{attrs:{for:\"candleSize\"}},[t._v(\"Candle Size\")]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.rawCandleSize,expression:\"rawCandleSize\"}],domProps:{value:t.rawCandleSize},on:{input:function(e){e.target.composing||(t.rawCandleSize=e.target.value)}}})]),a(\"div\",{staticClass:\"grd-row-col-3-6 align\"},[a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.candleSizeUnit,expression:\"candleSizeUnit\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.candleSizeUnit=e.target.multiple?a:a[0]}}},[a(\"option\",[t._v(\"minutes\")]),a(\"option\",[t._v(\"hours\")]),a(\"option\",[t._v(\"days\")])])])])])]),a(\"div\",[a(\"label\",{attrs:{for:\"historySize\"}},[t._v(\"Warmup period (in \"+t._s(t.rawCandleSize)+\" \"+t._s(t.singularCandleSizeUnit)+\" candles):\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.historySize,expression:\"historySize\"}],domProps:{value:t.historySize},on:{input:function(e){e.target.composing||(t.historySize=e.target.value)}}}),a(\"em\",{staticClass:\"label-like\"},[t._v(\"(will use \"+t._s(t.humanizeDuration(t.candleSize*t.historySize*1e3*60))+\" of data as history)\")])])]),a(\"div\",{staticClass:\"grd-row-col-3-6 px1\"},[a(\"div\",[a(\"h3\",[t._v(\"Parameters\")]),a(\"p\",[t._v(t._s(t.strategy)+\" Parameters:\")]),a(\"textarea\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.rawStratParams,expression:\"rawStratParams\"}],staticClass:\"params\",domProps:{value:t.rawStratParams},on:{input:function(e){e.target.composing||(t.rawStratParams=e.target.value)}}}),t.rawStratParamsError?a(\"p\",{staticClass:\"bg--red p1\"},[t._v(t._s(t.rawStratParamsError.message))]):t._e()])])])])},r=[],i=(a(\"dRSK\"),a(\"LvDl\")),s=a.n(i),o=a(\"wiDz\"),c={data:function(){return{strategies:[],candleSizeUnit:\"hours\",rawCandleSize:1,strategy:\"MACD\",historySize:10,rawStratParams:\"\",rawStratParamsError:!1,emptyStrat:!1,stratParams:{}}},created:function(){var t=this;Object(o[\"a\"])(\"strategies\",function(e,a){t.strategies=a,s.a.each(t.strategies,function(t){t.empty=\"\"===t.params}),t.rawStratParams=s.a.find(t.strategies,{name:t.strategy}).params,t.emptyStrat=s.a.find(t.strategies,{name:t.strategy}).empty,t.emitConfig()})},watch:{strategy:function(t){t=s.a.find(this.strategies,{name:t}),this.rawStratParams=t.params,this.emptyStrat=t.empty,this.emitConfig()},candleSize:function(){this.emitConfig()},historySize:function(){this.emitConfig()},rawStratParams:function(){this.emitConfig()}},computed:{candleSize:function(){return\"minutes\"===this.candleSizeUnit?this.rawCandleSize:\"hours\"===this.candleSizeUnit?60*this.rawCandleSize:\"days\"===this.candleSizeUnit?60*this.rawCandleSize*24:void 0},singularCandleSizeUnit:function(){return this.candleSizeUnit.slice(0,-1)},config:function(){var t={tradingAdvisor:{enabled:!0,method:this.strategy,candleSize:+this.candleSize,historySize:+this.historySize}};return this.emptyStrat?t[this.strategy]={__empty:!0}:t[this.strategy]=this.stratParams,t}},methods:{humanizeDuration:function(t){return window.humanizeDuration(t)},emitConfig:function(){this.parseParams(),this.$emit(\"stratConfig\",this.config)},parseParams:function(){try{this.stratParams=toml.parse(this.rawStratParams),this.rawStratParamsError=!1}catch(t){this.rawStratParamsError=t,this.stratParams={}}}}},u=c,l=(a(\"tr8f\"),a(\"KHd+\")),d=Object(l[\"a\"])(u,n,r,!1,null,null,null);e[\"a\"]=d.exports},\"7LpK\":function(t,e,a){},\"8KAT\":function(t,e,a){},\"9RND\":function(t){t.exports={name:\"gekko\",version:\"0.6.8\",description:\"A bitcoin trading bot for auto trading at various exchanges\",keywords:[\"trading\",\"bot\",\"bitcoin\",\"TA\",\"finance\"],scripts:{test:\"./node_modules/.bin/mocha test/*.js --recursive test -u tdd --reporter spec\",start:\"node ./gekko --config config.js --ui\"},author:\"Mike van Rossum <mike@mvr.me>\",dependencies:{async:\"2.1.2\",\"bitfinex-api-node\":\"^1.2.1\",\"co-fs\":\"^1.2.0\",commander:\"^2.13.0\",gekko:\"0.0.9\",\"humanize-duration\":\"^3.10.0\",koa:\"^1.2.0\",\"koa-bodyparser\":\"^2.2.0\",\"koa-cors\":\"0.0.16\",\"koa-logger\":\"^1.3.0\",\"koa-router\":\"^5.4.0\",\"koa-static\":\"^2.0.0\",lodash:\"2.x\",moment:\"^2.20.1\",opn:\"^4.0.2\",\"promisify-node\":\"^0.5.0\",\"prompt-lite\":\"0.1.1\",relieve:\"^2.1.3\",retry:\"^0.10.1\",semver:\"5.4.1\",sqlite3:\"^4.0.4\",\"stats-lite\":\"^2.0.4\",\"tiny-promisify\":\"^0.1.1\",toml:\"^2.3.0\",ws:\"^6.0.0\"},devDependencies:{chai:\"^4.1.2\",mocha:\"^5.0.0\",proxyquire:\"^1.7.10\",request:\"^2.83.0\",\"request-promise\":\"^4.2.2\",sinon:\"^4.2.0\"},engines:{node:\">=8.11.2\"},license:\"MIT\",repository:{type:\"git\",url:\"https://github.com/askmike/gekko.git\"}}},CyGp:function(t,e,a){\"use strict\";var n=a(\"jTvs\"),r=a.n(n);r.a},EAJ1:function(t,e,a){},EDI0:function(t,e,a){},EfWa:function(t,e,a){},FhOJ:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"h3\",[t._v(\"Daterange\")]),a(\"div\",[a(\"label\",{attrs:{for:\"from\"}},[t._v(\"From\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.from,expression:\"from\"}],domProps:{value:t.from},on:{input:function(e){e.target.composing||(t.from=e.target.value)}}})]),a(\"div\",[a(\"label\",{attrs:{for:\"to\"}},[t._v(\"To\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.to,expression:\"to\"}],domProps:{value:t.to},on:{input:function(e){e.target.composing||(t.to=e.target.value)}}})])])},r=[],i=(a(\"LvDl\"),a(\"wiDz\"),{data:function(){return{from:\"\",to:\"\"}},created:function(){var t=moment().startOf(\"minute\"),e=t.clone().subtract(3,\"months\");this.to=this.fmt(t),this.from=this.fmt(e),this.emitRange()},methods:{fmtTs:function(t){return moment.unix(t).utc()},fmt:function(t){return t.utc().format(\"YYYY-MM-DD HH:mm\")},emitRange:function(){this.$emit(\"range\",{from:this.fmtTs(this.from),to:this.fmtTs(this.to)})},emitManualEntry:function(){if(this.from.length<\"4\"||this.from.length<\"4\")return this.$emit(\"range\",{});var t=moment.utc(this.from),e=moment.utc(this.to);t.isValid()&&e.isValid()?this.$emit(\"range\",{from:this.fmt(t),to:this.fmt(e)}):this.$emit(\"range\",{})}},watch:{from:function(){this.emitManualEntry()},to:function(){this.emitManualEntry()},config:function(){this.scanned=!1},tab:function(){this.scanned=!1,this.$emit(\"range\",{})},selectedRangeIndex:function(){var t=this.ranges[this.selectedRangeIndex];t&&this.emitRange(t)}}}),s=i,o=(a(\"TPp/\"),a(\"KHd+\")),c=Object(o[\"a\"])(s,n,r,!1,null,null,null);e[\"a\"]=c.exports},\"H+ir\":function(t,e,a){\"use strict\";var n=a(\"5/bm\"),r=a.n(n);r.a},Kd0R:function(t,e,a){},\"MB/c\":function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"spinner\"},[a(\"div\",{staticClass:\"rect1\"}),a(\"div\",{staticClass:\"rect2\"}),a(\"div\",{staticClass:\"rect3\"}),a(\"div\",{staticClass:\"rect4\"})])}],i={},s=i,o=(a(\"q431\"),a(\"KHd+\")),c=Object(o[\"a\"])(s,n,r,!1,null,null,null);e[\"a\"]=c.exports},Pf3K:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{attrs:{id:\"app\"}},[a(\"top\"),a(\"div\",{staticClass:\"fill\"},[a(\"router-view\",{staticClass:\"view\"})],1),a(\"bottom\"),a(\"modal\")],1)},r=[],i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"div\",{attrs:{id:\"top\"}}),t._m(0),a(\"nav\",{staticClass:\"bg--light-gray\"},[a(\"div\",{staticClass:\"menu contain\"},[a(\"router-link\",{staticClass:\"py1\",attrs:{to:\"/home\"}},[t._v(\"Home\")]),a(\"router-link\",{staticClass:\"py1\",attrs:{to:\"/live-gekkos\"}},[t._v(\"Live Gekkos\")]),a(\"router-link\",{staticClass:\"py1\",attrs:{to:\"/backtest\"}},[t._v(\"Backtest\")]),a(\"router-link\",{staticClass:\"py1\",attrs:{to:\"/data\"}},[t._v(\"Local data\")]),a(\"router-link\",{staticClass:\"py1\",attrs:{to:\"/config\"}},[t._v(\"Config\")]),a(\"a\",{staticClass:\"py1\",attrs:{href:\"https://gekko.wizb.it/docs/introduction/about_gekko.html\",target:\"_blank\"}},[t._v(\"Documentation\")])],1)])])},s=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"header\",{staticClass:\"bg--off-white grd\"},[a(\"div\",{staticClass:\"contain grd-row\"},[a(\"h3\",{staticClass:\"py1 px2 col-2\"},[t._v(\"Gekko UI\")])])])}],o={},c=o,u=(a(\"uMTv\"),a(\"KHd+\")),l=Object(u[\"a\"])(c,i,s,!1,null,null,null),d=l.exports,f=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"footer\",{staticClass:\"p2 bg--off-white\"},[a(\"div\",{staticClass:\"contain\"},[t._m(0),a(\"p\",[t._v(\"Using Gekko v\"+t._s(t.version.gekko)+\" and Gekko UI v\"+t._s(t.version.ui)+\".\")])])])},h=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"p\",[a(\"em\",[t._v(\"Use Gekko at your own risk.\")])])}],m=a(\"kiQV\"),v=a(\"9RND\"),p=v,g=m,_={data:function(){return{version:{gekko:p.version,ui:g.version}}}},k=_,y=Object(u[\"a\"])(k,f,h,!1,null,null,null),w=y.exports,b=function(){var t=this,e=t.$createElement,a=t._self._c||e;return t.active?a(\"div\",[a(\"div\",{attrs:{id:\"modal-background\"}}),a(\"div\",{staticClass:\"modal\",attrs:{id:\"modal\"}},[a(\"div\",{staticClass:\"modal-guts\",domProps:{innerHTML:t._s(t.content)}})])]):t._e()},C=[],x=a(\"5shn\"),S={disconnected:Object(x[\"a\"])(\"\\n\\n## Disconnected\\n\\nSomething happened to either Gekko or the connection.\\nPlease check the terminal where Gekko is running or\\nyour network connection.\\n\\n*This message is shown when the UI is unable to open a websocket connection with the Gekko Server.*\\n\\n  \")},T={computed:{active:function(){return!this.$store.state.warnings.connected},content:function(){return this.$store.state.warnings.connected?\"\":S.disconnected}}},E=T,P=(a(\"TfKe\"),Object(u[\"a\"])(E,b,C,!1,null,null,null)),A=P.exports,j={name:\"app\",components:{top:d,bottom:w,modal:A}},D=j,O=(a(\"ZL7j\"),Object(u[\"a\"])(D,n,r,!1,null,null,null));e[\"a\"]=O.exports},Q2AE:function(t,e,a){\"use strict\";var n={};a.r(n),a.d(n,\"addImport\",function(){return d}),a.d(n,\"syncImports\",function(){return f}),a.d(n,\"updateImport\",function(){return h});var r={};a.r(r),a.d(r,\"syncGekkos\",function(){return C}),a.d(r,\"addGekko\",function(){return x}),a.d(r,\"updateGekko\",function(){return S}),a.d(r,\"archiveGekko\",function(){return T}),a.d(r,\"errorGekko\",function(){return E}),a.d(r,\"deleteGekko\",function(){return P});var i={};a.r(i),a.d(i,\"setGlobalWarning\",function(){return A});var s={};a.r(s),a.d(s,\"syncApiKeys\",function(){return j}),a.d(s,\"syncExchanges\",function(){return D});a(\"VRzm\");var o=a(\"Kw5r\"),c=a(\"L2JU\"),u=a(\"LvDl\"),l=a.n(u),d=(a(\"INYr\"),function(t,e){return t.imports.push(e),t}),f=function(t,e){return t.imports=e,t},h=function(t,e){var a=t.imports.findIndex(function(t){return t.id===e.import_id}),n=t.imports[a];if(!n)return t;var r=o[\"a\"].util.extend(n,e.updates);return o[\"a\"].set(t.imports,a,r),t},m=a(\"oyJW\"),v=a(\"yT7P\"),p=a(\"iv4g\"),g=(a(\"Z2Ku\"),[\"marketUpdate\"]),_=[\"marketStart\",\"stratWarmupCompleted\"],k=[\"tradeCompleted\",\"advice\",\"roundtrip\"],y=function(t,e){var a=e.type,n=e.payload;return t=Object(v[\"a\"])({},t,{latestUpdate:new Date}),k.includes(a)&&(t=t.events[a]?Object(v[\"a\"])({},t,{events:Object(v[\"a\"])({},t.events,Object(m[\"a\"])({},a,Object(p[\"a\"])(t.events[a]).concat([n])))}):Object(v[\"a\"])({},t,{events:Object(v[\"a\"])({},t.events,Object(m[\"a\"])({},a,[n]))})),t.events.initial[a]||g.includes(a)||(t=Object(v[\"a\"])({},t,{events:Object(v[\"a\"])({},t.events,{initial:Object(v[\"a\"])({},t.events.initial,Object(m[\"a\"])({},a,n))})})),_.includes(a)||(t=Object(v[\"a\"])({},t,{events:Object(v[\"a\"])({},t.events,{latest:Object(v[\"a\"])({},t.events.latest,Object(m[\"a\"])({},a,n))})})),t},w=y,b=w,C=function(t,e){return e?(t.gekkos=e.live,t.archivedGekkos=e.archive,t):t},x=function(t,e){return t.gekkos=Object(v[\"a\"])({},t.gekkos,Object(m[\"a\"])({},e.id,e)),t},S=function(t,e){return e.id&&l.a.has(t.gekkos,e.id)?(t.gekkos=Object(v[\"a\"])({},t.gekkos,Object(m[\"a\"])({},e.id,b(t.gekkos[e.id],e.event))),t):console.error(\"cannot update unknown gekko..\")},T=function(t,e){return l.a.has(t.gekkos,e)?(t.archivedGekkos=Object(v[\"a\"])({},t.archivedGekkos,Object(m[\"a\"])({},e,Object(v[\"a\"])({},t.gekkos[e],{stopped:!0,active:!1}))),t.gekkos=l.a.omit(t.gekkos,e),t):console.error(\"cannot archive unknown gekko..\")},E=function(t,e){return l.a.has(t.gekkos,e.id)?(t.gekkos=Object(v[\"a\"])({},t.gekkos,Object(m[\"a\"])({},e.id,Object(v[\"a\"])({},t.gekkos[e.id],{errored:!0,errorMessage:e.error}))),t):console.error(\"cannot error unknown gekko..\")},P=function(t,e){return l.a.has(t.archivedGekkos,e)?(t.archivedGekkos=l.a.omit(t.archivedGekkos,e),t):console.error(\"cannot delete unknown gekko..\")},A=function(t,e){return t.warnings[e.key]=e.value,t},j=function(t,e){return o[\"a\"].set(t,\"apiKeys\",e),t},D=function(t,e){return o[\"a\"].set(t,\"exchanges\",e),t};o[\"a\"].use(c[\"a\"]);var O=!1,z={};l.a.merge(z,n),l.a.merge(z,r),l.a.merge(z,i),l.a.merge(z,s);e[\"a\"]=new c[\"a\"].Store({state:{warnings:{connected:!0},imports:[],gekkos:{},archivedGekkos:{},connection:{disconnected:!1,reconnected:!1},apiKeys:[],exchanges:{}},mutations:z,strict:O})},Q6eY:function(t,e,a){\"use strict\";var n=a(\"SDwi\"),r=a.n(n);r.a},SDwi:function(t,e,a){},SWS5:function(t,e,a){},T0Mt:function(t,e,a){\"use strict\";var n=a(\"pd3X\"),r=a.n(n);r.a},TDb6:function(t,e,a){},\"TPp/\":function(t,e,a){\"use strict\";var n=a(\"7LpK\"),r=a.n(n);r.a},TfKe:function(t,e,a){\"use strict\";var n=a(\"ZpQ2\"),r=a.n(n);r.a},UeuA:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{class:{clickable:!t.isClicked},attrs:{id:\"chartWrapper\"}},[a(\"div\",{staticClass:\"shield\",on:{click:function(e){return e.preventDefault(),t.click(e)}}}),a(\"svg\",{attrs:{id:\"chart\",width:\"960\",height:t.height}})])},r=[],i=a(\"k5N+\"),s=a(\"LvDl\"),o=a.n(s),c=function(t,e,a){var n=function(t){return o.a.isNumber(t)?moment.unix(t).utc().toDate():moment.utc(t).toDate()},r=e.map(function(t){return{price:t.price,date:n(t.date),action:t.action}}),s=t.map(function(t){return{price:t.open,date:n(t.start)}}),c=s.map(function(t){return+t.date}),u=s.map(function(t){return+t.price}),l=d3.select(\"#chart\");l.attr(\"width\",window.innerWidth-20);var d={top:20,right:20,bottom:110,left:40},f=a-d.top-d.bottom,h={top:a-70,right:20,bottom:30,left:40},m=+l.attr(\"width\")-d.left-d.right,v=a-h.top-h.bottom,p=d3.scaleUtc().range([0,m]),g=d3.scaleUtc().range([0,m]),_=d3.scaleLinear().range([f,0]),k=d3.scaleLinear().range([v,0]),y=d3.axisBottom(p),w=d3.axisBottom(g),b=d3.axisLeft(_).ticks(a/50),C=d3.brushX().extent([[0,0],[m,v]]).on(\"brush end\",j),x=d3.zoom().scaleExtent([1,100]).translateExtent([[0,0],[m,f]]).extent([[0,0],[m,f]]).on(\"zoom\",O),S=d3.line().x(function(t){return p(t.date)}).y(function(t){return _(t.price)}),T=d3.line().x(function(t){return g(t.date)}).y(function(t){return k(t.price)});l.append(\"defs\").append(\"clipPath\").attr(\"id\",\"clip\").append(\"rect\").attr(\"width\",m).attr(\"height\",f);var E=l.append(\"g\").attr(\"class\",\"focus\").attr(\"transform\",\"translate(\"+d.left+\",\"+d.top+\")\"),P=l.append(\"g\").attr(\"class\",\"context\").attr(\"transform\",\"translate(\"+h.left+\",\"+h.top+\")\");p.domain(d3.extent(s,function(t){return t.date})),_.domain([.99*d3.min(u),1.01*d3.max(u)]),g.domain(p.domain()),k.domain(_.domain()),E.append(\"path\").datum(s).attr(\"class\",\"line price\").attr(\"d\",S),E.append(\"g\").attr(\"class\",\"axis axis--x\").attr(\"transform\",\"translate(0,\"+f+\")\").call(y),E.append(\"g\").attr(\"class\",\"axis axis--y\").call(b),P.append(\"path\").datum(s).attr(\"class\",\"line\").attr(\"d\",T),P.append(\"g\").attr(\"class\",\"axis axis--x\").attr(\"transform\",\"translate(0,\"+v+\")\").call(w);var A=l.append(\"g\").attr(\"transform\",\"translate(\"+d.left+\",\"+d.top+\")\").selectAll(\"circle\").data(r).enter().append(\"circle\").attr(\"class\",function(t){return t.action}).attr(\"cx\",function(t){return p(t.date)}).attr(\"cy\",function(t){return _(t.price)}).attr(\"r\",5);P.append(\"g\").selectAll(\"circle\").data(r).enter().append(\"circle\").attr(\"class\",function(t){return t.action}).attr(\"cx\",function(t){return g(t.date)}).attr(\"cy\",function(t){return k(t.price)}).attr(\"r\",3);function j(){if(!d3.event.sourceEvent||\"zoom\"!==d3.event.sourceEvent.type){var t=d3.event.selection||g.range();p.domain(t.map(g.invert,g)),D(p.domain()),l.select(\".axis--y\").call(b),A.attr(\"cx\",function(t){return p(t.date)}).attr(\"cy\",function(t){return _(t.price)}),E.select(\".line\").attr(\"d\",S),E.select(\".axis--x\").call(y),l.select(\".zoom\").call(x.transform,d3.zoomIdentity.scale(m/(t[1]-t[0])).translate(-t[0],0))}}function D(t){var e=Object(i[\"a\"])(t,2),a=e[0],n=e[1],r=o.a.sortedIndex(c,a),s=o.a.sortedIndex(c,n),l=u.slice(r,s);_.domain([.9995*d3.min(l),1.0005*d3.max(l)])}function O(){if(!d3.event.sourceEvent||\"brush\"!==d3.event.sourceEvent.type){var t=d3.event.transform;D(t.rescaleX(g).domain()),l.select(\".axis--y\").call(b),p.domain(t.rescaleX(g).domain()),E.select(\".line\").attr(\"d\",S),A.attr(\"cx\",function(t){return p(t.date)}).attr(\"cy\",function(t){return _(t.price)}),E.select(\".axis--x\").call(y),P.select(\".brush\").call(C.move,p.range().map(t.invertX,t))}}P.append(\"g\").attr(\"class\",\"brush\").call(C).call(C.move,p.range()),l.append(\"rect\").attr(\"class\",\"zoom\").attr(\"width\",m).attr(\"height\",f).attr(\"transform\",\"translate(\"+d.left+\",\"+d.top+\")\").call(x)},u=(a(\"dRSK\"),function(t){d3.select(\"#chart\").append(\"text\").attr(\"class\",\"message\").attr(\"x\",150).attr(\"y\",150).text(t)}),l=4,d={props:[\"data\",\"height\"],data:function(){return{isClicked:!1}},watch:{data:function(){this.render()}},created:function(){setTimeout(this.render,100)},beforeDestroy:function(){this.remove()},methods:{click:function(){this.isClicked=!0},render:function(){this.remove(),_.size(this.data.candles)<l?u(\"Not enough data to spawn chart\"):c(this.data.candles,this.data.trades,this.height)},remove:function(){d3.select(\"#chart\").html(\"\")}}},f=d,h=(a(\"T0Mt\"),a(\"KHd+\")),m=Object(h[\"a\"])(f,n,r,!1,null,null,null);e[\"a\"]=m.exports},\"Ug4+\":function(t,e,a){},VZpO:function(t,e,a){},Vtdi:function(t,e,a){\"use strict\";a.r(e),function(t){a(\"VRzm\");var e=a(\"Kw5r\"),n=a(\"Pf3K\"),r=a(\"jE9Z\"),i=a(\"Q2AE\"),s=a(\"bqjz\"),o=a(\"ldlP\"),c=a(\"dHeD\"),u=a(\"jloR\"),l=a(\"g298\"),d=a(\"WqVH\"),f=a(\"hGnM\"),h=a(\"2Yda\"),m=a(\"mf2E\"),v=a(\"gYof\");e[\"a\"].use(r[\"a\"]);var p=new r[\"a\"]({mode:\"hash\",base:t,routes:[{path:\"/\",redirect:\"/home\"},{path:\"/home\",component:o[\"a\"]},{path:\"/backtest\",component:s[\"a\"]},{path:\"/config\",component:d[\"a\"]},{path:\"/data\",component:c[\"a\"]},{path:\"/data/importer\",component:u[\"a\"]},{path:\"/data/importer/import/:id\",component:l[\"a\"]},{path:\"/live-gekkos\",component:f[\"a\"]},{path:\"/live-gekkos/new\",component:h[\"a\"]},{path:\"/live-gekkos/:id\",component:m[\"a\"]}]});Object(v[\"b\"])(),new e[\"a\"]({router:p,store:i[\"a\"],el:\"#app\",render:function(t){return t(n[\"a\"])}})}.call(this,\"/\")},WlXR:function(t,e,a){\"use strict\";var n=a(\"jnJk\"),r=a.n(n);r.a},WqVH:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain\"},[a(\"h2\",[t._v(\"Config\")]),a(\"div\",{staticClass:\"hr\"}),a(\"h3\",[t._v(\"Available API keys\")]),t.apiKeySets.length?t._e():a(\"p\",[a(\"em\",[t._v(\"You don't have any API keys yet.\")])]),a(\"ul\",t._l(t.apiKeySets,function(e){return a(\"li\",[t._v(t._s(e)+\" (\"),a(\"a\",{attrs:{href:\"#\"},on:{click:function(a){a.preventDefault(),t.removeApiKey(e)}}},[t._v(\"remove\")]),t._v(\")\")])})),t.addApiToggle?t._e():a(\"a\",{staticClass:\"btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.openAddApi(e)}}},[t._v(\"Add an API key\")]),t.addApiToggle?[a(\"div\",{staticClass:\"hr\"}),a(\"apiConfigBuilder\")]:t._e(),a(\"div\",{staticClass:\"hr\"})],2)},r=[],i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd contain\"},[a(\"h3\",[t._v(\"Add an API key\")]),a(\"p\",[t._v(\"Make sure that the API key has the permissions to create and cancel orders and view balances.\")]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"h3\",[t._v(\"Exchange\")]),a(\"exchange-picker\",{attrs:{\"only-tradable\":\"true\"},on:{exchange:t.updateExchange}})],1),a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"h3\",[t._v(\"Credentials\")]),t._l(t.requires,function(e){return[a(\"label\",[t._v(t._s(e))]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.credentials[e],expression:\"credentials[cred]\"}],domProps:{value:t.credentials[e]},on:{input:function(a){a.target.composing||t.$set(t.credentials,e,a.target.value)}}})]})],2)]),a(\"div\",{staticClass:\"txt--center\"},[a(\"a\",{staticClass:\"w100--s my1 btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.upload(e)}}},[t._v(\"Add\")])])])},s=[],o=(a(\"Z2Ku\"),a(\"L9s1\"),function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"div\",{staticClass:\"mx1\"},[a(\"label\",{staticClass:\"wrapper\",attrs:{for:\"exchange\"}},[t._v(\"Exchange:\")]),a(\"div\",{staticClass:\"custom-select button\"},[a(\"select\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.exchange,expression:\"exchange\"}],on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){var e=\"_value\"in t?t._value:t.value;return e});t.exchange=e.target.multiple?a:a[0]}}},t._l(t.exchanges,function(e,n){return a(\"option\",[t._v(t._s(n))])}))])])])}),c=[],u=(a(\"f3/d\"),a(\"91GP\"),a(\"LvDl\")),l=a.n(u),d=(a(\"YIjs\"),a(\"FhOJ\"),a(\"wiDz\")),f={props:[\"onlyTradable\",\"onlyImportable\"],data:function(){return{exchange:\"poloniex\"}},created:function(){this.emitExchange()},computed:{exchanges:function(){var t=Object.assign({},this.$store.state.exchanges);return!l.a.isEmpty(t)&&(this.onlyTradable&&l.a.each(t,function(e,a){e.tradable||delete t[a]}),this.onlyImportable&&l.a.each(t,function(e,a){e.importable||delete t[a]}),t)}},watch:{exchanges:function(){this.emitExchange()},exchange:function(){this.emitExchange()}},methods:{emitExchange:function(){this.$emit(\"exchange\",this.exchange)}}},h=f,m=a(\"KHd+\"),v=Object(m[\"a\"])(h,o,c,!1,null,null,null),p=v.exports,g={data:function(){return{exchange:!1,credentials:{}}},components:{exchangePicker:p},computed:{apiKeySets:function(){return this.$store.state.apiKeys},exchanges:function(){return this.$store.state.exchanges},requires:function(){return this.exchanges&&this.exchange?this.exchanges[this.exchange].requires:[]},config:function(){var t={exchange:this.exchange,values:this.credentials};return t}},watch:{credentials:function(){this.emitConfig()}},methods:{updateExchange:function(t){this.credentials={},this.exchange=t,this.emitConfig()},emitConfig:function(){this.$emit(\"config\",this.config)},upload:function(){var t=this,e=this.config.exchange;this.exchanges&&this.apiKeySets.includes(e)&&!confirm(\"You already have API keys for \".concat(e,\" defined, do you want to overwrite them?\"))||Object(d[\"b\"])(\"addApiKey\",this.config,function(e,a){if(e)return alert(e);t.credentials={}})}}},_=g,k=(a(\"aOB3\"),Object(m[\"a\"])(_,i,s,!1,null,null,null)),y=k.exports,w={components:{apiConfigBuilder:y},data:function(){return{addApiToggle:!1}},methods:{openAddApi:function(){this.addApiToggle=!0},removeApiKey:function(t){confirm(\"Are you sure you want to delete these API keys?\")&&Object(d[\"b\"])(\"removeApiKey\",{exchange:t},function(t,e){if(t)return alert(t)})}},computed:{apiKeySets:function(){return this.$store.state.apiKeys}},watch:{apiKeySets:function(){this.addApiToggle=!1}}},b=w,C=Object(m[\"a\"])(b,n,r,!1,null,null,null);e[\"a\"]=C.exports},YEdZ:function(t,e,a){\"use strict\";var n=a(\"jVW9\"),r=a.n(n);r.a},YIjs:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"h3\",[t._v(\"Daterange\")]),\"scan\"===t.tab?[t.scanned?t._e():a(\"div\",{staticClass:\"txt--center\"},[a(\"a\",{staticClass:\"w100--s btn--primary scan-btn\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.scan(e)}}},[t._v(\"Scan available data\")])]),\"fetching\"==t.scanned?a(\"div\",{staticClass:\"txt--center\"},[a(\"p\",{staticClass:\"scan-btn\"},[t._v(\"Scanning..\")])]):t._e(),1==t.scanned?[0===t.ranges.length?[a(\"p\",[a(\"strong\",[t._v('Unable to find any local data, do you have local data available for\"'+t._s(t.config.watch.exchange)+\":\"+t._s(t.config.watch.currency)+\"/\"+t._s(t.config.watch.asset)+'\"?')])])]:[a(\"label\",{staticClass:\"wrapper\",attrs:{for:\"exchange\"}},[t._v(\"Run simulation over:\")]),a(\"form\",{staticClass:\"radio grd\"},t._l(t.ranges,function(e,n){return a(\"div\",{staticClass:\"grd-row m1\"},[a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.selectedRangeIndex,expression:\"selectedRangeIndex\"}],staticClass:\"grd-row-col-1-6\",attrs:{type:\"radio\"},domProps:{value:n,checked:t._q(t.selectedRangeIndex,n)},on:{change:function(e){t.selectedRangeIndex=n}}}),a(\"label\",{staticClass:\"grd-row-col-5-6\",attrs:{for:n}},[t._v(t._s(t.printRange(e)))])])}))],a(\"p\",[a(\"em\",[a(\"a\",{attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.scan(e)}}},[t._v(\"rescan\")])])])]:t._e(),a(\"p\",{staticClass:\"txt--center\"},[a(\"em\",[a(\"a\",{attrs:{href:\"#\"},on:{click:function(e){e.preventDefault(),t.tab=\"manual\"}}},[t._v(\"Or manually set a daterange\")])])])]:t._e(),\"manual\"===t.tab?[a(\"div\",[a(\"label\",{attrs:{for:\"from\"}},[t._v(\"From:\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.from,expression:\"from\"}],domProps:{value:t.from},on:{input:function(e){e.target.composing||(t.from=e.target.value)}}})]),a(\"div\",[a(\"label\",{attrs:{for:\"to\"}},[t._v(\"To:\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.to,expression:\"to\"}],domProps:{value:t.to},on:{input:function(e){e.target.composing||(t.to=e.target.value)}}})]),a(\"p\",{staticClass:\"txt--center\"}),a(\"em\",[a(\"a\",{attrs:{href:\"#\"},on:{click:function(e){e.preventDefault(),t.tab=\"scan\"}}},[t._v(\"Or scan for a daterange\")])])]:t._e()],2)},r=[],i=(a(\"LvDl\"),a(\"wiDz\")),s={props:[\"config\"],data:function(){return{scanned:!1,ranges:[],selectedRangeIndex:-1,tab:\"scan\",from:\"\",to:\"\"}},methods:{scan:function(){var t=this;this.scanned=\"fetching\",this.selectedRangeIndex=-1,Object(i[\"b\"])(\"scan\",this.config,function(e,a){t.scanned=!0,t.ranges=a,t.selectedRangeIndex=0})},printRange:function(t){var e=function(t){return t.format(\"YYYY-MM-DD HH:mm\")},a=moment.unix(t.from),n=moment.unix(t.to),r=moment.duration(n.diff(a)).humanize();return\"\".concat(e(a),\" to \").concat(e(n),\" (\").concat(r,\")\")},fmtTs:function(t){return moment.unix(t).utc()},fmt:function(t){return t.utc().format()},emitRange:function(t){this.$emit(\"range\",{from:this.fmtTs(t.from),to:this.fmtTs(t.to)})},emitManualEntry:function(){if(this.from.length<\"4\"||this.from.length<\"4\")return this.$emit(\"range\",{});var t=moment.utc(this.from),e=moment.utc(this.to);t.isValid()&&e.isValid()?this.$emit(\"range\",{from:this.fmt(t),to:this.fmt(e)}):this.$emit(\"range\",{})},reset:function(){this.scanned=!1,this.$emit(\"range\",{})}},watch:{from:function(){this.emitManualEntry()},to:function(){this.emitManualEntry()},config:function(){this.reset()},tab:function(){this.reset()},selectedRangeIndex:function(){var t=this.ranges[this.selectedRangeIndex];t&&this.emitRange(t)}}},o=s,c=(a(\"CyGp\"),a(\"KHd+\")),u=Object(c[\"a\"])(o,n,r,!1,null,null,null);u.exports},ZL7j:function(t,e,a){\"use strict\";var n=a(\"EDI0\"),r=a.n(n);r.a},ZpQ2:function(t,e,a){},aOB3:function(t,e,a){\"use strict\";var n=a(\"8KAT\"),r=a.n(n);r.a},bqjz:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"h2\",{staticClass:\"contain\"},[t._v(\"Backtest\")]),a(\"div\",{staticClass:\"hr\"}),a(\"config-builder\",{on:{config:t.check}}),t.backtestable?a(\"div\",[a(\"div\",{staticClass:\"txt--center\"},[\"fetching\"!==t.backtestState?a(\"a\",{staticClass:\"w100--s my1 btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.run(e)}}},[t._v(\"Backtest\")]):t._e(),\"fetching\"===t.backtestState?a(\"div\",{staticClass:\"scan-btn\"},[a(\"p\",[t._v(\"Running backtest..\")]),a(\"spinner\")],1):t._e()])]):t._e(),t.backtestResult&&\"fetched\"===t.backtestState?a(\"result\",{attrs:{result:t.backtestResult}}):t._e()],1)},r=[],i=(a(\"VRzm\"),function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"dataset-picker\",{staticClass:\"my2 contain\",on:{dataset:t.updateDataset}}),a(\"div\",{staticClass:\"hr\"}),a(\"strat-picker\",{staticClass:\"my2 contain\",on:{stratConfig:t.updateStrat}}),a(\"div\",{staticClass:\"hr\"}),a(\"paper-trader\",{staticClass:\"contain\",on:{settings:t.updatePaperTrader}}),a(\"div\",{staticClass:\"hr\"})],1)}),s=[],o=(a(\"91GP\"),function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"h3\",[t._v(\"Select a dataset\")]),\"idle\"===t.datasetScanstate?a(\"div\",{staticClass:\"txt--center my2\"},[a(\"a\",{staticClass:\"w100--s btn--primary scan-btn\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.scan(e)}}},[t._v(\"Scan available data\")])]):t._e(),\"scanning\"===t.datasetScanstate?a(\"div\",{staticClass:\"txt--center my2\"},[a(\"spinner\")],1):t._e(),\"scanned\"===t.datasetScanstate?a(\"div\",{staticClass:\"my2\"},[0!=t.datasets.length?a(\"div\",[a(\"table\",{staticClass:\"full\"},[t._m(0),a(\"tbody\",t._l(t.datasets,function(e,n){return a(\"tr\",[a(\"td\",{staticClass:\"radio\"},[a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.setIndex,expression:\"setIndex\"}],attrs:{type:\"radio\",name:\"dataset\",id:e.id},domProps:{value:n,checked:t._q(t.setIndex,n)},on:{change:function(e){t.setIndex=n}}})]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(e.exchange))])]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(e.currency))])]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(e.asset))])]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(t.fmt(e.from)))])]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(t.fmt(e.to)))])]),a(\"td\",[a(\"label\",{attrs:{for:e.id}},[t._v(t._s(t.humanizeDuration(e.to.diff(e.from))))])])])}))]),t.rangeVisible?t._e():a(\"a\",{staticClass:\"btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.openRange(e)}}},[t._v(\"Adjust range\")]),t.rangeVisible?[a(\"div\",[a(\"label\",{attrs:{for:\"customFrom\"}},[t._v(\"From:\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.customFrom,expression:\"customFrom\"}],domProps:{value:t.customFrom},on:{input:function(e){e.target.composing||(t.customFrom=e.target.value)}}})]),a(\"div\",[a(\"label\",{attrs:{for:\"customTo\"}},[t._v(\"To:\")]),a(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.customTo,expression:\"customTo\"}],domProps:{value:t.customTo},on:{input:function(e){e.target.composing||(t.customTo=e.target.value)}}})])]:t._e()],2):a(\"em\",[t._v(\"No Data found \"),a(\"a\",{attrs:{href:\"#/data/importer\"}},[t._v(\"Lets add some\")])])]):t._e()])}),c=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"thead\",[a(\"tr\",[a(\"th\"),a(\"th\",[t._v(\"exchange\")]),a(\"th\",[t._v(\"currency\")]),a(\"th\",[t._v(\"asset\")]),a(\"th\",[t._v(\"from\")]),a(\"th\",[t._v(\"to\")]),a(\"th\",[t._v(\"duration\")])])])}],u=a(\"LvDl\"),l=a.n(u),d=a(\"Kw5r\"),f=a(\"wiDz\"),h=a(\"MB/c\"),m=a(\"spvI\"),v={components:{spinner:h[\"a\"]},data:function(){return{setIndex:-1,customTo:!1,customFrom:!1,rangeVisible:!1,set:!1}},mixins:[m[\"a\"]],methods:{humanizeDuration:function(t){return window.humanizeDuration(t,{largest:4})},fmt:function(t){return t.utc().format(\"YYYY-MM-DD HH:mm\")},openRange:function(){if(-1===this.setIndex)return alert(\"Select a dataset to adjust range\");this.updateCustomRange(),this.rangeVisible=!0},updateCustomRange:function(){this.customTo=this.fmt(this.set.to),this.customFrom=this.fmt(this.set.from)},emitSet:function(t){var e;t&&(this.customTo?(e=d[\"a\"].util.extend({},t),e.to=moment.utc(this.customTo,\"YYYY-MM-DD HH:mm\").format(),e.from=moment.utc(this.customFrom,\"YYYY-MM-DD HH:mm\").format()):e=t,this.$emit(\"dataset\",e))}},watch:{setIndex:function(){this.set=this.datasets[this.setIndex],this.updateCustomRange(),this.emitSet(this.set)},customTo:function(){this.emitSet(this.set)},customFrom:function(){this.emitSet(this.set)}}},p=v,g=(a(\"ngcj\"),a(\"KHd+\")),_=Object(g[\"a\"])(p,o,c,!1,null,null,null),k=_.exports,y=a(\"6Wkr\"),w=a(\"rloZ\"),b={created:function(){var t=this;Object(f[\"a\"])(\"configPart/performanceAnalyzer\",function(e,a){t.performanceAnalyzer=toml.parse(a.part),t.performanceAnalyzer.enabled=!0})},data:function(){return{dataset:{},strat:{},paperTrader:{},performanceAnalyzer:{}}},components:{stratPicker:y[\"a\"],datasetPicker:k,paperTrader:w[\"a\"]},computed:{market:function(){return this.dataset.exchange?{exchange:this.dataset.exchange,currency:this.dataset.currency,asset:this.dataset.asset}:{}},range:function(){return this.dataset.exchange?{from:this.dataset.from,to:this.dataset.to}:{}},config:function(){var t={};return Object.assign(t,{watch:this.market},{paperTrader:this.paperTrader},this.strat,{backtest:{daterange:this.range},backtestResultExporter:{enabled:!0,writeToDisk:!1,data:{stratUpdates:!1,roundtrips:!0,stratCandles:!0,stratCandleProps:[\"open\"],trades:!0}}},{performanceAnalyzer:this.performanceAnalyzer}),t.valid=this.validConfig(t),t.backtestResultExporter.enabled=!0,t}},methods:{validConfig:function(t){if(!t.backtest)return!1;if(!t.backtest.daterange)return!1;if(l.a.isEmpty(t.backtest.daterange))return!1;if(!t.watch)return!1;if(!t.tradingAdvisor)return!1;var e=t.tradingAdvisor.method;if(l.a.isEmpty(t[e]))return!1;if(t.tradingAdvisor){if(l.a.isNaN(t.tradingAdvisor.candleSize))return!1;if(0==t.tradingAdvisor.candleSize)return!1}return!0},updateDataset:function(t){this.dataset=t,this.$emit(\"config\",this.config)},updateStrat:function(t){this.strat=t,this.$emit(\"config\",this.config)},updatePaperTrader:function(t){this.paperTrader=t,this.paperTrader.enabled=!0,this.$emit(\"config\",this.config)}}},C=b,x=(a(\"Q6eY\"),Object(g[\"a\"])(C,i,s,!1,null,null,null)),S=x.exports,T=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",[a(\"div\",{staticClass:\"hr contain\"}),t._m(0),a(\"result-summary\",{attrs:{report:t.result.performanceReport}}),a(\"div\",{staticClass:\"hr contain\"}),a(\"chart\",{attrs:{data:t.candles,height:\"500\"}}),a(\"div\",{staticClass:\"hr contain\"}),a(\"roundtripTable\",{attrs:{roundtrips:t.result.roundtrips}})],1)},E=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain\"},[a(\"h3\",[t._v(\"Backtest result\")])])}],P=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain\"},[a(\"div\",{staticClass:\"grd-row summary\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"table\",{staticClass:\"p1\"},[a(\"tr\",[a(\"th\",[t._v(\"start time\")]),a(\"td\",[t._v(t._s(t.report.startTime))])]),a(\"tr\",[a(\"th\",[t._v(\"end time\")]),a(\"td\",[t._v(t._s(t.report.endTime))])]),a(\"tr\",[a(\"th\",[t._v(\"timespan\")]),a(\"td\",[t._v(t._s(t.report.timespan))])]),a(\"tr\",[a(\"th\",[t._v(\"start price\")]),a(\"td\",[t._v(t._s(t.round(t.report.startPrice))+\" \"+t._s(t.report.currency))])]),a(\"tr\",[a(\"th\",[t._v(\"end price\")]),a(\"td\",[t._v(t._s(t.round(t.report.endPrice))+\" \"+t._s(t.report.currency))])]),a(\"tr\",[a(\"th\",[t._v(\"market\")]),a(\"td\",[t._v(t._s(t.round(t.report.market))+\"%\")])])])]),a(\"paperTradeSummary\",{attrs:{report:t.report}})],1)])},A=[],j=a(\"0Bu0\"),D={props:[\"report\"],components:{paperTradeSummary:j[\"a\"]},methods:{round:function(t){return(+t).toFixed(5)}},computed:{profitClass:function(){return this.report.relativeProfit>0?\"profit\":\"loss\"}}},O=D,z=(a(\"WlXR\"),Object(g[\"a\"])(O,P,A,!1,null,null,null)),$=z.exports,M=a(\"UeuA\"),G=a(\"vf3E\"),I={props:[\"result\"],data:function(){return{}},methods:{},components:{roundtripTable:G[\"a\"],resultSummary:$,chart:M[\"a\"]},computed:{candles:function(){return{candles:this.result.stratCandles,trades:this.result.trades}}}},R=I,H=(a(\"wVP4\"),Object(g[\"a\"])(R,T,E,!1,null,null,null)),K=H.exports,Y={data:function(){return{backtestable:!1,backtestState:\"idle\",backtestResult:!1,config:!1}},methods:{check:function(t){if(this.config=t,!t.valid)return this.backtestable=!1;this.backtestable=!0},run:function(){var t=this;this.backtestState=\"fetching\",Object(f[\"b\"])(\"backtest\",this.config,function(e,a){t.backtestState=\"fetched\",t.backtestResult=a})}},components:{configBuilder:S,result:K,spinner:h[\"a\"]}},W=Y,N=Object(g[\"a\"])(W,n,r,!1,null,null,null);e[\"a\"]=N.exports},dHeD:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain\"},[a(\"div\",{staticClass:\"text\",domProps:{innerHTML:t._s(t.intro)}}),a(\"div\",{staticClass:\"hr\"}),a(\"h2\",[t._v(\"Available datasets\")]),\"idle\"===t.datasetScanstate?a(\"div\",{staticClass:\"txt--center my2\"},[a(\"a\",{staticClass:\"w100--s btn--primary scan-btn\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.scan(e)}}},[t._v(\"Scan available data\")])]):t._e(),\"scanning\"===t.datasetScanstate?a(\"div\",{staticClass:\"txt--center my2\"},[a(\"spinner\")],1):t._e(),\"scanned\"===t.datasetScanstate?a(\"div\",{staticClass:\"my2\"},[t.unscannableMakets.length?a(\"div\",{staticClass:\"bg--orange p1 warning my1\"},[t.viewUnscannable?t._e():a(\"p\",{staticClass:\"clickable\",on:{click:function(e){return e.preventDefault(),t.toggleUnscannable(e)}}},[t._v(\"Some markets were unscannable, click here for details.\")]),t.viewUnscannable?[a(\"p\",[t._v(\"Unable to find datasets in the following markets:\")]),t._l(t.unscannableMakets,function(e){return a(\"div\",{staticClass:\"mx2\"},[t._v(\"- \"+t._s(e.exchange)+\":\"+t._s(e.currency)+\":\"+t._s(e.asset))])})]:t._e()],2):t._e(),t.datasets.length?[a(\"table\",{staticClass:\"full data\"},[t._m(0),a(\"tbody\",t._l(t.datasets,function(e){return a(\"tr\",[a(\"td\",[t._v(t._s(e.exchange))]),a(\"td\",[t._v(t._s(e.currency))]),a(\"td\",[t._v(t._s(e.asset))]),a(\"td\",[t._v(t._s(t.fmt(e.from)))]),a(\"td\",[t._v(t._s(t.fmt(e.to)))]),a(\"td\",[t._v(t._s(t.humanizeDuration(e.to.diff(e.from))))])])}))])]:t._e(),t.datasets.length?t._e():[a(\"p\",[t._v(\"It looks like you don't have any local data yet.\")])]],2):t._e(),a(\"div\",{staticClass:\"my2\"},[a(\"h2\",[t._v(\"Import more data\")]),a(\"p\",{staticClass:\"text\"},[t._v(\"You can easily import more market data directly from exchanges using the importer.\")]),a(\"router-link\",{staticClass:\"btn--primary\",attrs:{to:\"/data/importer\"}},[t._v(\"Go to the importer!\")])],1)])},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"thead\",[a(\"tr\",[a(\"th\",[t._v(\"exchange\")]),a(\"th\",[t._v(\"currency\")]),a(\"th\",[t._v(\"asset\")]),a(\"th\",[t._v(\"from\")]),a(\"th\",[t._v(\"to\")]),a(\"th\",[t._v(\"duration\")])])])}],i=(a(\"VRzm\"),a(\"MB/c\")),s=a(\"5shn\"),o=a(\"spvI\"),c=Object(s[\"a\"])(\"\\n\\n## Local data\\n\\nGekko needs local market data in order to backtest strategies. The local\\ndata can also be used in a warmup period when running a strategy against a\\nlive market.\\n\\n\"),u={mixins:[o[\"a\"]],components:{spinner:i[\"a\"]},data:function(){return{intro:c,viewUnscannable:!1}},methods:{toggleUnscannable:function(){this.viewUnscannable=!0},humanizeDuration:function(t){return window.humanizeDuration(t)},fmt:function(t){return t.format(\"YYYY-MM-DD HH:mm\")}}},l=u,d=(a(\"2rY9\"),a(\"KHd+\")),f=Object(d[\"a\"])(l,n,r,!1,null,null,null);e[\"a\"]=f.exports},dW8q:function(t,e,a){\"use strict\";var n=a(\"w3yp\"),r=a.n(n);r.a},daul:function(t,e,a){\"use strict\";var n=a(\"Kd0R\"),r=a.n(n);r.a},g298:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain my2\"},[t.data&&!t.data.done?a(\"div\",[a(\"h2\",[t._v(\"Importing data..\")]),a(\"div\",{staticClass:\"grd\"},[a(\"div\",{staticClass:\"grd-row\"},[t._m(0),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.data.watch.exchange))])]),a(\"div\",{staticClass:\"grd-row\"},[t._m(1),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.data.watch.currency)+\"/\"+t._s(t.data.watch.asset))])])]),a(\"div\",{staticClass:\"grd\"},[a(\"div\",{staticClass:\"grd-row\"},[t._m(2),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fmt(t.from)))])]),a(\"div\",{staticClass:\"grd-row\"},[t._m(3),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fmt(t.to)))])]),t.initialized?a(\"div\",{staticClass:\"grd-row\"},[t._m(4),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fmt(t.latest)))])]):t._e(),t.initialized?a(\"div\",{staticClass:\"grd-row\"},[t._m(5),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fromEnd))])]):t._e()]),t.initialized?t._e():a(\"spinner\"),t.initialized?a(\"div\",{staticClass:\"contain\"},[a(\"progressBar\",{attrs:{progress:t.progress}})],1):t._e(),a(\"p\",[a(\"em\",[t._v(\"(you don't have to wait until the import is done,you can already start \"),a(\"router-link\",{attrs:{to:\"/backtest\"}},[t._v(\"backtesting\")]),t._v(\").\")],1)])],1):t._e(),t.data&&t.data.done?a(\"div\",{staticClass:\"txt--center\"},[a(\"h2\",[t._v(\"Import done\")]),a(\"p\",[t._v(\" Go and \"),a(\"router-link\",{attrs:{to:\"/backtest\"}},[t._v(\"backtest\")]),t._v(\" with your new data!\")],1)]):t._e(),t.data?t._e():a(\"div\",{staticClass:\"txt--center\"},[a(\"h2\",[t._v(\"ERROR: Unknown import\")]),a(\"p\",[a(\"I\",[t._v(\"don't know this import..\")])],1)])])},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"Market:\")])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"Currency/Asset:\")])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"From:\")])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"To:\")])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"Imported data until:\")])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-2-6\"},[a(\"strong\",[t._v(\"Remaining:\")])])}],i=(a(\"dRSK\"),a(\"LvDl\")),s=a.n(i),o=function(){var t=this,e=t.$createElement,a=t._self._c||e;return t.progress?a(\"div\",{staticClass:\"progressbarWrapper\"},[a(\"p\",[a(\"strong\",[t._v(t._s(t.round(t.progress))+\"%\")])]),a(\"div\",{staticClass:\"progressbar\"},[a(\"div\",{style:{width:t.progress+\"%\"}})])]):t._e()},c=[],u={props:[\"progress\"],methods:{round:function(t){return(+t).toFixed(2)}}},l=u,d=(a(\"/vJE\"),a(\"KHd+\")),f=Object(d[\"a\"])(l,o,c,!1,null,null,null),h=f.exports,m=a(\"MB/c\"),v={components:{progressBar:h,spinner:m[\"a\"]},computed:{data:function(){return s.a.find(this.$store.state.imports,{id:this.$route.params.id})},initialized:function(){if(this.data&&this.latest.isValid())return!0},latest:function(){if(this.data)return this.mom(this.data.latest)},fromEndMs:function(){if(this.data)return this.to.diff(this.latest)},fromEnd:function(){return this.latest?humanizeDuration(this.fromEndMs):\"LOADING\"},from:function(){if(this.data)return this.mom(this.data.from)},to:function(){if(this.data)return this.mom(this.data.to)},timespan:function(){if(this.data)return this.to.diff(this.from)},progress:function(){if(this.data){var t=this.timespan-this.fromEndMs;return 100*t/this.timespan}}},methods:{fmt:function(t){return t.format(\"YYYY-MM-DD HH:mm:ss\")},mom:function(t){return moment.utc(t)}}},p=v,g=(a(\"qDq4\"),Object(d[\"a\"])(p,n,r,!1,null,null,null));e[\"a\"]=g.exports},gYof:function(t,e,a){\"use strict\";a(\"LvDl\");var n=a(\"Kw5r\"),r=a(\"r0f2\"),i=(a(\"L2JU\"),a(\"wiDz\")),s=a(\"Q2AE\"),o=function(){Object(i[\"a\"])(\"imports\",function(t,e){s[\"a\"].commit(\"syncImports\",e)})},c=function(){C.$on(\"import_update\",function(t){s[\"a\"].commit(\"updateImport\",t)})},u=function(){o(),c()},l=function(){Object(i[\"a\"])(\"gekkos\",function(t,e){var a=e;s[\"a\"].commit(\"syncGekkos\",a)})},d=function(){C.$on(\"gekko_new\",function(t){return s[\"a\"].commit(\"addGekko\",t.state)}),C.$on(\"gekko_event\",function(t){return s[\"a\"].commit(\"updateGekko\",t)}),C.$on(\"gekko_archived\",function(t){return s[\"a\"].commit(\"archiveGekko\",t.id)}),C.$on(\"gekko_error\",function(t){return s[\"a\"].commit(\"errorGekko\",t)}),C.$on(\"gekko_deleted\",function(t){return s[\"a\"].commit(\"deleteGekko\",t.id)})},f=function(){l(),d()},h=function(){},m=function(){C.$on(\"WS_STATUS_CHANGE\",function(t){return s[\"a\"].commit(\"setGlobalWarning\",{key:\"connected\",value:t.connected})})},v=function(){h(),m()},p=a(\"k5N+\"),g=(a(\"rGqo\"),function(t){if(!t)return{};var e=t,a={};return e.forEach(function(t){a[t.slug]=a[t.slug]||{markets:{}},t.markets.forEach(function(e){var n=Object(p[\"a\"])(e[\"pair\"],2),r=n[0],i=n[1];a[t.slug].markets[r]=a[t.slug].markets[r]||[],a[t.slug].markets[r].push(i)}),\"exchangeMaxHistoryAge\"in t&&(a[t.slug].exchangeMaxHistoryAge=t.exchangeMaxHistoryAge),a[t.slug].importable=!!t.providesFullHistory,a[t.slug].tradable=!!t.tradable,a[t.slug].requires=t.requires}),a}),_=function(){Object(i[\"a\"])(\"apiKeys\",function(t,e){s[\"a\"].commit(\"syncApiKeys\",e)}),Object(i[\"a\"])(\"exchanges\",function(t,e){s[\"a\"].commit(\"syncExchanges\",g(e))})},k=function(){C.$on(\"apiKeys\",function(t){s[\"a\"].commit(\"syncApiKeys\",t.exchanges)})},y=function(){_(),k()},w=function(){u(),f(),v(),y()};a.d(e,\"a\",function(){return C}),a.d(e,\"b\",function(){return S});var b=null,C=new n[\"a\"];C.$on(\"gekko_update\",function(t){return console.log(t)}),C.$on(\"import_update\",function(t){return console.log(t)}),C.$on(\"import_error\",function(t){alert(\"IMPORT ERROR: \"+t.error)});var x={connected:!1},S=function(){b=new ReconnectingWebSocket(r[\"b\"],null,{maxReconnectInterval:4e3}),setTimeout(function(){x.connected||(w(),C.$emit(\"WS_STATUS_CHANGE\",x))},500),b.onopen=function(){x.connected||(x.connected=!0,C.$emit(\"WS_STATUS_CHANGE\",x),w())},b.onclose=function(){x.connected&&(x.connected=!1,C.$emit(\"WS_STATUS_CHANGE\",x))},b.onerror=function(){x.connected&&(x.connected=!1,C.$emit(\"WS_STATUS_CHANGE\",x))},b.onmessage=function(t){var e=JSON.parse(t.data);C.$emit(e.type,e)}}},h8ks:function(t,e,a){},hGnM:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain py2\"},[a(\"h3\",[t._v(\"Market watchers\")]),t.watchers.length?t._e():a(\"div\",{staticClass:\"text\"},[a(\"p\",[t._v(\"You don't have any market watchers.\")])]),t.watchers.length?a(\"table\",{staticClass:\"full clickable\"},[t._m(0),a(\"tbody\",t._l(t.watchers,function(e){return a(\"tr\",{staticClass:\"clickable\",on:{click:function(a){t.$router.push({path:\"/live-gekkos/\"+e.id})}}},[a(\"td\",[t._v(t._s(e.config.watch.exchange))]),a(\"td\",[t._v(t._s(e.config.watch.currency))]),a(\"td\",[t._v(t._s(e.config.watch.asset))]),a(\"td\",[t._v(t._s(t.status(e)))]),a(\"td\",[e.events.initial.candle?[t._v(t._s(t.fmt(e.events.initial.candle.start)))]:t._e()],2),a(\"td\",[e.events.latest.candle?[t._v(t._s(t.fmt(e.events.latest.candle.start)))]:t._e()],2),a(\"td\",[e.events.initial.candle&&e.events.latest.candle?[t._v(t._s(t.timespan(e.events.latest.candle.start,e.events.initial.candle.start)))]:t._e()],2)])}))]):t._e(),a(\"h3\",[t._v(\"Strat runners\")]),t.stratrunners.length?t._e():a(\"div\",{staticClass:\"text\"},[a(\"p\",[t._v(\"You don't have any stratrunners.\")])]),t.stratrunners.length?a(\"table\",{staticClass:\"full\"},[t._m(1),a(\"tbody\",t._l(t.stratrunners,function(e){return a(\"tr\",{staticClass:\"clickable\",on:{click:function(a){t.$router.push({path:\"/live-gekkos/\"+e.id})}}},[a(\"td\",[t._v(t._s(e.config.watch.exchange))]),a(\"td\",[t._v(t._s(e.config.watch.currency))]),a(\"td\",[t._v(t._s(e.config.watch.asset))]),a(\"td\",[t._v(t._s(t.status(e)))]),a(\"td\",[e.events.initial.candle&&e.events.latest.candle?[t._v(t._s(t.timespan(e.events.latest.candle.start,e.events.initial.candle.start)))]:t._e()],2),a(\"td\",[t._v(t._s(e.config.tradingAdvisor.method))]),a(\"td\",[t.report(e)?t._e():[t._v(\"0\")],t.report(e)?[t._v(t._s(t.round(t.report(e).profit))+\" \"+t._s(t.report(e).currency))]:t._e()],2),a(\"td\",[t._v(t._s(e.logType))]),a(\"td\",[e.events.tradeCompleted?t._e():[t._v(\"0\")],e.events.tradeCompleted?[t._v(t._s(e.events.tradeCompleted.length))]:t._e()],2)])}))]):t._e(),a(\"div\",{staticClass:\"hr\"}),a(\"h2\",[t._v(\"Start a new live Gekko\")]),a(\"router-link\",{staticClass:\"btn--primary\",attrs:{to:\"/live-gekkos/new\"}},[t._v(\"Start a new live Gekko!\")])],1)},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"thead\",[a(\"tr\",[a(\"th\",[t._v(\"exchange\")]),a(\"th\",[t._v(\"currency\")]),a(\"th\",[t._v(\"asset\")]),a(\"th\",[t._v(\"status\")]),a(\"th\",[t._v(\"started at\")]),a(\"th\",[t._v(\"last update\")]),a(\"th\",[t._v(\"duration\")])])])},function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"thead\",[a(\"tr\",[a(\"th\",[t._v(\"exchange\")]),a(\"th\",[t._v(\"currency\")]),a(\"th\",[t._v(\"asset\")]),a(\"th\",[t._v(\"status\")]),a(\"th\",[t._v(\"duration\")]),a(\"th\",[t._v(\"strategy\")]),a(\"th\",[t._v(\"PnL\")]),a(\"th\",[t._v(\"type\")]),a(\"th\",[t._v(\"trades\")])])])}],i=(a(\"a1Th\"),a(\"rGqo\"),a(\"yt8O\"),{created:function(){var t=this;this.timer=setInterval(function(){t.now=moment()},1e3)},destroyed:function(){clearTimeout(this.timer)},data:function(){return{timer:!1,now:moment()}},computed:{stratrunners:function(){return _.values(this.$store.state.gekkos).concat(_.values(this.$store.state.archivedGekkos)).filter(function(t){return\"papertrader\"===t.logType||\"tradebot\"===t.logType})},watchers:function(){return _.values(this.$store.state.gekkos).concat(_.values(this.$store.state.archivedGekkos)).filter(function(t){return\"watcher\"===t.logType})}},methods:{humanizeDuration:function(t){return window.humanizeDuration(t)},moment:function(t){function e(e){return t.apply(this,arguments)}return e.toString=function(){return t.toString()},e}(function(t){return moment.utc(t)}),fmt:function(t){return moment.utc(t).format(\"YYYY-MM-DD HH:mm\")},round:function(t){return(+t).toFixed(3)},timespan:function(t,e){return this.humanizeDuration(this.moment(t).diff(this.moment(e)))},status:function(t){return t.errored?\"errored\":t.stopped?\"stopped\":t.active?\"running\":void console.log(\"unknown state:\",t)},report:function(t){return _.get(t,\"events.latest.performanceReport\")}}}),s=i,o=(a(\"daul\"),a(\"KHd+\")),c=Object(o[\"a\"])(s,n,r,!1,null,null,null);e[\"a\"]=c.exports},jTvs:function(t,e,a){},jVW9:function(t,e,a){},jf14:function(t,e,a){},jloR:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain my2\"},[a(\"div\",{staticClass:\"text\",domProps:{innerHTML:t._s(t.intro)}}),a(\"div\",{staticClass:\"hr\"}),a(\"h3\",[t._v(\"Currently running imports\")]),0===t.imports.length?a(\"p\",[t._v(\"You currently don't have any imports running.\")]):t._e(),t.imports.length?a(\"ul\",t._l(t.imports,function(e){return a(\"li\",[a(\"router-link\",{attrs:{to:\"/data/importer/import/\"+e.id}},[t._v(t._s(e.watch.exchange)+\":\"+t._s(e.watch.currency)+\"/\"+t._s(e.watch.asset))])],1)})):t._e(),a(\"div\",{staticClass:\"hr\"}),a(\"h3\",[t._v(\"Start a new import\")]),a(\"import-config-builder\",{on:{config:t.updateConfig}}),a(\"div\",{staticClass:\"hr\"}),a(\"div\",{staticClass:\"txt--center\"},[a(\"a\",{staticClass:\"w100--s my1 btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.run(e)}}},[t._v(\"Import\")])])],1)},r=[],i=a(\"wiDz\"),s=a(\"MB/c\"),o=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd contain\"},[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"h3\",[t._v(\"Market\")]),a(\"market-picker\",{attrs:{\"only-importable\":\"true\"},on:{market:t.updateMarketConfig}})],1),a(\"div\",{staticClass:\"grd-row-col-3-6 mx1\"},[a(\"range-creator\",{on:{range:t.updateRange}})],1)])])},c=[],u=(a(\"91GP\"),a(\"6BxS\")),l=a(\"FhOJ\"),d=(a(\"LvDl\"),{data:function(){return{market:{},range:{}}},components:{marketPicker:u[\"a\"],rangeCreator:l[\"a\"]},computed:{config:function(){var t={};return Object.assign(t,this.market,{importer:{daterange:this.range}},{candleWriter:{enabled:!0}}),t}},methods:{updateMarketConfig:function(t){this.market=t,this.emitConfig()},updateRange:function(t){this.range=t,this.emitConfig()},emitConfig:function(){this.$emit(\"config\",this.config)}}}),f=d,h=(a(\"H+ir\"),a(\"KHd+\")),m=Object(h[\"a\"])(f,o,c,!1,null,null,null),v=m.exports,p=a(\"5shn\"),g=Object(p[\"a\"])(\"\\n\\n## Import data\\n\\nThe importer can download historical market data directly from the exchange.\\n\\n\"),_={components:{importConfigBuilder:v,spinner:s[\"a\"]},data:function(){return{intro:g,config:{}}},computed:{imports:function(){return this.$store.state.imports}},methods:{daysApart:function(t){var e=moment(t.to),a=moment(t.from);return e.diff(a,\"days\")},updateConfig:function(t){this.config=t},run:function(){var t=this,e=this.daysApart(this.config.importer.daterange);if(e<1)return alert(\"You can only import at least one day of data..\");var a=this.$store.state.exchanges[this.config.watch.exchange];if(\"exchangeMaxHistoryAge\"in a&&moment(this.config.importer.daterange.from)<moment().subtract(a.exchangeMaxHistoryAge,\"days\"))return alert(\"Your date from is too old for \"+this.config.watch.exchange+\". It supports only the last \"+a.exchangeMaxHistoryAge+\" days..\");Object(i[\"b\"])(\"import\",this.config,function(e,a){if(e)return alert(e);t.$store.commit(\"addImport\",a),t.$router.push({path:\"/data/importer/import/\".concat(a.id)})})}}},k=_,y=(a(\"yomC\"),Object(h[\"a\"])(k,n,r,!1,null,null,null));e[\"a\"]=y.exports},jnJk:function(t,e,a){},kiQV:function(t){t.exports={name:\"gekko-vue-ui\",version:\"0.2.3\",private:!0,scripts:{serve:\"vue-cli-service serve\",build:\"vue-cli-service build\"},dependencies:{marked:\"^0.4.0\",superagent:\"^3.8.3\",\"superagent-no-cache\":\"github:uditalias/superagent-no-cache\",vue:\"^2.5.16\",\"vue-router\":\"^3.0.1\",vuex:\"^3.0.1\"},devDependencies:{\"@vue/cli-plugin-babel\":\"^3.0.0-beta.15\",\"@vue/cli-service\":\"^3.0.0-beta.15\",\"babel-plugin-transform-commonjs-es2015-modules\":\"^4.0.1\",\"copy-webpack-plugin\":\"^4.5.2\",pug:\"^2.0.3\",\"pug-plain-loader\":\"^1.0.0\",\"vue-template-compiler\":\"^2.5.16\"},postcss:{plugins:{autoprefixer:{}}},browserslist:[\"> 1%\",\"last 2 versions\",\"not ie <= 8\"]}},ldlP:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"section\",{staticClass:\"contain grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\",domProps:{innerHTML:t._s(t.left)}}),t._m(0)])},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd-row-col-3-6 txt--center\"},[a(\"img\",{attrs:{src:\"static/gekko.jpg\"}}),a(\"p\",[a(\"em\",[t._v(\"The most valuable commodity I know of is information.\")])])])}],i=a(\"5shn\"),s=Object(i[\"a\"])(\"\\n\\n## Gekko\\n\\nGekko is a Bitcoin trading bot and backtesting platform that\\nconnects to popular Bitcoin exchanges. It is written in javascript\\nand runs on nodejs.\\n\\n[Find out more](https://gekko.wizb.it/).\\n\\n*Gekko is 100% free (open source), if you paid for this you have been scammed.*\\n\\n\"),o={data:function(){return{left:s}}},c=o,u=a(\"KHd+\"),l=Object(u[\"a\"])(c,n,r,!1,null,null,null);e[\"a\"]=l.exports},mf2E:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"my2\"},[t.data?t._e():a(\"div\",{staticClass:\"contain\"},[a(\"h1\",[t._v(\"Unknown Gekko instance\")]),a(\"p\",[t._v(\"Gekko doesn't know what gekko this is...\")])]),t.data?a(\"div\",[a(\"h2\",{staticClass:\"contain\"},[t._v(\"Gekko \"+t._s(t.type))]),t.isArchived?a(\"div\",{staticClass:\"contain brdr--mid-gray p1 bg--orange\"},[t._v(\"This is an archived Gekko, it is currently not running anymore.\")]):t._e(),t.data.errorMessage?a(\"div\",{staticClass:\"contain brdr--mid-gray p1 bg--orange\"},[t._v(\"This is Gekko crashed with the following error: \"+t._s(t.data.errorMessage))]):t._e(),a(\"div\",{staticClass:\"grd contain\"},[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"h3\",[t._v(\"Market\")]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Exchange\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.config.watch.exchange))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Currency\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.config.watch.currency))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Asset\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.config.watch.asset))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Type\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.type))])])]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"h3\",[t._v(\"Runtime\")]),t.isLoading?a(\"spinner\"):t._e(),t.isLoading?t._e():[t.initialEvents.candle?a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"Watching since\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fmt(t.initialEvents.candle.start)))])]):t._e(),t.latestEvents.candle?a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"Received data until\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.fmt(t.latestEvents.candle.start)))])]):t._e(),t.latestEvents.candle?a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"Data spanning\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.humanizeDuration(t.moment(t.latestEvents.candle.start).diff(t.moment(t.initialEvents.candle.start)))))])]):t._e(),t.isStratrunner?[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"Amount of trades\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.trades.length))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"Candle size\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.config.tradingAdvisor.candleSize))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-2-6\"},[t._v(\"History size\")]),a(\"div\",{staticClass:\"grd-row-col-4-6\"},[t._v(t._s(t.config.tradingAdvisor.historySize))])])]:t._e()]],2)]),t.warmupRemaining?a(\"div\",{staticClass:\"contain brdr--mid-gray p1 bg--orange\"},[t._v(\"This stratrunner is still warming up for the next \"),a(\"i\",[t._v(t._s(t.warmupRemaining.replace(\",\",\" and \")))]),t._v(\", it will not trade until it is warmed up.\")]):t._e(),t.isStratrunner?a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"h3\",[t._v(\"Strategy\")]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Name\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"strong\",[t._v(t._s(t.stratName))])])]),t._v(\"Parameters\"),a(\"pre\",[t._v(t._s(t.stratParams))])]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[a(\"h3\",[t._v(\"Profit report\")]),t.report?t._e():[a(\"p\",[t.isArchived?a(\"em\",[t._v(\"This Gekko never executed a trade..\")]):t._e(),t.isArchived?t._e():a(\"em\",[t._v(\"Waiting for at least one trade..\")])])],t.report?[a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Start balance\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.round(t.report.startBalance)))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Current balance\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.round(t.report.balance)))])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Market\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.round(t.report.market/100*t.report.startPrice))+\" \"+t._s(t.config.watch.currency)+\" (\"+t._s(t.round(t.report.market))+\" %)\")])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Profit\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.round(t.report.profit))+\" \"+t._s(t.config.watch.currency)+\" (\"+t._s(t.round(t.report.relativeProfit))+\" %)\")])]),a(\"div\",{staticClass:\"grd-row\"},[a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(\"Alpha\")]),a(\"div\",{staticClass:\"grd-row-col-3-6\"},[t._v(t._s(t.round(t.report.alpha))+\" \"+t._s(t.config.watch.currency))])])]:t._e()],2)]):t._e(),!t.isStratrunner||t.watcher||t.isArchived?t._e():a(\"p\",[t._v(\"WARNING: stale gekko, not attached to a watcher, please report \"),a(\"a\",{attrs:{href:\"https://github.com/askmike/gekko/issues\"}},[t._v(\"here\")]),t._v(\".\")]),t.isArchived?t._e():a(\"p\",[a(\"a\",{staticClass:\"w100--s my1 btn--red\",on:{click:t.stopGekko}},[t._v(\"Stop Gekko\")])]),t.isArchived?a(\"p\",[a(\"a\",{staticClass:\"w100--s my1 btn--red\",on:{click:t.deleteGekko}},[t._v(\"Delete Gekko\")])]):t._e(),t.isStratrunner&&t.watcher&&!t.isArchived?a(\"p\",[a(\"em\",[t._v(\"This gekko gets market data from \"),a(\"router-link\",{attrs:{to:\"/live-gekkos/\"+t.watcher.id}},[t._v(\"this market watcher\")])],1),t._v(\".\")]):t._e()]),t.isLoading?t._e():[a(\"h3\",{staticClass:\"contain\"},[t._v(\"Market graph\")]),\"fetching\"===t.candleFetch?a(\"spinner\"):t._e(),\"fetched\"===t.candleFetch?[a(\"chart\",{attrs:{data:t.chartData,height:300}})]:t._e(),t.isStratrunner?a(\"roundtrips\",{attrs:{roundtrips:t.roundtrips}}):t._e()]],2):t._e()])},r=[],i=(a(\"a1Th\"),a(\"dRSK\"),a(\"Kw5r\")),s=a(\"LvDl\"),o=a.n(s),c=a(\"wiDz\"),u=a(\"MB/c\"),l=a(\"UeuA\"),d=a(\"vf3E\"),f=a(\"0Bu0\"),h={created:function(){this.isLoading||this.getCandles()},components:{spinner:u[\"a\"],chart:l[\"a\"],paperTradeSummary:f[\"a\"],roundtrips:d[\"a\"]},data:function(){return{candleFetch:\"idle\",candles:!1}},computed:{id:function(){return this.$route.params.id},gekkos:function(){return this.$store.state.gekkos},archivedGekkos:function(){return this.$store.state.archivedGekkos},data:function(){return!!this.gekkos&&(o.a.has(this.gekkos,this.id)?this.gekkos[this.id]:!!o.a.has(this.archivedGekkos,this.id)&&this.archivedGekkos[this.id])},config:function(){return o.a.get(this,\"data.config\")},latestEvents:function(){return o.a.get(this,\"data.events.latest\")},initialEvents:function(){return o.a.get(this,\"data.events.initial\")},trades:function(){return o.a.get(this,\"data.events.tradeCompleted\")||[]},roundtrips:function(){return o.a.get(this,\"data.events.roundtrip\")||[]},isLive:function(){return o.a.has(this.gekkos,this.id)},type:function(){return this.data.logType},isStratrunner:function(){return\"watcher\"!==this.type},isArchived:function(){return this.data.stopped},warmupRemaining:function(){if(!this.isStratrunner)return!1;if(this.isArchived)return!1;if(this.initialEvents.stratWarmupCompleted)return!1;if(!this.initialEvents.candle)return!1;var t=o.a.get(this.config,\"tradingAdvisor.historySize\");if(!t)return!1;var e=o.a.get(this.config,\"tradingAdvisor.candleSize\")*t;return humanizeDuration(moment(this.initialEvents.candle.start).add(e,\"m\").diff(moment()),{largest:2})},chartData:function(){return{candles:this.candles,trades:this.trades}},report:function(){return o.a.get(this.latestEvents,\"performanceReport\")},stratName:function(){if(this.data)return this.data.config.tradingAdvisor.method},stratParams:function(){if(!this.data)return\"Loading...\";var t=i[\"a\"].util.extend({},this.data.config[this.stratName]);return delete t.__empty,o.a.isEmpty(t)?\"No parameters\":JSON.stringify(t,null,4)},isLoading:function(){return!this.data||(!o.a.get(this.data,\"events.initial.candle\")||!o.a.get(this.data,\"events.latest.candle\"))},watcher:function(){var t=this;if(!this.isStratrunner)return!1;var e=i[\"a\"].util.extend({},this.data.config.watch);return o.a.find(this.gekkos,function(a){return a.id!==t.id&&o.a.isEqual(e,a.config.watch)})},hasLeechers:function(){var t=this;if(this.isStratrunner)return!1;var e=i[\"a\"].util.extend({},this.data.config.watch);return o.a.find(this.gekkos,function(a){return a.id!==t.id&&o.a.isEqual(e,a.config.watch)})}},watch:{\"data.events.latest.candle.start\":function(){setTimeout(this.getCandles,o.a.random(100,2e3))}},methods:{round:function(t){return(+t).toFixed(5)},humanizeDuration:function(t,e){return window.humanizeDuration(t,e)},moment:function(t){function e(e){return t.apply(this,arguments)}return e.toString=function(){return t.toString()},e}(function(t){return moment.utc(t)}),fmt:function(t){return moment.utc(t).format(\"YYYY-MM-DD HH:mm\")},getCandles:function(){var t=this;if(!this.isLoading&&\"fetching\"!==this.candleFetch){this.candleFetch=\"fetching\";var e=this.data.events.latest.candle.start,a=this.data.events.initial.candle.start,n=1;\"watcher\"!==this.type&&(n=this.data.config.tradingAdvisor.candleSize);var r={watch:this.data.config.watch,daterange:{to:e,from:a},candleSize:n};setTimeout(function(){Object(c[\"b\"])(\"getCandles\",r,function(e,a){if(t.candleFetch=\"fetched\",!a||a.error||!o.a.isArray(a))return console.log(a);t.candles=a.map(function(t){return t.start=moment.unix(t.start).utc().format(),t})})},o.a.random(150,2500))}},stopGekko:function(){if(this.hasLeechers)return alert(\"This Gekko is fetching market data for multiple stratrunners, stop these first.\");confirm(\"Are you sure you want to stop this Gekko?\")&&Object(c[\"b\"])(\"stopGekko\",{id:this.data.id},function(t,e){console.log(\"stopped gekko\")})},deleteGekko:function(){var t=this;if(!this.isArchived)return alert(\"This Gekko is still running, stop it first!\");confirm(\"Are you sure you want to delete this Gekko?\")&&Object(c[\"b\"])(\"deleteGekko\",{id:this.data.id},function(e,a){t.$router.push({path:\"/live-gekkos/\"})})}}},m=h,v=(a(\"/Dpa\"),a(\"KHd+\")),p=Object(v[\"a\"])(m,n,r,!1,null,null,null);e[\"a\"]=p.exports},ngcj:function(t,e,a){\"use strict\";var n=a(\"EAJ1\"),r=a.n(n);r.a},nzng:function(t,e,a){},pd3X:function(t,e,a){},pyMo:function(t,e,a){},q431:function(t,e,a){\"use strict\";var n=a(\"ydmZ\"),r=a.n(n);r.a},qDq4:function(t,e,a){\"use strict\";var n=a(\"nzng\"),r=a.n(n);r.a},r0f2:function(t,e,a){\"use strict\";a.d(e,\"b\",function(){return i}),a.d(e,\"a\",function(){return r});var n,r,i,s=window.CONFIG.ui,o=\"\".concat(s.host).concat(80===s.port?\"\":\":\".concat(s.port)).concat(s.path);n=s.ssl?\"https://\".concat(o):\"http://\".concat(o),r=n+\"api/\",i=s.ssl?\"wss://\".concat(o,\"api\"):\"ws://\".concat(o,\"api\")},rloZ:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"grd\"},[a(\"div\",{staticClass:\"px1\"},[a(\"h3\",[t._v(\"Paper trader\")]),\"closed\"===t.toggle?a(\"a\",{staticClass:\"btn--primary\",attrs:{href:\"#\"},on:{click:function(e){return e.preventDefault(),t.switchToggle(e)}}},[t._v(\"Change paper trader settings\")]):t._e(),\"open\"===t.toggle?[a(\"p\",[t._v(\"Settings:\")]),a(\"textarea\",{directives:[{name:\"model\",rawName:\"v-model\",value:t.rawPaperTraderParams,expression:\"rawPaperTraderParams\"}],staticClass:\"params\",domProps:{value:t.rawPaperTraderParams},on:{input:function(e){e.target.composing||(t.rawPaperTraderParams=e.target.value)}}}),t.rawPaperTraderParamsError?a(\"p\",{staticClass:\"bg--red p1\"},[t._v(t._s(t.rawPaperTraderParamsError.message))]):t._e()]:t._e()],2)])},r=[],i=(a(\"LvDl\"),a(\"wiDz\")),s={created:function(){var t=this;Object(i[\"a\"])(\"configPart/paperTrader\",function(e,a){t.rawPaperTraderParams=a.part})},data:function(){return{rawPaperTraderParams:\"\",rawPaperTraderParamsError:!1,paperTraderParams:{},toggle:\"closed\"}},watch:{rawPaperTraderParams:function(){this.emitConfig()}},methods:{switchToggle:function(){\"open\"===this.toggle?this.toggle=\"closed\":this.toggle=\"open\"},emitConfig:function(){this.parseParams(),this.$emit(\"settings\",this.paperTraderParams)},parseParams:function(){try{this.paperTraderParams=toml.parse(this.rawPaperTraderParams),this.paperTraderParams.reportRoundtrips=!0,this.rawPaperTraderParamsError=!1}catch(t){this.rawPaperTraderParamsError=t,this.paperTraderParams={}}}}},o=s,c=(a(\"0zrD\"),a(\"KHd+\")),u=Object(c[\"a\"])(o,n,r,!1,null,null,null);e[\"a\"]=u.exports},spvI:function(t,e,a){\"use strict\";a(\"Vd3H\"),a(\"rGqo\");var n=a(\"wiDz\"),r={data:function(){return{datasets:[],datasetScanstate:\"idle\",unscannableMakets:[]}},methods:{scan:function(){var t=this;this.datasetScanstate=\"scanning\",Object(n[\"b\"])(\"scansets\",{},function(e,a){t.datasetScanstate=\"scanned\",t.unscannableMakets=a.errors;var n=[];a.datasets.forEach(function(t){t.ranges.forEach(function(e,a){n.push({exchange:t.exchange,currency:t.currency,asset:t.asset,from:moment.unix(e.from).utc(),to:moment.unix(e.to).utc(),id:t.exchange+t.asset+t.currency+a})})}),n=n.filter(function(t){if(t.to.diff(t.from,\"hours\")>2)return!0}),n=n.sort(function(t,e){var a=t.to.diff(t.from),n=e.to.diff(e.from);return a<n?-1:a>n?1:0}).reverse(),t.datasets=n})}}};e[\"a\"]=r},tr8f:function(t,e,a){\"use strict\";var n=a(\"h8ks\"),r=a.n(n);r.a},tr8z:function(t,e,a){\"use strict\";var n=a(\"Ug4+\"),r=a.n(n);r.a},uMTv:function(t,e,a){\"use strict\";var n=a(\"pyMo\"),r=a.n(n);r.a},uXxc:function(t,e,a){},vf3E:function(t,e,a){\"use strict\";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"div\",{staticClass:\"contain roundtrips\"},[a(\"h2\",[t._v(\"Roundtrips\")]),t.roundtrips.length?a(\"table\",[a(\"thead\",[t._m(0),t._l(t.roundtrips,function(e){return a(\"tr\",[a(\"td\",[t._v(t._s(t.fmt(e.entryAt)))]),a(\"td\",[t._v(t._s(t.fmt(e.exitAt)))]),a(\"td\",[t._v(t._s(t.diff(e.duration)))]),a(\"td\",[t._v(t._s(t.round(e.entryBalance)))]),a(\"td\",[t._v(t._s(t.round(e.exitBalance)))]),-1===Math.sign(e.pnl)?[a(\"td\",{staticClass:\"loss\"},[t._v(t._s(Math.sign(e.pnl)*e.pnl.toFixed(2)))]),a(\"td\",{staticClass:\"loss\"},[t._v(t._s(e.profit.toFixed(2))+\"%\")])]:[a(\"td\",{staticClass:\"profit\"},[t._v(t._s(e.pnl.toFixed(2)))]),a(\"td\",{staticClass:\"profit\"},[t._v(t._s(e.profit.toFixed(2))+\"%\")])]],2)})],2)]):t._e(),t.roundtrips.length?t._e():a(\"div\",[a(\"p\",[t._v(\"Not enough data to display\")])])])},r=[function(){var t=this,e=t.$createElement,a=t._self._c||e;return a(\"tr\",[a(\"th\",[t._v(\"Entry at (UTC)\")]),a(\"th\",[t._v(\"Exit at (UTC)\")]),a(\"th\",[t._v(\"Exposure\")]),a(\"th\",[t._v(\"Entry balance\")]),a(\"th\",[t._v(\"Exit balance\")]),a(\"th\",[t._v(\"P&L\")]),a(\"th\",[t._v(\"Profit\")])])}],i=a(\"LvDl\"),s=a.n(i),o={props:[\"roundtrips\"],data:function(){return{}},methods:{diff:function(t){return moment.duration(t).humanize()},humanizeDuration:function(t){return window.humanizeDuration(t)},fmt:function(t){var e;return e=s.a.isNumber(t)?moment.unix(t):moment(t).utc(),e.utc().format(\"YYYY-MM-DD HH:mm\")},round:function(t){return(+t).toFixed(3)}}},c=o,u=(a(\"dW8q\"),a(\"KHd+\")),l=Object(u[\"a\"])(c,n,r,!1,null,null,null);e[\"a\"]=l.exports},vwRV:function(t,e,a){},w3yp:function(t,e,a){},wVP4:function(t,e,a){\"use strict\";var n=a(\"vwRV\"),r=a.n(n);r.a},wVPO:function(t,e,a){\"use strict\";var n=a(\"uXxc\"),r=a.n(n);r.a},wiDz:function(t,e,a){\"use strict\";a.d(e,\"b\",function(){return u}),a.d(e,\"a\",function(){return l});var n=a(\"24Ii\"),r=a.n(n),i=a(\"TrxG\"),s=a.n(i),o=a(\"r0f2\"),c=function(t){return function(e,a){if(e)return t(e);if(!a.text)return t(\"no data\");var n=JSON.parse(a.text);t(!1,n)}},u=function(t,e,a){r.a.post(o[\"a\"]+t).use(s.a).send(e).end(c(a))},l=function(t,e){r.a.get(o[\"a\"]+t).use(s.a).end(c(e))}},ydmZ:function(t,e,a){},yomC:function(t,e,a){\"use strict\";var n=a(\"EfWa\"),r=a.n(n);r.a},yuKf:function(t,e,a){}});\n//# sourceMappingURL=app.5e99ecf7.js.map"
  },
  {
    "path": "web/vue/dist/app.730569ff.css",
    "content": ".menu{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;margin-top:0;margin-bottom:2rem}.menu a{-webkit-box-flex:1;-ms-flex:1 1 100%;flex:1 1 100%;display:block;text-align:center;text-decoration:none;color:inherit}.menu .router-link-active{background-color:hsla(0,0%,98%,.99)}.menu a:hover{text-decoration:underline}#modal-background{position:fixed;top:0;bottom:0;left:0;right:0;background-color:#000;opacity:.5}.modal{position:fixed;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:600px;min-height:300px;background-color:#fff}.modal-guts{position:absolute;top:0;left:0;width:100%;height:100%;padding:20px 50px 20px 20px;overflow:auto}#app{display:-webkit-box;display:-ms-flexbox;display:flex;min-height:100vh;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.fill{-webkit-box-flex:1;-ms-flex:1;flex:1}.text{max-width:500px}input{background:none;margin-top:.5em}.params{min-height:235px;line-height:1.3em}.hr{margin-top:2rem;margin-bottom:2rem;height:10px;background-color:hsla(0,0%,98%,.99)}.contain{width:900px;margin-left:auto;margin-right:auto}.btn--primary{display:inline-block;margin-right:12px;margin-bottom:12px;height:40px;padding:0 18px;border-radius:4px;text-shadow:0 1px 3px rgba(36,180,126,.4);-webkit-box-shadow:0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08);box-shadow:0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08);line-height:40px;-webkit-transition:-webkit-transform .25s;transition:-webkit-transform .25s;transition:transform .25s;transition:transform .25s,-webkit-transform .25s}.btn--primary,.btn--primary:hover{background-color:#3498db;color:#fff;text-decoration:none}.btn--primary:hover{-webkit-transform:translateY(-1px);transform:translateY(-1px);-webkit-box-shadow:0 7px 14px rgba(50,50,93,.1),0 3px 6px rgba(0,0,0,.08);box-shadow:0 7px 14px rgba(50,50,93,.1),0 3px 6px rgba(0,0,0,.08)}.btn--primary:active,.btn--primary:focus{background-color:#3498db;color:#fff;text-decoration:none}.btn--primary:active{-webkit-transform:translateY(1px);transform:translateY(1px)}.spinner{margin:20px auto 100px;width:50px;height:40px;text-align:center;font-size:10px}.spinner>div{background-color:#333;height:100%;width:6px;display:inline-block;margin-right:4px;-webkit-animation:sk-stretchdelay 1.2s infinite ease-in-out;animation:sk-stretchdelay 1.2s infinite ease-in-out}.spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.spinner .rect3{-webkit-animation-delay:-1s;animation-delay:-1s}.spinner .rect4{-webkit-animation-delay:-.9s;animation-delay:-.9s}.spinner .rect5{-webkit-animation-delay:-.8s;animation-delay:-.8s}@-webkit-keyframes sk-stretchdelay{0%,40%,to{-webkit-transform:scaleY(.4)}20%{-webkit-transform:scaleY(1)}}@keyframes sk-stretchdelay{0%,40%,to{transform:scaleY(.4);-webkit-transform:scaleY(.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}td.radio{width:45px}td label{display:inline;font-size:1em}.align .custom-select select{padding:.4em 1.2em .3em .8em}.label-like{display:block;font-size:.9em;color:#777}.align{padding-left:1em}.big{font-size:1.3em}.big,.summary table{width:80%}.price.profit{color:#7fff00}.price.loss{color:red}.summary td{text-align:right}#chartWrapper.clickable{position:relative}#chartWrapper.clickable .shield{cursor:-webkit-zoom-in;cursor:zoom-in;position:absolute;top:0;bottom:0;left:0;right:0;background:grey;opacity:.1}#chart{background-color:#eee;width:100%}#chart circle{-webkit-clip-path:url(#clip);clip-path:url(#clip)}#chart .zoom{cursor:move;fill:none;pointer-events:all}#chart .line{fill:none;stroke:#4682b4;stroke-width:1.5px;-webkit-clip-path:url(#clip);clip-path:url(#clip)}#chart circle.buy{fill:#7fff00}#chart circle.sell{fill:red}.roundtrips{margin-top:50px;margin-bottom:50px}.roundtrips table{width:100%}.roundtrips table td,.roundtrips table th{border:1px solid #c6cbd1;padding:8px 12px}.roundtrips table td.loss{color:red;text-align:right}.roundtrips table td.profit{color:green;text-align:right}.roundtrips table tr:nth-child(2n){background-color:#f6f8fa}.clickable{cursor:pointer}table.full{width:100%}table.full td{padding:.5rem 0}table.full.data th{text-align:left;padding:.5rem 0}.warning p{margin:0;padding:0}.scan-btn{margin-top:80px;margin-bottom:30px}.progressbarWrapper p{text-align:center;font-size:20px}.progressbar{background-color:hsla(0,0%,85%,.99);border-radius:13px;padding:0}@-webkit-keyframes shimmer{0%{background-position:0 0}to{background-position:960px 0}}@keyframes shimmer{0%{background-position:0 0}to{background-position:960px 0}}.progressbar>div{height:20px;border-radius:10px;background-color:orange;-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shimmer;animation-name:shimmer;-webkit-animation-timing-function:linear;animation-timing-function:linear;background:#f6f7f8;background:-webkit-gradient(linear,left top,right top,color-stop(10%,orange),color-stop(25%,#ffce77),color-stop(40%,orange));background:linear-gradient(90deg,orange 10%,#ffce77 25%,orange 40%);background-size:960px 50px;background-position:0;position:relative}table.clickable{border-collapse:separate}tr.clickable td:first-child{padding-left:5px}tr.clickable{cursor:pointer}tr.clickable:hover{background:hsla(0,0%,85%,.99)}.radio label{margin-top:0}"
  },
  {
    "path": "web/vue/dist/chunk-vendors.b9a11975.js",
    "content": "(window[\"webpackJsonp\"]=window[\"webpackJsonp\"]||[]).push([[0],{\"+rLv\":function(t,e,n){var r=n(\"dyZX\").document;t.exports=r&&r.documentElement},\"/yFf\":function(t,e,n){\"use strict\";var r=n(\"oHnp\");function i(t){if(t)return o(t)}function o(t){for(var e in i.prototype)t[e]=i.prototype[e];return t}t.exports=i,i.prototype.get=function(t){return this.header[t.toLowerCase()]},i.prototype._setHeaderProperties=function(t){var e=t[\"content-type\"]||\"\";this.type=r.type(e);var n=r.params(e);for(var i in n)this[i]=n[i];this.links={};try{t.link&&(this.links=r.parseLinks(t.link))}catch(t){}},i.prototype._setStatusProperties=function(t){var e=t/100|0;this.status=this.statusCode=t,this.statusType=e,this.info=1==e,this.ok=2==e,this.redirect=3==e,this.clientError=4==e,this.serverError=5==e,this.error=(4==e||5==e)&&this.toError(),this.created=201==t,this.accepted=202==t,this.noContent=204==t,this.badRequest=400==t,this.unauthorized=401==t,this.notAcceptable=406==t,this.forbidden=403==t,this.notFound=404==t,this.unprocessableEntity=422==t}},\"0/R4\":function(t,e){t.exports=function(t){return\"object\"===typeof t?null!==t:\"function\"===typeof t}},\"0sh+\":function(t,e,n){var r=n(\"quPj\"),i=n(\"vhPU\");t.exports=function(t,e,n){if(r(e))throw TypeError(\"String#\"+n+\" doesn't accept regex!\");return String(i(t))}},\"1TsA\":function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},\"24Ii\":function(t,e,n){var r;\"undefined\"!==typeof window?r=window:\"undefined\"!==typeof self?r=self:(console.warn(\"Using browser-only version of superagent in non-browser environment\"),r=this);var i=n(\"cpc2\"),o=n(\"kMlx\"),a=n(\"8zgK\"),u=n(\"/yFf\"),s=n(\"nZbv\");function c(){}var l=e=t.exports=function(t,n){return\"function\"==typeof n?new e.Request(\"GET\",t).end(n):1==arguments.length?new e.Request(\"GET\",t):new e.Request(t,n)};e.Request=_,l.getXHR=function(){if(!(!r.XMLHttpRequest||r.location&&\"file:\"==r.location.protocol&&r.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject(\"Microsoft.XMLHTTP\")}catch(t){}try{return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\")}catch(t){}try{return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\")}catch(t){}try{return new ActiveXObject(\"Msxml2.XMLHTTP\")}catch(t){}throw Error(\"Browser-only version of superagent could not find XHR\")};var f=\"\".trim?function(t){return t.trim()}:function(t){return t.replace(/(^\\s*|\\s*$)/g,\"\")};function p(t){if(!a(t))return t;var e=[];for(var n in t)h(e,n,t[n]);return e.join(\"&\")}function h(t,e,n){if(null!=n)if(Array.isArray(n))n.forEach(function(n){h(t,e,n)});else if(a(n))for(var r in n)h(t,e+\"[\"+r+\"]\",n[r]);else t.push(encodeURIComponent(e)+\"=\"+encodeURIComponent(n));else null===n&&t.push(encodeURIComponent(e))}function d(t){for(var e,n,r={},i=t.split(\"&\"),o=0,a=i.length;o<a;++o)e=i[o],n=e.indexOf(\"=\"),-1==n?r[decodeURIComponent(e)]=\"\":r[decodeURIComponent(e.slice(0,n))]=decodeURIComponent(e.slice(n+1));return r}function v(t){for(var e,n,r,i,o=t.split(/\\r?\\n/),a={},u=0,s=o.length;u<s;++u)n=o[u],e=n.indexOf(\":\"),-1!==e&&(r=n.slice(0,e).toLowerCase(),i=f(n.slice(e+1)),a[r]=i);return a}function y(t){return/[\\/+]json($|[^-\\w])/.test(t)}function g(t){this.req=t,this.xhr=this.req.xhr,this.text=\"HEAD\"!=this.req.method&&(\"\"===this.xhr.responseType||\"text\"===this.xhr.responseType)||\"undefined\"===typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText;var e=this.xhr.status;1223===e&&(e=204),this._setStatusProperties(e),this.header=this.headers=v(this.xhr.getAllResponseHeaders()),this.header[\"content-type\"]=this.xhr.getResponseHeader(\"content-type\"),this._setHeaderProperties(this.header),null===this.text&&t._responseType?this.body=this.xhr.response:this.body=\"HEAD\"!=this.req.method?this._parseBody(this.text?this.text:this.xhr.response):null}function _(t,e){var n=this;this._query=this._query||[],this.method=t,this.url=e,this.header={},this._header={},this.on(\"end\",function(){var t,e=null,r=null;try{r=new g(n)}catch(t){return e=new Error(\"Parser is unable to parse the response\"),e.parse=!0,e.original=t,n.xhr?(e.rawResponse=\"undefined\"==typeof n.xhr.responseType?n.xhr.responseText:n.xhr.response,e.status=n.xhr.status?n.xhr.status:null,e.statusCode=e.status):(e.rawResponse=null,e.status=null),n.callback(e)}n.emit(\"response\",r);try{n._isResponseOK(r)||(t=new Error(r.statusText||\"Unsuccessful HTTP response\"))}catch(e){t=e}t?(t.original=e,t.response=r,t.status=r.status,n.callback(t,r)):n.callback(null,r)})}function m(t,e,n){var r=l(\"DELETE\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.send(e),n&&r.end(n),r}l.serializeObject=p,l.parseString=d,l.types={html:\"text/html\",json:\"application/json\",xml:\"text/xml\",urlencoded:\"application/x-www-form-urlencoded\",form:\"application/x-www-form-urlencoded\",\"form-data\":\"application/x-www-form-urlencoded\"},l.serialize={\"application/x-www-form-urlencoded\":p,\"application/json\":JSON.stringify},l.parse={\"application/x-www-form-urlencoded\":d,\"application/json\":JSON.parse},u(g.prototype),g.prototype._parseBody=function(t){var e=l.parse[this.type];return this.req._parser?this.req._parser(this,t):(!e&&y(this.type)&&(e=l.parse[\"application/json\"]),e&&t&&(t.length||t instanceof Object)?e(t):null)},g.prototype.toError=function(){var t=this.req,e=t.method,n=t.url,r=\"cannot \"+e+\" \"+n+\" (\"+this.status+\")\",i=new Error(r);return i.status=this.status,i.method=e,i.url=n,i},l.Response=g,i(_.prototype),o(_.prototype),_.prototype.type=function(t){return this.set(\"Content-Type\",l.types[t]||t),this},_.prototype.accept=function(t){return this.set(\"Accept\",l.types[t]||t),this},_.prototype.auth=function(t,e,n){1===arguments.length&&(e=\"\"),\"object\"===typeof e&&null!==e&&(n=e,e=\"\"),n||(n={type:\"function\"===typeof btoa?\"basic\":\"auto\"});var r=function(t){if(\"function\"===typeof btoa)return btoa(t);throw new Error(\"Cannot use basic auth, btoa is not a function\")};return this._auth(t,e,n,r)},_.prototype.query=function(t){return\"string\"!=typeof t&&(t=p(t)),t&&this._query.push(t),this},_.prototype.attach=function(t,e,n){if(e){if(this._data)throw Error(\"superagent can't mix .send() and .attach()\");this._getFormData().append(t,e,n||e.name)}return this},_.prototype._getFormData=function(){return this._formData||(this._formData=new r.FormData),this._formData},_.prototype.callback=function(t,e){if(this._shouldRetry(t,e))return this._retry();var n=this._callback;this.clearTimeout(),t&&(this._maxRetries&&(t.retries=this._retries-1),this.emit(\"error\",t)),n(t,e)},_.prototype.crossDomainError=function(){var t=new Error(\"Request has been terminated\\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.\");t.crossDomain=!0,t.status=this.status,t.method=this.method,t.url=this.url,this.callback(t)},_.prototype.buffer=_.prototype.ca=_.prototype.agent=function(){return console.warn(\"This is not supported in browser version of superagent\"),this},_.prototype.pipe=_.prototype.write=function(){throw Error(\"Streaming is not supported in browser version of superagent\")},_.prototype._isHost=function(t){return t&&\"object\"===typeof t&&!Array.isArray(t)&&\"[object Object]\"!==Object.prototype.toString.call(t)},_.prototype.end=function(t){return this._endCalled&&console.warn(\"Warning: .end() was called twice. This is not supported in superagent\"),this._endCalled=!0,this._callback=t||c,this._finalizeQueryString(),this._end()},_.prototype._end=function(){var t=this,e=this.xhr=l.getXHR(),n=this._formData||this._data;this._setTimeouts(),e.onreadystatechange=function(){var n=e.readyState;if(n>=2&&t._responseTimeoutTimer&&clearTimeout(t._responseTimeoutTimer),4==n){var r;try{r=e.status}catch(t){r=0}if(!r){if(t.timedout||t._aborted)return;return t.crossDomainError()}t.emit(\"end\")}};var r=function(e,n){n.total>0&&(n.percent=n.loaded/n.total*100),n.direction=e,t.emit(\"progress\",n)};if(this.hasListeners(\"progress\"))try{e.onprogress=r.bind(null,\"download\"),e.upload&&(e.upload.onprogress=r.bind(null,\"upload\"))}catch(t){}try{this.username&&this.password?e.open(this.method,this.url,!0,this.username,this.password):e.open(this.method,this.url,!0)}catch(t){return this.callback(t)}if(this._withCredentials&&(e.withCredentials=!0),!this._formData&&\"GET\"!=this.method&&\"HEAD\"!=this.method&&\"string\"!=typeof n&&!this._isHost(n)){var i=this._header[\"content-type\"],o=this._serializer||l.serialize[i?i.split(\";\")[0]:\"\"];!o&&y(i)&&(o=l.serialize[\"application/json\"]),o&&(n=o(n))}for(var a in this.header)null!=this.header[a]&&this.header.hasOwnProperty(a)&&e.setRequestHeader(a,this.header[a]);return this._responseType&&(e.responseType=this._responseType),this.emit(\"request\",this),e.send(\"undefined\"!==typeof n?n:null),this},l.agent=function(){return new s},[\"GET\",\"POST\",\"OPTIONS\",\"PATCH\",\"PUT\",\"DELETE\"].forEach(function(t){s.prototype[t.toLowerCase()]=function(e,n){var r=new l.Request(t,e);return this._setDefaults(r),n&&r.end(n),r}}),s.prototype.del=s.prototype[\"delete\"],l.get=function(t,e,n){var r=l(\"GET\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.query(e),n&&r.end(n),r},l.head=function(t,e,n){var r=l(\"HEAD\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.query(e),n&&r.end(n),r},l.options=function(t,e,n){var r=l(\"OPTIONS\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.send(e),n&&r.end(n),r},l[\"del\"]=m,l[\"delete\"]=m,l.patch=function(t,e,n){var r=l(\"PATCH\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.send(e),n&&r.end(n),r},l.post=function(t,e,n){var r=l(\"POST\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.send(e),n&&r.end(n),r},l.put=function(t,e,n){var r=l(\"PUT\",t);return\"function\"==typeof e&&(n=e,e=null),e&&r.send(e),n&&r.end(n),r}},\"2OiF\":function(t,e){t.exports=function(t){if(\"function\"!=typeof t)throw TypeError(t+\" is not a function!\");return t}},\"3Lyj\":function(t,e,n){var r=n(\"KroJ\");t.exports=function(t,e,n){for(var i in e)r(t,i,e[i],n);return t}},\"4R4u\":function(t,e){t.exports=\"constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf\".split(\",\")},\"69bn\":function(t,e,n){var r=n(\"y3w9\"),i=n(\"2OiF\"),o=n(\"K0xU\")(\"species\");t.exports=function(t,e){var n,a=r(t).constructor;return void 0===a||void 0==(n=r(a)[o])?e:i(n)}},\"6FMO\":function(t,e,n){var r=n(\"0/R4\"),i=n(\"EWmC\"),o=n(\"K0xU\")(\"species\");t.exports=function(t){var e;return i(t)&&(e=t.constructor,\"function\"!=typeof e||e!==Array&&!i(e.prototype)||(e=void 0),r(e)&&(e=e[o],null===e&&(e=void 0))),void 0===e?Array:e}},\"8zgK\":function(t,e,n){\"use strict\";function r(t){return null!==t&&\"object\"===typeof t}t.exports=r},\"91GP\":function(t,e,n){var r=n(\"XKFU\");r(r.S+r.F,\"Object\",{assign:n(\"czNK\")})},\"9gX7\":function(t,e){t.exports=function(t,e,n,r){if(!(t instanceof e)||void 0!==r&&r in t)throw TypeError(n+\": incorrect invocation!\");return t}},Afnz:function(t,e,n){\"use strict\";var r=n(\"LQAc\"),i=n(\"XKFU\"),o=n(\"KroJ\"),a=n(\"Mukb\"),u=n(\"hPIQ\"),s=n(\"QaDb\"),c=n(\"fyDq\"),l=n(\"OP3Y\"),f=n(\"K0xU\")(\"iterator\"),p=!([].keys&&\"next\"in[].keys()),h=\"@@iterator\",d=\"keys\",v=\"values\",y=function(){return this};t.exports=function(t,e,n,g,_,m,b){s(n,e,g);var w,x,k,A=function(t){if(!p&&t in j)return j[t];switch(t){case d:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},O=e+\" Iterator\",C=_==v,E=!1,j=t.prototype,S=j[f]||j[h]||_&&j[_],$=S||A(_),T=_?C?A(\"entries\"):$:void 0,R=\"Array\"==e&&j.entries||S;if(R&&(k=l(R.call(new t)),k!==Object.prototype&&k.next&&(c(k,O,!0),r||\"function\"==typeof k[f]||a(k,f,y))),C&&S&&S.name!==v&&(E=!0,$=function(){return S.call(this)}),r&&!b||!p&&!E&&j[f]||a(j,f,$),u[e]=$,u[O]=y,_)if(w={values:C?$:A(v),keys:m?$:A(d),entries:T},b)for(x in w)x in j||o(j,x,w[x]);else i(i.P+i.F*(p||E),e,w);return w}},\"C/va\":function(t,e,n){\"use strict\";var r=n(\"y3w9\");t.exports=function(){var t=r(this),e=\"\";return t.global&&(e+=\"g\"),t.ignoreCase&&(e+=\"i\"),t.multiline&&(e+=\"m\"),t.unicode&&(e+=\"u\"),t.sticky&&(e+=\"y\"),e}},CkkT:function(t,e,n){var r=n(\"m0Pp\"),i=n(\"Ymqv\"),o=n(\"S/j/\"),a=n(\"ne8i\"),u=n(\"zRwo\");t.exports=function(t,e){var n=1==t,s=2==t,c=3==t,l=4==t,f=6==t,p=5==t||f,h=e||u;return function(e,u,d){for(var v,y,g=o(e),_=i(g),m=r(u,d,3),b=a(_.length),w=0,x=n?h(e,b):s?h(e,0):void 0;b>w;w++)if((p||w in _)&&(v=_[w],y=m(v,w,g),t))if(n)x[w]=y;else if(y)switch(t){case 3:return!0;case 5:return v;case 6:return w;case 2:x.push(v)}else if(l)return!1;return f?-1:c||l?l:x}}},DVgA:function(t,e,n){var r=n(\"zhAb\"),i=n(\"4R4u\");t.exports=Object.keys||function(t){return r(t,i)}},DlQD:function(t,e,n){(function(e){(function(e){\"use strict\";var n={newline:/^\\n+/,code:/^( {4}[^\\n]+\\n*)+/,fences:v,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)/,heading:/^ *(#{1,6}) *([^\\n]+?) *(?:#+ *)?(?:\\n+|$)/,nptable:v,blockquote:/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/,list:/^( *)(bull) [\\s\\S]+?(?:hr|def|\\n{2,}(?! )(?!\\1bull )\\n*|\\s*$)/,html:\"^ {0,3}(?:<(script|pre|style)[\\\\s>][\\\\s\\\\S]*?(?:</\\\\1>[^\\\\n]*\\\\n+|$)|comment[^\\\\n]*(\\\\n+|$)|<\\\\?[\\\\s\\\\S]*?\\\\?>\\\\n*|<![A-Z][\\\\s\\\\S]*?>\\\\n*|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>\\\\n*|</?(tag)(?: +|\\\\n|/?>)[\\\\s\\\\S]*?(?:\\\\n{2,}|$)|<(?!script|pre|style)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=\\\\h*\\\\n)[\\\\s\\\\S]*?(?:\\\\n{2,}|$)|</(?!script|pre|style)[a-z][\\\\w-]*\\\\s*>(?=\\\\h*\\\\n)[\\\\s\\\\S]*?(?:\\\\n{2,}|$))\",def:/^ {0,3}\\[(label)\\]: *\\n? *<?([^\\s>]+)>?(?:(?: +\\n? *| *\\n *)(title))? *(?:\\n+|$)/,table:v,lheading:/^([^\\n]+)\\n *(=|-){2,} *(?:\\n+|$)/,paragraph:/^([^\\n]+(?:\\n(?!hr|heading|lheading| {0,3}>|<\\/?(?:tag)(?: +|\\n|\\/?>)|<(?:script|pre|style|!--))[^\\n]+)*)/,text:/^[^\\n]+/};function r(t){this.tokens=[],this.tokens.links={},this.options=t||_.defaults,this.rules=n.normal,this.options.pedantic?this.rules=n.pedantic:this.options.gfm&&(this.options.tables?this.rules=n.tables:this.rules=n.gfm)}n._label=/(?!\\s*\\])(?:\\\\[\\[\\]]|[^\\[\\]])+/,n._title=/(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/,n.def=f(n.def).replace(\"label\",n._label).replace(\"title\",n._title).getRegex(),n.bullet=/(?:[*+-]|\\d+\\.)/,n.item=/^( *)(bull) [^\\n]*(?:\\n(?!\\1bull )[^\\n]*)*/,n.item=f(n.item,\"gm\").replace(/bull/g,n.bullet).getRegex(),n.list=f(n.list).replace(/bull/g,n.bullet).replace(\"hr\",\"\\\\n+(?=\\\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$))\").replace(\"def\",\"\\\\n+(?=\"+n.def.source+\")\").getRegex(),n._tag=\"address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul\",n._comment=/<!--(?!-?>)[\\s\\S]*?-->/,n.html=f(n.html,\"i\").replace(\"comment\",n._comment).replace(\"tag\",n._tag).replace(\"attribute\",/ +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/).getRegex(),n.paragraph=f(n.paragraph).replace(\"hr\",n.hr).replace(\"heading\",n.heading).replace(\"lheading\",n.lheading).replace(\"tag\",n._tag).getRegex(),n.blockquote=f(n.blockquote).replace(\"paragraph\",n.paragraph).getRegex(),n.normal=y({},n),n.gfm=y({},n.normal,{fences:/^ *(`{3,}|~{3,})[ \\.]*(\\S+)? *\\n([\\s\\S]*?)\\n? *\\1 *(?:\\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\\n]+?) *#* *(?:\\n+|$)/}),n.gfm.paragraph=f(n.paragraph).replace(\"(?!\",\"(?!\"+n.gfm.fences.source.replace(\"\\\\1\",\"\\\\2\")+\"|\"+n.list.source.replace(\"\\\\1\",\"\\\\3\")+\"|\").getRegex(),n.tables=y({},n.gfm,{nptable:/^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:.*[^>\\n ].*(?:\\n|$))*)\\n*|$)/,table:/^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n((?: *[^>\\n ].*(?:\\n|$))*)\\n*|$)/}),n.pedantic=y({},n.normal,{html:f(\"^ *(?:comment *(?:\\\\n|\\\\s*$)|<(tag)[\\\\s\\\\S]+?</\\\\1> *(?:\\\\n{2,}|\\\\s*$)|<tag(?:\\\"[^\\\"]*\\\"|'[^']*'|\\\\s[^'\\\"/>\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))\").replace(\"comment\",n._comment).replace(/tag/g,\"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b\").getRegex(),def:/^ *\\[([^\\]]+)\\]: *<?([^\\s>]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/}),r.rules=n,r.lex=function(t,e){var n=new r(e);return n.lex(t)},r.prototype.lex=function(t){return t=t.replace(/\\r\\n|\\r/g,\"\\n\").replace(/\\t/g,\"    \").replace(/\\u00a0/g,\" \").replace(/\\u2424/g,\"\\n\"),this.token(t,!0)},r.prototype.token=function(t,e){var r,i,o,a,u,s,c,l,f,p,h,d,v;t=t.replace(/^ +$/gm,\"\");while(t)if((o=this.rules.newline.exec(t))&&(t=t.substring(o[0].length),o[0].length>1&&this.tokens.push({type:\"space\"})),o=this.rules.code.exec(t))t=t.substring(o[0].length),o=o[0].replace(/^ {4}/gm,\"\"),this.tokens.push({type:\"code\",text:this.options.pedantic?o:o.replace(/\\n+$/,\"\")});else if(o=this.rules.fences.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"code\",lang:o[2],text:o[3]||\"\"});else if(o=this.rules.heading.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"heading\",depth:o[1].length,text:o[2]});else if(e&&(o=this.rules.nptable.exec(t))&&(s={type:\"table\",header:g(o[1].replace(/^ *| *\\| *$/g,\"\")),align:o[2].replace(/^ *|\\| *$/g,\"\").split(/ *\\| */),cells:o[3]?o[3].replace(/\\n$/,\"\").split(\"\\n\"):[]},s.header.length===s.align.length)){for(t=t.substring(o[0].length),l=0;l<s.align.length;l++)/^ *-+: *$/.test(s.align[l])?s.align[l]=\"right\":/^ *:-+: *$/.test(s.align[l])?s.align[l]=\"center\":/^ *:-+ *$/.test(s.align[l])?s.align[l]=\"left\":s.align[l]=null;for(l=0;l<s.cells.length;l++)s.cells[l]=g(s.cells[l],s.header.length);this.tokens.push(s)}else if(o=this.rules.hr.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"hr\"});else if(o=this.rules.blockquote.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"blockquote_start\"}),o=o[0].replace(/^ *> ?/gm,\"\"),this.token(o,e),this.tokens.push({type:\"blockquote_end\"});else if(o=this.rules.list.exec(t)){for(t=t.substring(o[0].length),a=o[2],h=a.length>1,this.tokens.push({type:\"list_start\",ordered:h,start:h?+a:\"\"}),o=o[0].match(this.rules.item),r=!1,p=o.length,l=0;l<p;l++)s=o[l],c=s.length,s=s.replace(/^ *([*+-]|\\d+\\.) +/,\"\"),~s.indexOf(\"\\n \")&&(c-=s.length,s=this.options.pedantic?s.replace(/^ {1,4}/gm,\"\"):s.replace(new RegExp(\"^ {1,\"+c+\"}\",\"gm\"),\"\")),this.options.smartLists&&l!==p-1&&(u=n.bullet.exec(o[l+1])[0],a===u||a.length>1&&u.length>1||(t=o.slice(l+1).join(\"\\n\")+t,l=p-1)),i=r||/\\n\\n(?!\\s*$)/.test(s),l!==p-1&&(r=\"\\n\"===s.charAt(s.length-1),i||(i=r)),d=/^\\[[ xX]\\] /.test(s),v=void 0,d&&(v=\" \"!==s[1],s=s.replace(/^\\[[ xX]\\] +/,\"\")),this.tokens.push({type:i?\"loose_item_start\":\"list_item_start\",task:d,checked:v}),this.token(s,!1),this.tokens.push({type:\"list_item_end\"});this.tokens.push({type:\"list_end\"})}else if(o=this.rules.html.exec(t))t=t.substring(o[0].length),this.tokens.push({type:this.options.sanitize?\"paragraph\":\"html\",pre:!this.options.sanitizer&&(\"pre\"===o[1]||\"script\"===o[1]||\"style\"===o[1]),text:o[0]});else if(e&&(o=this.rules.def.exec(t)))t=t.substring(o[0].length),o[3]&&(o[3]=o[3].substring(1,o[3].length-1)),f=o[1].toLowerCase().replace(/\\s+/g,\" \"),this.tokens.links[f]||(this.tokens.links[f]={href:o[2],title:o[3]});else if(e&&(o=this.rules.table.exec(t))&&(s={type:\"table\",header:g(o[1].replace(/^ *| *\\| *$/g,\"\")),align:o[2].replace(/^ *|\\| *$/g,\"\").split(/ *\\| */),cells:o[3]?o[3].replace(/(?: *\\| *)?\\n$/,\"\").split(\"\\n\"):[]},s.header.length===s.align.length)){for(t=t.substring(o[0].length),l=0;l<s.align.length;l++)/^ *-+: *$/.test(s.align[l])?s.align[l]=\"right\":/^ *:-+: *$/.test(s.align[l])?s.align[l]=\"center\":/^ *:-+ *$/.test(s.align[l])?s.align[l]=\"left\":s.align[l]=null;for(l=0;l<s.cells.length;l++)s.cells[l]=g(s.cells[l].replace(/^ *\\| *| *\\| *$/g,\"\"),s.header.length);this.tokens.push(s)}else if(o=this.rules.lheading.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"heading\",depth:\"=\"===o[2]?1:2,text:o[1]});else if(e&&(o=this.rules.paragraph.exec(t)))t=t.substring(o[0].length),this.tokens.push({type:\"paragraph\",text:\"\\n\"===o[1].charAt(o[1].length-1)?o[1].slice(0,-1):o[1]});else if(o=this.rules.text.exec(t))t=t.substring(o[0].length),this.tokens.push({type:\"text\",text:o[0]});else if(t)throw new Error(\"Infinite loop on byte: \"+t.charCodeAt(0));return this.tokens};var i={escape:/^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/,autolink:/^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/,url:v,tag:\"^comment|^</[a-zA-Z][\\\\w:-]*\\\\s*>|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>|^<\\\\?[\\\\s\\\\S]*?\\\\?>|^<![a-zA-Z]+\\\\s[\\\\s\\\\S]*?>|^<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>\",link:/^!?\\[(label)\\]\\(href(?:\\s+(title))?\\s*\\)/,reflink:/^!?\\[(label)\\]\\[(?!\\s*\\])((?:\\\\[\\[\\]]?|[^\\[\\]\\\\])+)\\]/,nolink:/^!?\\[(?!\\s*\\])((?:\\[[^\\[\\]]*\\]|\\\\[\\[\\]]|[^\\[\\]])*)\\](?:\\[\\])?/,strong:/^__([^\\s][\\s\\S]*?[^\\s])__(?!_)|^\\*\\*([^\\s][\\s\\S]*?[^\\s])\\*\\*(?!\\*)|^__([^\\s])__(?!_)|^\\*\\*([^\\s])\\*\\*(?!\\*)/,em:/^_([^\\s][\\s\\S]*?[^\\s_])_(?!_)|^_([^\\s_][\\s\\S]*?[^\\s])_(?!_)|^\\*([^\\s][\\s\\S]*?[^\\s*])\\*(?!\\*)|^\\*([^\\s*][\\s\\S]*?[^\\s])\\*(?!\\*)|^_([^\\s_])_(?!_)|^\\*([^\\s*])\\*(?!\\*)/,code:/^(`+)\\s*([\\s\\S]*?[^`]?)\\s*\\1(?!`)/,br:/^ {2,}\\n(?!\\s*$)/,del:v,text:/^[\\s\\S]+?(?=[\\\\<!\\[`*]|\\b_| {2,}\\n|$)/};function o(t,e){if(this.options=e||_.defaults,this.links=t,this.rules=i.normal,this.renderer=this.options.renderer||new a,this.renderer.options=this.options,!this.links)throw new Error(\"Tokens array requires a `links` property.\");this.options.pedantic?this.rules=i.pedantic:this.options.gfm&&(this.options.breaks?this.rules=i.breaks:this.rules=i.gfm)}function a(t){this.options=t||_.defaults}function u(){}function s(t){this.tokens=[],this.token=null,this.options=t||_.defaults,this.options.renderer=this.options.renderer||new a,this.renderer=this.options.renderer,this.renderer.options=this.options}function c(t,e){return t.replace(e?/&/g:/&(?!#?\\w+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&#39;\")}function l(t){return t.replace(/&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/gi,function(t,e){return e=e.toLowerCase(),\"colon\"===e?\":\":\"#\"===e.charAt(0)?\"x\"===e.charAt(1)?String.fromCharCode(parseInt(e.substring(2),16)):String.fromCharCode(+e.substring(1)):\"\"})}function f(t,e){return t=t.source||t,e=e||\"\",{replace:function(e,n){return n=n.source||n,n=n.replace(/(^|[^\\[])\\^/g,\"$1\"),t=t.replace(e,n),this},getRegex:function(){return new RegExp(t,e)}}}function p(t,e){return h[\" \"+t]||(/^[^:]+:\\/*[^/]*$/.test(t)?h[\" \"+t]=t+\"/\":h[\" \"+t]=t.replace(/[^/]*$/,\"\")),t=h[\" \"+t],\"//\"===e.slice(0,2)?t.replace(/:[\\s\\S]*/,\":\")+e:\"/\"===e.charAt(0)?t.replace(/(:\\/*[^/]*)[\\s\\S]*/,\"$1\")+e:t+e}i._escapes=/\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/g,i._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,i._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,i.autolink=f(i.autolink).replace(\"scheme\",i._scheme).replace(\"email\",i._email).getRegex(),i._attribute=/\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/,i.tag=f(i.tag).replace(\"comment\",n._comment).replace(\"attribute\",i._attribute).getRegex(),i._label=/(?:\\[[^\\[\\]]*\\]|\\\\[\\[\\]]?|`[^`]*`|[^\\[\\]\\\\])*?/,i._href=/\\s*(<(?:\\\\[<>]?|[^\\s<>\\\\])*>|(?:\\\\[()]?|\\([^\\s\\x00-\\x1f()\\\\]*\\)|[^\\s\\x00-\\x1f()\\\\])*?)/,i._title=/\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/,i.link=f(i.link).replace(\"label\",i._label).replace(\"href\",i._href).replace(\"title\",i._title).getRegex(),i.reflink=f(i.reflink).replace(\"label\",i._label).getRegex(),i.normal=y({},i),i.pedantic=y({},i.normal,{strong:/^__(?=\\S)([\\s\\S]*?\\S)__(?!_)|^\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*(?!\\*)/,em:/^_(?=\\S)([\\s\\S]*?\\S)_(?!_)|^\\*(?=\\S)([\\s\\S]*?\\S)\\*(?!\\*)/,link:f(/^!?\\[(label)\\]\\((.*?)\\)/).replace(\"label\",i._label).getRegex(),reflink:f(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace(\"label\",i._label).getRegex()}),i.gfm=y({},i.normal,{escape:f(i.escape).replace(\"])\",\"~|])\").getRegex(),url:f(/^((?:ftp|https?):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/).replace(\"email\",i._email).getRegex(),_backpedal:/(?:[^?!.,:;*_~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~~(?=\\S)([\\s\\S]*?\\S)~~/,text:f(i.text).replace(\"]|\",\"~]|\").replace(\"|\",\"|https?://|ftp://|www\\\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\\\|}~-]+@|\").getRegex()}),i.breaks=y({},i.gfm,{br:f(i.br).replace(\"{2,}\",\"*\").getRegex(),text:f(i.gfm.text).replace(\"{2,}\",\"*\").getRegex()}),o.rules=i,o.output=function(t,e,n){var r=new o(e,n);return r.output(t)},o.prototype.output=function(t){var e,n,r,i,a,u=\"\";while(t)if(a=this.rules.escape.exec(t))t=t.substring(a[0].length),u+=a[1];else if(a=this.rules.autolink.exec(t))t=t.substring(a[0].length),\"@\"===a[2]?(n=c(this.mangle(a[1])),r=\"mailto:\"+n):(n=c(a[1]),r=n),u+=this.renderer.link(r,null,n);else if(this.inLink||!(a=this.rules.url.exec(t))){if(a=this.rules.tag.exec(t))!this.inLink&&/^<a /i.test(a[0])?this.inLink=!0:this.inLink&&/^<\\/a>/i.test(a[0])&&(this.inLink=!1),t=t.substring(a[0].length),u+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):c(a[0]):a[0];else if(a=this.rules.link.exec(t))t=t.substring(a[0].length),this.inLink=!0,r=a[2],this.options.pedantic?(e=/^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/.exec(r),e?(r=e[1],i=e[3]):i=\"\"):i=a[3]?a[3].slice(1,-1):\"\",r=r.trim().replace(/^<([\\s\\S]*)>$/,\"$1\"),u+=this.outputLink(a,{href:o.escapes(r),title:o.escapes(i)}),this.inLink=!1;else if((a=this.rules.reflink.exec(t))||(a=this.rules.nolink.exec(t))){if(t=t.substring(a[0].length),e=(a[2]||a[1]).replace(/\\s+/g,\" \"),e=this.links[e.toLowerCase()],!e||!e.href){u+=a[0].charAt(0),t=a[0].substring(1)+t;continue}this.inLink=!0,u+=this.outputLink(a,e),this.inLink=!1}else if(a=this.rules.strong.exec(t))t=t.substring(a[0].length),u+=this.renderer.strong(this.output(a[4]||a[3]||a[2]||a[1]));else if(a=this.rules.em.exec(t))t=t.substring(a[0].length),u+=this.renderer.em(this.output(a[6]||a[5]||a[4]||a[3]||a[2]||a[1]));else if(a=this.rules.code.exec(t))t=t.substring(a[0].length),u+=this.renderer.codespan(c(a[2].trim(),!0));else if(a=this.rules.br.exec(t))t=t.substring(a[0].length),u+=this.renderer.br();else if(a=this.rules.del.exec(t))t=t.substring(a[0].length),u+=this.renderer.del(this.output(a[1]));else if(a=this.rules.text.exec(t))t=t.substring(a[0].length),u+=this.renderer.text(c(this.smartypants(a[0])));else if(t)throw new Error(\"Infinite loop on byte: \"+t.charCodeAt(0))}else a[0]=this.rules._backpedal.exec(a[0])[0],t=t.substring(a[0].length),\"@\"===a[2]?(n=c(a[0]),r=\"mailto:\"+n):(n=c(a[0]),r=\"www.\"===a[1]?\"http://\"+n:n),u+=this.renderer.link(r,null,n);return u},o.escapes=function(t){return t?t.replace(o.rules._escapes,\"$1\"):t},o.prototype.outputLink=function(t,e){var n=e.href,r=e.title?c(e.title):null;return\"!\"!==t[0].charAt(0)?this.renderer.link(n,r,this.output(t[1])):this.renderer.image(n,r,c(t[1]))},o.prototype.smartypants=function(t){return this.options.smartypants?t.replace(/---/g,\"—\").replace(/--/g,\"–\").replace(/(^|[-\\u2014/(\\[{\"\\s])'/g,\"$1‘\").replace(/'/g,\"’\").replace(/(^|[-\\u2014/(\\[{\\u2018\\s])\"/g,\"$1“\").replace(/\"/g,\"”\").replace(/\\.{3}/g,\"…\"):t},o.prototype.mangle=function(t){if(!this.options.mangle)return t;for(var e,n=\"\",r=t.length,i=0;i<r;i++)e=t.charCodeAt(i),Math.random()>.5&&(e=\"x\"+e.toString(16)),n+=\"&#\"+e+\";\";return n},a.prototype.code=function(t,e,n){if(this.options.highlight){var r=this.options.highlight(t,e);null!=r&&r!==t&&(n=!0,t=r)}return e?'<pre><code class=\"'+this.options.langPrefix+c(e,!0)+'\">'+(n?t:c(t,!0))+\"</code></pre>\\n\":\"<pre><code>\"+(n?t:c(t,!0))+\"</code></pre>\"},a.prototype.blockquote=function(t){return\"<blockquote>\\n\"+t+\"</blockquote>\\n\"},a.prototype.html=function(t){return t},a.prototype.heading=function(t,e,n){return this.options.headerIds?\"<h\"+e+' id=\"'+this.options.headerPrefix+n.toLowerCase().replace(/[^\\w]+/g,\"-\")+'\">'+t+\"</h\"+e+\">\\n\":\"<h\"+e+\">\"+t+\"</h\"+e+\">\\n\"},a.prototype.hr=function(){return this.options.xhtml?\"<hr/>\\n\":\"<hr>\\n\"},a.prototype.list=function(t,e,n){var r=e?\"ol\":\"ul\",i=e&&1!==n?' start=\"'+n+'\"':\"\";return\"<\"+r+i+\">\\n\"+t+\"</\"+r+\">\\n\"},a.prototype.listitem=function(t){return\"<li>\"+t+\"</li>\\n\"},a.prototype.checkbox=function(t){return\"<input \"+(t?'checked=\"\" ':\"\")+'disabled=\"\" type=\"checkbox\"'+(this.options.xhtml?\" /\":\"\")+\"> \"},a.prototype.paragraph=function(t){return\"<p>\"+t+\"</p>\\n\"},a.prototype.table=function(t,e){return e&&(e=\"<tbody>\"+e+\"</tbody>\"),\"<table>\\n<thead>\\n\"+t+\"</thead>\\n\"+e+\"</table>\\n\"},a.prototype.tablerow=function(t){return\"<tr>\\n\"+t+\"</tr>\\n\"},a.prototype.tablecell=function(t,e){var n=e.header?\"th\":\"td\",r=e.align?\"<\"+n+' align=\"'+e.align+'\">':\"<\"+n+\">\";return r+t+\"</\"+n+\">\\n\"},a.prototype.strong=function(t){return\"<strong>\"+t+\"</strong>\"},a.prototype.em=function(t){return\"<em>\"+t+\"</em>\"},a.prototype.codespan=function(t){return\"<code>\"+t+\"</code>\"},a.prototype.br=function(){return this.options.xhtml?\"<br/>\":\"<br>\"},a.prototype.del=function(t){return\"<del>\"+t+\"</del>\"},a.prototype.link=function(t,e,n){if(this.options.sanitize){try{var r=decodeURIComponent(l(t)).replace(/[^\\w:]/g,\"\").toLowerCase()}catch(t){return n}if(0===r.indexOf(\"javascript:\")||0===r.indexOf(\"vbscript:\")||0===r.indexOf(\"data:\"))return n}this.options.baseUrl&&!d.test(t)&&(t=p(this.options.baseUrl,t));try{t=encodeURI(t).replace(/%25/g,\"%\")}catch(t){return n}var i='<a href=\"'+c(t)+'\"';return e&&(i+=' title=\"'+e+'\"'),i+=\">\"+n+\"</a>\",i},a.prototype.image=function(t,e,n){this.options.baseUrl&&!d.test(t)&&(t=p(this.options.baseUrl,t));var r='<img src=\"'+t+'\" alt=\"'+n+'\"';return e&&(r+=' title=\"'+e+'\"'),r+=this.options.xhtml?\"/>\":\">\",r},a.prototype.text=function(t){return t},u.prototype.strong=u.prototype.em=u.prototype.codespan=u.prototype.del=u.prototype.text=function(t){return t},u.prototype.link=u.prototype.image=function(t,e,n){return\"\"+n},u.prototype.br=function(){return\"\"},s.parse=function(t,e){var n=new s(e);return n.parse(t)},s.prototype.parse=function(t){this.inline=new o(t.links,this.options),this.inlineText=new o(t.links,y({},this.options,{renderer:new u})),this.tokens=t.reverse();var e=\"\";while(this.next())e+=this.tok();return e},s.prototype.next=function(){return this.token=this.tokens.pop()},s.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},s.prototype.parseText=function(){var t=this.token.text;while(\"text\"===this.peek().type)t+=\"\\n\"+this.next().text;return this.inline.output(t)},s.prototype.tok=function(){switch(this.token.type){case\"space\":return\"\";case\"hr\":return this.renderer.hr();case\"heading\":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,l(this.inlineText.output(this.token.text)));case\"code\":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case\"table\":var t,e,n,r,i=\"\",o=\"\";for(n=\"\",t=0;t<this.token.header.length;t++)n+=this.renderer.tablecell(this.inline.output(this.token.header[t]),{header:!0,align:this.token.align[t]});for(i+=this.renderer.tablerow(n),t=0;t<this.token.cells.length;t++){for(e=this.token.cells[t],n=\"\",r=0;r<e.length;r++)n+=this.renderer.tablecell(this.inline.output(e[r]),{header:!1,align:this.token.align[r]});o+=this.renderer.tablerow(n)}return this.renderer.table(i,o);case\"blockquote_start\":o=\"\";while(\"blockquote_end\"!==this.next().type)o+=this.tok();return this.renderer.blockquote(o);case\"list_start\":o=\"\";var a=this.token.ordered,u=this.token.start;while(\"list_end\"!==this.next().type)o+=this.tok();return this.renderer.list(o,a,u);case\"list_item_start\":o=\"\",this.token.task&&(o+=this.renderer.checkbox(this.token.checked));while(\"list_item_end\"!==this.next().type)o+=\"text\"===this.token.type?this.parseText():this.tok();return this.renderer.listitem(o);case\"loose_item_start\":o=\"\";while(\"list_item_end\"!==this.next().type)o+=this.tok();return this.renderer.listitem(o);case\"html\":return this.renderer.html(this.token.text);case\"paragraph\":return this.renderer.paragraph(this.inline.output(this.token.text));case\"text\":return this.renderer.paragraph(this.parseText())}};var h={},d=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function v(){}function y(t){for(var e,n,r=1;r<arguments.length;r++)for(n in e=arguments[r],e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t}function g(t,e){var n=t.replace(/([^\\\\])\\|/g,\"$1 |\").split(/ +\\| */),r=0;if(n.length>e)n.splice(e);else while(n.length<e)n.push(\"\");for(;r<n.length;r++)n[r]=n[r].replace(/\\\\\\|/g,\"|\");return n}function _(t,e,n){if(\"undefined\"===typeof t||null===t)throw new Error(\"marked(): input parameter is undefined or null\");if(\"string\"!==typeof t)throw new Error(\"marked(): input parameter is of type \"+Object.prototype.toString.call(t)+\", string expected\");if(n||\"function\"===typeof e){n||(n=e,e=null),e=y({},_.defaults,e||{});var i,o,a=e.highlight,u=0;try{i=r.lex(t,e)}catch(t){return n(t)}o=i.length;var l=function(t){if(t)return e.highlight=a,n(t);var r;try{r=s.parse(i,e)}catch(e){t=e}return e.highlight=a,t?n(t):n(null,r)};if(!a||a.length<3)return l();if(delete e.highlight,!o)return l();for(;u<i.length;u++)(function(t){\"code\"!==t.type?--o||l():a(t.text,t.lang,function(e,n){return e?l(e):null==n||n===t.text?--o||l():(t.text=n,t.escaped=!0,void(--o||l()))})})(i[u])}else try{return e&&(e=y({},_.defaults,e)),s.parse(r.lex(t,e),e)}catch(t){if(t.message+=\"\\nPlease report this to https://github.com/markedjs/marked.\",(e||_.defaults).silent)return\"<p>An error occurred:</p><pre>\"+c(t.message+\"\",!0)+\"</pre>\";throw t}}v.exec=v,_.options=_.setOptions=function(t){return y(_.defaults,t),_},_.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:\"\",highlight:null,langPrefix:\"language-\",mangle:!0,pedantic:!1,renderer:new a,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},_.defaults=_.getDefaults(),_.Parser=s,_.parser=s.parse,_.Renderer=a,_.TextRenderer=u,_.Lexer=r,_.lexer=r.lex,_.InlineLexer=o,_.inlineLexer=o.output,_.parse=_,t.exports=_})(this||\"undefined\"!==typeof window&&window)}).call(this,n(\"yLpj\"))},EWmC:function(t,e,n){var r=n(\"LZWt\");t.exports=Array.isArray||function(t){return\"Array\"==r(t)}},FJW5:function(t,e,n){var r=n(\"hswa\"),i=n(\"y3w9\"),o=n(\"DVgA\");t.exports=n(\"nh4g\")?Object.defineProperties:function(t,e){i(t);var n,a=o(e),u=a.length,s=0;while(u>s)r.f(t,n=a[s++],e[n]);return t}},GZEu:function(t,e,n){var r,i,o,a=n(\"m0Pp\"),u=n(\"MfQN\"),s=n(\"+rLv\"),c=n(\"Iw71\"),l=n(\"dyZX\"),f=l.process,p=l.setImmediate,h=l.clearImmediate,d=l.MessageChannel,v=l.Dispatch,y=0,g={},_=\"onreadystatechange\",m=function(){var t=+this;if(g.hasOwnProperty(t)){var e=g[t];delete g[t],e()}},b=function(t){m.call(t.data)};p&&h||(p=function(t){var e=[],n=1;while(arguments.length>n)e.push(arguments[n++]);return g[++y]=function(){u(\"function\"==typeof t?t:Function(t),e)},r(y),y},h=function(t){delete g[t]},\"process\"==n(\"LZWt\")(f)?r=function(t){f.nextTick(a(m,t,1))}:v&&v.now?r=function(t){v.now(a(m,t,1))}:d?(i=new d,o=i.port2,i.port1.onmessage=b,r=a(o.postMessage,o,1)):l.addEventListener&&\"function\"==typeof postMessage&&!l.importScripts?(r=function(t){l.postMessage(t+\"\",\"*\")},l.addEventListener(\"message\",b,!1)):r=_ in c(\"script\")?function(t){s.appendChild(c(\"script\"))[_]=function(){s.removeChild(this),m.call(t)}}:function(t){setTimeout(a(m,t,1),0)}),t.exports={set:p,clear:h}},H6hf:function(t,e,n){var r=n(\"y3w9\");t.exports=function(t,e,n,i){try{return i?e(r(n)[0],n[1]):e(n)}catch(e){var o=t[\"return\"];throw void 0!==o&&r(o.call(t)),e}}},\"I8a+\":function(t,e,n){var r=n(\"LZWt\"),i=n(\"K0xU\")(\"toStringTag\"),o=\"Arguments\"==r(function(){return arguments}()),a=function(t,e){try{return t[e]}catch(t){}};t.exports=function(t){var e,n,u;return void 0===t?\"Undefined\":null===t?\"Null\":\"string\"==typeof(n=a(e=Object(t),i))?n:o?r(e):\"Object\"==(u=r(e))&&\"function\"==typeof e.callee?\"Arguments\":u}},INYr:function(t,e,n){\"use strict\";var r=n(\"XKFU\"),i=n(\"CkkT\")(6),o=\"findIndex\",a=!0;o in[]&&Array(1)[o](function(){a=!1}),r(r.P+r.F*a,\"Array\",{findIndex:function(t){return i(this,t,arguments.length>1?arguments[1]:void 0)}}),n(\"nGyu\")(o)},Iw71:function(t,e,n){var r=n(\"0/R4\"),i=n(\"dyZX\").document,o=r(i)&&r(i.createElement);t.exports=function(t){return o?i.createElement(t):{}}},\"J+6e\":function(t,e,n){var r=n(\"I8a+\"),i=n(\"K0xU\")(\"iterator\"),o=n(\"hPIQ\");t.exports=n(\"g3g5\").getIteratorMethod=function(t){if(void 0!=t)return t[i]||t[\"@@iterator\"]||o[r(t)]}},JiEa:function(t,e){e.f=Object.getOwnPropertySymbols},K0xU:function(t,e,n){var r=n(\"VTer\")(\"wks\"),i=n(\"ylqs\"),o=n(\"dyZX\").Symbol,a=\"function\"==typeof o,u=t.exports=function(t){return r[t]||(r[t]=a&&o[t]||(a?o:i)(\"Symbol.\"+t))};u.store=r},\"KHd+\":function(t,e,n){\"use strict\";function r(t,e,n,r,i,o,a,u){var s,c=\"function\"===typeof t?t.options:t;if(e&&(c.render=e,c.staticRenderFns=n,c._compiled=!0),r&&(c.functional=!0),o&&(c._scopeId=\"data-v-\"+o),a?(s=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||\"undefined\"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},c._ssrRegister=s):i&&(s=u?function(){i.call(this,this.$root.$options.shadowRoot)}:i),s)if(c.functional){c._injectStyles=s;var l=c.render;c.render=function(t,e){return s.call(e),l(t,e)}}else{var f=c.beforeCreate;c.beforeCreate=f?[].concat(f,s):[s]}return{exports:t,options:c}}n.d(e,\"a\",function(){return r})},KroJ:function(t,e,n){var r=n(\"dyZX\"),i=n(\"Mukb\"),o=n(\"aagx\"),a=n(\"ylqs\")(\"src\"),u=\"toString\",s=Function[u],c=(\"\"+s).split(u);n(\"g3g5\").inspectSource=function(t){return s.call(t)},(t.exports=function(t,e,n,u){var s=\"function\"==typeof n;s&&(o(n,\"name\")||i(n,\"name\",e)),t[e]!==n&&(s&&(o(n,a)||i(n,a,t[e]?\"\"+t[e]:c.join(String(e)))),t===r?t[e]=n:u?t[e]?t[e]=n:i(t,e,n):(delete t[e],i(t,e,n)))})(Function.prototype,u,function(){return\"function\"==typeof this&&this[a]||s.call(this)})},Kuth:function(t,e,n){var r=n(\"y3w9\"),i=n(\"FJW5\"),o=n(\"4R4u\"),a=n(\"YTvA\")(\"IE_PROTO\"),u=function(){},s=\"prototype\",c=function(){var t,e=n(\"Iw71\")(\"iframe\"),r=o.length,i=\"<\",a=\">\";e.style.display=\"none\",n(\"+rLv\").appendChild(e),e.src=\"javascript:\",t=e.contentWindow.document,t.open(),t.write(i+\"script\"+a+\"document.F=Object\"+i+\"/script\"+a),t.close(),c=t.F;while(r--)delete c[s][o[r]];return c()};t.exports=Object.create||function(t,e){var n;return null!==t?(u[s]=r(t),n=new u,u[s]=null,n[a]=t):n=c(),void 0===e?n:i(n,e)}},Kw5r:function(t,e,n){\"use strict\";(function(t){\n/*!\n * Vue.js v2.5.16\n * (c) 2014-2018 Evan You\n * Released under the MIT License.\n */\nvar n=Object.freeze({});function r(t){return void 0===t||null===t}function i(t){return void 0!==t&&null!==t}function o(t){return!0===t}function a(t){return!1===t}function u(t){return\"string\"===typeof t||\"number\"===typeof t||\"symbol\"===typeof t||\"boolean\"===typeof t}function s(t){return null!==t&&\"object\"===typeof t}var c=Object.prototype.toString;function l(t){return\"[object Object]\"===c.call(t)}function f(t){return\"[object RegExp]\"===c.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function h(t){return null==t?\"\":\"object\"===typeof t?JSON.stringify(t,null,2):String(t)}function d(t){var e=parseFloat(t);return isNaN(e)?t:e}function v(t,e){for(var n=Object.create(null),r=t.split(\",\"),i=0;i<r.length;i++)n[r[i]]=!0;return e?function(t){return n[t.toLowerCase()]}:function(t){return n[t]}}v(\"slot,component\",!0);var y=v(\"key,ref,slot,slot-scope,is\");function g(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}var _=Object.prototype.hasOwnProperty;function m(t,e){return _.call(t,e)}function b(t){var e=Object.create(null);return function(n){var r=e[n];return r||(e[n]=t(n))}}var w=/-(\\w)/g,x=b(function(t){return t.replace(w,function(t,e){return e?e.toUpperCase():\"\"})}),k=b(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),A=/\\B([A-Z])/g,O=b(function(t){return t.replace(A,\"-$1\").toLowerCase()});function C(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function E(t,e){return t.bind(e)}var j=Function.prototype.bind?E:C;function S(t,e){e=e||0;var n=t.length-e,r=new Array(n);while(n--)r[n]=t[n+e];return r}function $(t,e){for(var n in e)t[n]=e[n];return t}function T(t){for(var e={},n=0;n<t.length;n++)t[n]&&$(e,t[n]);return e}function R(t,e,n){}var L=function(t,e,n){return!1},I=function(t){return t};function P(t,e){if(t===e)return!0;var n=s(t),r=s(e);if(!n||!r)return!n&&!r&&String(t)===String(e);try{var i=Array.isArray(t),o=Array.isArray(e);if(i&&o)return t.length===e.length&&t.every(function(t,n){return P(t,e[n])});if(i||o)return!1;var a=Object.keys(t),u=Object.keys(e);return a.length===u.length&&a.every(function(n){return P(t[n],e[n])})}catch(t){return!1}}function M(t,e){for(var n=0;n<t.length;n++)if(P(t[n],e))return n;return-1}function D(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments))}}var U=\"data-server-rendered\",z=[\"component\",\"directive\",\"filter\"],q=[\"beforeCreate\",\"created\",\"beforeMount\",\"mounted\",\"beforeUpdate\",\"updated\",\"beforeDestroy\",\"destroyed\",\"activated\",\"deactivated\",\"errorCaptured\"],N={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:L,isReservedAttr:L,isUnknownElement:L,getTagNamespace:R,parsePlatformTagName:I,mustUseProp:L,_lifecycleHooks:q};function F(t){var e=(t+\"\").charCodeAt(0);return 36===e||95===e}function H(t,e,n,r){Object.defineProperty(t,e,{value:n,enumerable:!!r,writable:!0,configurable:!0})}var W=/[^\\w.$]/;function B(t){if(!W.test(t)){var e=t.split(\".\");return function(t){for(var n=0;n<e.length;n++){if(!t)return;t=t[e[n]]}return t}}}var K,V=\"__proto__\"in{},Z=\"undefined\"!==typeof window,X=\"undefined\"!==typeof WXEnvironment&&!!WXEnvironment.platform,G=X&&WXEnvironment.platform.toLowerCase(),J=Z&&window.navigator.userAgent.toLowerCase(),Y=J&&/msie|trident/.test(J),Q=J&&J.indexOf(\"msie 9.0\")>0,tt=J&&J.indexOf(\"edge/\")>0,et=(J&&J.indexOf(\"android\"),J&&/iphone|ipad|ipod|ios/.test(J)||\"ios\"===G),nt=(J&&/chrome\\/\\d+/.test(J),{}.watch),rt=!1;if(Z)try{var it={};Object.defineProperty(it,\"passive\",{get:function(){rt=!0}}),window.addEventListener(\"test-passive\",null,it)}catch(t){}var ot=function(){return void 0===K&&(K=!Z&&!X&&\"undefined\"!==typeof t&&\"server\"===t[\"process\"].env.VUE_ENV),K},at=Z&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ut(t){return\"function\"===typeof t&&/native code/.test(t.toString())}var st,ct=\"undefined\"!==typeof Symbol&&ut(Symbol)&&\"undefined\"!==typeof Reflect&&ut(Reflect.ownKeys);st=\"undefined\"!==typeof Set&&ut(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var lt=R,ft=0,pt=function(){this.id=ft++,this.subs=[]};pt.prototype.addSub=function(t){this.subs.push(t)},pt.prototype.removeSub=function(t){g(this.subs,t)},pt.prototype.depend=function(){pt.target&&pt.target.addDep(this)},pt.prototype.notify=function(){for(var t=this.subs.slice(),e=0,n=t.length;e<n;e++)t[e].update()},pt.target=null;var ht=[];function dt(t){pt.target&&ht.push(pt.target),pt.target=t}function vt(){pt.target=ht.pop()}var yt=function(t,e,n,r,i,o,a,u){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=i,this.ns=void 0,this.context=o,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=a,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=u,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1},gt={child:{configurable:!0}};gt.child.get=function(){return this.componentInstance},Object.defineProperties(yt.prototype,gt);var _t=function(t){void 0===t&&(t=\"\");var e=new yt;return e.text=t,e.isComment=!0,e};function mt(t){return new yt(void 0,void 0,void 0,String(t))}function bt(t){var e=new yt(t.tag,t.data,t.children,t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.isCloned=!0,e}var wt=Array.prototype,xt=Object.create(wt),kt=[\"push\",\"pop\",\"shift\",\"unshift\",\"splice\",\"sort\",\"reverse\"];kt.forEach(function(t){var e=wt[t];H(xt,t,function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];var i,o=e.apply(this,n),a=this.__ob__;switch(t){case\"push\":case\"unshift\":i=n;break;case\"splice\":i=n.slice(2);break}return i&&a.observeArray(i),a.dep.notify(),o})});var At=Object.getOwnPropertyNames(xt),Ot=!0;function Ct(t){Ot=t}var Et=function(t){if(this.value=t,this.dep=new pt,this.vmCount=0,H(t,\"__ob__\",this),Array.isArray(t)){var e=V?jt:St;e(t,xt,At),this.observeArray(t)}else this.walk(t)};function jt(t,e,n){t.__proto__=e}function St(t,e,n){for(var r=0,i=n.length;r<i;r++){var o=n[r];H(t,o,e[o])}}function $t(t,e){var n;if(s(t)&&!(t instanceof yt))return m(t,\"__ob__\")&&t.__ob__ instanceof Et?n=t.__ob__:Ot&&!ot()&&(Array.isArray(t)||l(t))&&Object.isExtensible(t)&&!t._isVue&&(n=new Et(t)),e&&n&&n.vmCount++,n}function Tt(t,e,n,r,i){var o=new pt,a=Object.getOwnPropertyDescriptor(t,e);if(!a||!1!==a.configurable){var u=a&&a.get;u||2!==arguments.length||(n=t[e]);var s=a&&a.set,c=!i&&$t(n);Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var e=u?u.call(t):n;return pt.target&&(o.depend(),c&&(c.dep.depend(),Array.isArray(e)&&It(e))),e},set:function(e){var r=u?u.call(t):n;e===r||e!==e&&r!==r||(s?s.call(t,e):n=e,c=!i&&$t(e),o.notify())}})}}function Rt(t,e,n){if(Array.isArray(t)&&p(e))return t.length=Math.max(t.length,e),t.splice(e,1,n),n;if(e in t&&!(e in Object.prototype))return t[e]=n,n;var r=t.__ob__;return t._isVue||r&&r.vmCount?n:r?(Tt(r.value,e,n),r.dep.notify(),n):(t[e]=n,n)}function Lt(t,e){if(Array.isArray(t)&&p(e))t.splice(e,1);else{var n=t.__ob__;t._isVue||n&&n.vmCount||m(t,e)&&(delete t[e],n&&n.dep.notify())}}function It(t){for(var e=void 0,n=0,r=t.length;n<r;n++)e=t[n],e&&e.__ob__&&e.__ob__.dep.depend(),Array.isArray(e)&&It(e)}Et.prototype.walk=function(t){for(var e=Object.keys(t),n=0;n<e.length;n++)Tt(t,e[n])},Et.prototype.observeArray=function(t){for(var e=0,n=t.length;e<n;e++)$t(t[e])};var Pt=N.optionMergeStrategies;function Mt(t,e){if(!e)return t;for(var n,r,i,o=Object.keys(e),a=0;a<o.length;a++)n=o[a],r=t[n],i=e[n],m(t,n)?l(r)&&l(i)&&Mt(r,i):Rt(t,n,i);return t}function Dt(t,e,n){return n?function(){var r=\"function\"===typeof e?e.call(n,n):e,i=\"function\"===typeof t?t.call(n,n):t;return r?Mt(r,i):i}:e?t?function(){return Mt(\"function\"===typeof e?e.call(this,this):e,\"function\"===typeof t?t.call(this,this):t)}:e:t}function Ut(t,e){return e?t?t.concat(e):Array.isArray(e)?e:[e]:t}function zt(t,e,n,r){var i=Object.create(t||null);return e?$(i,e):i}Pt.data=function(t,e,n){return n?Dt(t,e,n):e&&\"function\"!==typeof e?t:Dt(t,e)},q.forEach(function(t){Pt[t]=Ut}),z.forEach(function(t){Pt[t+\"s\"]=zt}),Pt.watch=function(t,e,n,r){if(t===nt&&(t=void 0),e===nt&&(e=void 0),!e)return Object.create(t||null);if(!t)return e;var i={};for(var o in $(i,t),e){var a=i[o],u=e[o];a&&!Array.isArray(a)&&(a=[a]),i[o]=a?a.concat(u):Array.isArray(u)?u:[u]}return i},Pt.props=Pt.methods=Pt.inject=Pt.computed=function(t,e,n,r){if(!t)return e;var i=Object.create(null);return $(i,t),e&&$(i,e),i},Pt.provide=Dt;var qt=function(t,e){return void 0===e?t:e};function Nt(t,e){var n=t.props;if(n){var r,i,o,a={};if(Array.isArray(n)){r=n.length;while(r--)i=n[r],\"string\"===typeof i&&(o=x(i),a[o]={type:null})}else if(l(n))for(var u in n)i=n[u],o=x(u),a[o]=l(i)?i:{type:i};else 0;t.props=a}}function Ft(t,e){var n=t.inject;if(n){var r=t.inject={};if(Array.isArray(n))for(var i=0;i<n.length;i++)r[n[i]]={from:n[i]};else if(l(n))for(var o in n){var a=n[o];r[o]=l(a)?$({from:o},a):{from:a}}else 0}}function Ht(t){var e=t.directives;if(e)for(var n in e){var r=e[n];\"function\"===typeof r&&(e[n]={bind:r,update:r})}}function Wt(t,e,n){\"function\"===typeof e&&(e=e.options),Nt(e,n),Ft(e,n),Ht(e);var r=e.extends;if(r&&(t=Wt(t,r,n)),e.mixins)for(var i=0,o=e.mixins.length;i<o;i++)t=Wt(t,e.mixins[i],n);var a,u={};for(a in t)s(a);for(a in e)m(t,a)||s(a);function s(r){var i=Pt[r]||qt;u[r]=i(t[r],e[r],n,r)}return u}function Bt(t,e,n,r){if(\"string\"===typeof n){var i=t[e];if(m(i,n))return i[n];var o=x(n);if(m(i,o))return i[o];var a=k(o);if(m(i,a))return i[a];var u=i[n]||i[o]||i[a];return u}}function Kt(t,e,n,r){var i=e[t],o=!m(n,t),a=n[t],u=Gt(Boolean,i.type);if(u>-1)if(o&&!m(i,\"default\"))a=!1;else if(\"\"===a||a===O(t)){var s=Gt(String,i.type);(s<0||u<s)&&(a=!0)}if(void 0===a){a=Vt(r,i,t);var c=Ot;Ct(!0),$t(a),Ct(c)}return a}function Vt(t,e,n){if(m(e,\"default\")){var r=e.default;return t&&t.$options.propsData&&void 0===t.$options.propsData[n]&&void 0!==t._props[n]?t._props[n]:\"function\"===typeof r&&\"Function\"!==Zt(e.type)?r.call(t):r}}function Zt(t){var e=t&&t.toString().match(/^\\s*function (\\w+)/);return e?e[1]:\"\"}function Xt(t,e){return Zt(t)===Zt(e)}function Gt(t,e){if(!Array.isArray(e))return Xt(e,t)?0:-1;for(var n=0,r=e.length;n<r;n++)if(Xt(e[n],t))return n;return-1}function Jt(t,e,n){if(e){var r=e;while(r=r.$parent){var i=r.$options.errorCaptured;if(i)for(var o=0;o<i.length;o++)try{var a=!1===i[o].call(r,t,e,n);if(a)return}catch(t){Yt(t,r,\"errorCaptured hook\")}}}Yt(t,e,n)}function Yt(t,e,n){if(N.errorHandler)try{return N.errorHandler.call(null,t,e,n)}catch(t){Qt(t,null,\"config.errorHandler\")}Qt(t,e,n)}function Qt(t,e,n){if(!Z&&!X||\"undefined\"===typeof console)throw t;console.error(t)}var te,ee,ne=[],re=!1;function ie(){re=!1;var t=ne.slice(0);ne.length=0;for(var e=0;e<t.length;e++)t[e]()}var oe=!1;if(\"undefined\"!==typeof setImmediate&&ut(setImmediate))ee=function(){setImmediate(ie)};else if(\"undefined\"===typeof MessageChannel||!ut(MessageChannel)&&\"[object MessageChannelConstructor]\"!==MessageChannel.toString())ee=function(){setTimeout(ie,0)};else{var ae=new MessageChannel,ue=ae.port2;ae.port1.onmessage=ie,ee=function(){ue.postMessage(1)}}if(\"undefined\"!==typeof Promise&&ut(Promise)){var se=Promise.resolve();te=function(){se.then(ie),et&&setTimeout(R)}}else te=ee;function ce(t){return t._withTask||(t._withTask=function(){oe=!0;var e=t.apply(null,arguments);return oe=!1,e})}function le(t,e){var n;if(ne.push(function(){if(t)try{t.call(e)}catch(t){Jt(t,e,\"nextTick\")}else n&&n(e)}),re||(re=!0,oe?ee():te()),!t&&\"undefined\"!==typeof Promise)return new Promise(function(t){n=t})}var fe=new st;function pe(t){he(t,fe),fe.clear()}function he(t,e){var n,r,i=Array.isArray(t);if(!(!i&&!s(t)||Object.isFrozen(t)||t instanceof yt)){if(t.__ob__){var o=t.__ob__.dep.id;if(e.has(o))return;e.add(o)}if(i){n=t.length;while(n--)he(t[n],e)}else{r=Object.keys(t),n=r.length;while(n--)he(t[r[n]],e)}}}var de,ve=b(function(t){var e=\"&\"===t.charAt(0);t=e?t.slice(1):t;var n=\"~\"===t.charAt(0);t=n?t.slice(1):t;var r=\"!\"===t.charAt(0);return t=r?t.slice(1):t,{name:t,once:n,capture:r,passive:e}});function ye(t){function e(){var t=arguments,n=e.fns;if(!Array.isArray(n))return n.apply(null,arguments);for(var r=n.slice(),i=0;i<r.length;i++)r[i].apply(null,t)}return e.fns=t,e}function ge(t,e,n,i,o){var a,u,s,c;for(a in t)u=t[a],s=e[a],c=ve(a),r(u)||(r(s)?(r(u.fns)&&(u=t[a]=ye(u)),n(c.name,u,c.once,c.capture,c.passive,c.params)):u!==s&&(s.fns=u,t[a]=s));for(a in e)r(t[a])&&(c=ve(a),i(c.name,e[a],c.capture))}function _e(t,e,n){var a;t instanceof yt&&(t=t.data.hook||(t.data.hook={}));var u=t[e];function s(){n.apply(this,arguments),g(a.fns,s)}r(u)?a=ye([s]):i(u.fns)&&o(u.merged)?(a=u,a.fns.push(s)):a=ye([u,s]),a.merged=!0,t[e]=a}function me(t,e,n){var o=e.options.props;if(!r(o)){var a={},u=t.attrs,s=t.props;if(i(u)||i(s))for(var c in o){var l=O(c);be(a,s,c,l,!0)||be(a,u,c,l,!1)}return a}}function be(t,e,n,r,o){if(i(e)){if(m(e,n))return t[n]=e[n],o||delete e[n],!0;if(m(e,r))return t[n]=e[r],o||delete e[r],!0}return!1}function we(t){for(var e=0;e<t.length;e++)if(Array.isArray(t[e]))return Array.prototype.concat.apply([],t);return t}function xe(t){return u(t)?[mt(t)]:Array.isArray(t)?Ae(t):void 0}function ke(t){return i(t)&&i(t.text)&&a(t.isComment)}function Ae(t,e){var n,a,s,c,l=[];for(n=0;n<t.length;n++)a=t[n],r(a)||\"boolean\"===typeof a||(s=l.length-1,c=l[s],Array.isArray(a)?a.length>0&&(a=Ae(a,(e||\"\")+\"_\"+n),ke(a[0])&&ke(c)&&(l[s]=mt(c.text+a[0].text),a.shift()),l.push.apply(l,a)):u(a)?ke(c)?l[s]=mt(c.text+a):\"\"!==a&&l.push(mt(a)):ke(a)&&ke(c)?l[s]=mt(c.text+a.text):(o(t._isVList)&&i(a.tag)&&r(a.key)&&i(e)&&(a.key=\"__vlist\"+e+\"_\"+n+\"__\"),l.push(a)));return l}function Oe(t,e){return(t.__esModule||ct&&\"Module\"===t[Symbol.toStringTag])&&(t=t.default),s(t)?e.extend(t):t}function Ce(t,e,n,r,i){var o=_t();return o.asyncFactory=t,o.asyncMeta={data:e,context:n,children:r,tag:i},o}function Ee(t,e,n){if(o(t.error)&&i(t.errorComp))return t.errorComp;if(i(t.resolved))return t.resolved;if(o(t.loading)&&i(t.loadingComp))return t.loadingComp;if(!i(t.contexts)){var a=t.contexts=[n],u=!0,c=function(){for(var t=0,e=a.length;t<e;t++)a[t].$forceUpdate()},l=D(function(n){t.resolved=Oe(n,e),u||c()}),f=D(function(e){i(t.errorComp)&&(t.error=!0,c())}),p=t(l,f);return s(p)&&(\"function\"===typeof p.then?r(t.resolved)&&p.then(l,f):i(p.component)&&\"function\"===typeof p.component.then&&(p.component.then(l,f),i(p.error)&&(t.errorComp=Oe(p.error,e)),i(p.loading)&&(t.loadingComp=Oe(p.loading,e),0===p.delay?t.loading=!0:setTimeout(function(){r(t.resolved)&&r(t.error)&&(t.loading=!0,c())},p.delay||200)),i(p.timeout)&&setTimeout(function(){r(t.resolved)&&f(null)},p.timeout))),u=!1,t.loading?t.loadingComp:t.resolved}t.contexts.push(n)}function je(t){return t.isComment&&t.asyncFactory}function Se(t){if(Array.isArray(t))for(var e=0;e<t.length;e++){var n=t[e];if(i(n)&&(i(n.componentOptions)||je(n)))return n}}function $e(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Le(t,e)}function Te(t,e,n){n?de.$once(t,e):de.$on(t,e)}function Re(t,e){de.$off(t,e)}function Le(t,e,n){de=t,ge(e,n||{},Te,Re,t),de=void 0}function Ie(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this,i=this;if(Array.isArray(t))for(var o=0,a=t.length;o<a;o++)r.$on(t[o],n);else(i._events[t]||(i._events[t]=[])).push(n),e.test(t)&&(i._hasHookEvent=!0);return i},t.prototype.$once=function(t,e){var n=this;function r(){n.$off(t,r),e.apply(n,arguments)}return r.fn=e,n.$on(t,r),n},t.prototype.$off=function(t,e){var n=this,r=this;if(!arguments.length)return r._events=Object.create(null),r;if(Array.isArray(t)){for(var i=0,o=t.length;i<o;i++)n.$off(t[i],e);return r}var a=r._events[t];if(!a)return r;if(!e)return r._events[t]=null,r;if(e){var u,s=a.length;while(s--)if(u=a[s],u===e||u.fn===e){a.splice(s,1);break}}return r},t.prototype.$emit=function(t){var e=this,n=e._events[t];if(n){n=n.length>1?S(n):n;for(var r=S(arguments,1),i=0,o=n.length;i<o;i++)try{n[i].apply(e,r)}catch(n){Jt(n,e,'event handler for \"'+t+'\"')}}return e}}function Pe(t,e){var n={};if(!t)return n;for(var r=0,i=t.length;r<i;r++){var o=t[r],a=o.data;if(a&&a.attrs&&a.attrs.slot&&delete a.attrs.slot,o.context!==e&&o.fnContext!==e||!a||null==a.slot)(n.default||(n.default=[])).push(o);else{var u=a.slot,s=n[u]||(n[u]=[]);\"template\"===o.tag?s.push.apply(s,o.children||[]):s.push(o)}}for(var c in n)n[c].every(Me)&&delete n[c];return n}function Me(t){return t.isComment&&!t.asyncFactory||\" \"===t.text}function De(t,e){e=e||{};for(var n=0;n<t.length;n++)Array.isArray(t[n])?De(t[n],e):e[t[n].key]=t[n].fn;return e}var Ue=null;function ze(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){while(n.$options.abstract&&n.$parent)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}function qe(t){t.prototype._update=function(t,e){var n=this;n._isMounted&&Ke(n,\"beforeUpdate\");var r=n.$el,i=n._vnode,o=Ue;Ue=n,n._vnode=t,i?n.$el=n.__patch__(i,t):(n.$el=n.__patch__(n.$el,t,e,!1,n.$options._parentElm,n.$options._refElm),n.$options._parentElm=n.$options._refElm=null),Ue=o,r&&(r.__vue__=null),n.$el&&(n.$el.__vue__=n),n.$vnode&&n.$parent&&n.$vnode===n.$parent._vnode&&(n.$parent.$el=n.$el)},t.prototype.$forceUpdate=function(){var t=this;t._watcher&&t._watcher.update()},t.prototype.$destroy=function(){var t=this;if(!t._isBeingDestroyed){Ke(t,\"beforeDestroy\"),t._isBeingDestroyed=!0;var e=t.$parent;!e||e._isBeingDestroyed||t.$options.abstract||g(e.$children,t),t._watcher&&t._watcher.teardown();var n=t._watchers.length;while(n--)t._watchers[n].teardown();t._data.__ob__&&t._data.__ob__.vmCount--,t._isDestroyed=!0,t.__patch__(t._vnode,null),Ke(t,\"destroyed\"),t.$off(),t.$el&&(t.$el.__vue__=null),t.$vnode&&(t.$vnode.parent=null)}}}function Ne(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=_t),Ke(t,\"beforeMount\"),r=function(){t._update(t._render(),n)},new un(t,r,R,null,!0),n=!1,null==t.$vnode&&(t._isMounted=!0,Ke(t,\"mounted\")),t}function Fe(t,e,r,i,o){var a=!!(o||t.$options._renderChildren||i.data.scopedSlots||t.$scopedSlots!==n);if(t.$options._parentVnode=i,t.$vnode=i,t._vnode&&(t._vnode.parent=i),t.$options._renderChildren=o,t.$attrs=i.data.attrs||n,t.$listeners=r||n,e&&t.$options.props){Ct(!1);for(var u=t._props,s=t.$options._propKeys||[],c=0;c<s.length;c++){var l=s[c],f=t.$options.props;u[l]=Kt(l,f,e,t)}Ct(!0),t.$options.propsData=e}r=r||n;var p=t.$options._parentListeners;t.$options._parentListeners=r,Le(t,r,p),a&&(t.$slots=Pe(o,i.context),t.$forceUpdate())}function He(t){while(t&&(t=t.$parent))if(t._inactive)return!0;return!1}function We(t,e){if(e){if(t._directInactive=!1,He(t))return}else if(t._directInactive)return;if(t._inactive||null===t._inactive){t._inactive=!1;for(var n=0;n<t.$children.length;n++)We(t.$children[n]);Ke(t,\"activated\")}}function Be(t,e){if((!e||(t._directInactive=!0,!He(t)))&&!t._inactive){t._inactive=!0;for(var n=0;n<t.$children.length;n++)Be(t.$children[n]);Ke(t,\"deactivated\")}}function Ke(t,e){dt();var n=t.$options[e];if(n)for(var r=0,i=n.length;r<i;r++)try{n[r].call(t)}catch(n){Jt(n,t,e+\" hook\")}t._hasHookEvent&&t.$emit(\"hook:\"+e),vt()}var Ve=[],Ze=[],Xe={},Ge=!1,Je=!1,Ye=0;function Qe(){Ye=Ve.length=Ze.length=0,Xe={},Ge=Je=!1}function tn(){var t,e;for(Je=!0,Ve.sort(function(t,e){return t.id-e.id}),Ye=0;Ye<Ve.length;Ye++)t=Ve[Ye],e=t.id,Xe[e]=null,t.run();var n=Ze.slice(),r=Ve.slice();Qe(),rn(n),en(r),at&&N.devtools&&at.emit(\"flush\")}function en(t){var e=t.length;while(e--){var n=t[e],r=n.vm;r._watcher===n&&r._isMounted&&Ke(r,\"updated\")}}function nn(t){t._inactive=!1,Ze.push(t)}function rn(t){for(var e=0;e<t.length;e++)t[e]._inactive=!0,We(t[e],!0)}function on(t){var e=t.id;if(null==Xe[e]){if(Xe[e]=!0,Je){var n=Ve.length-1;while(n>Ye&&Ve[n].id>t.id)n--;Ve.splice(n+1,0,t)}else Ve.push(t);Ge||(Ge=!0,le(tn))}}var an=0,un=function(t,e,n,r,i){this.vm=t,i&&(t._watcher=this),t._watchers.push(this),r?(this.deep=!!r.deep,this.user=!!r.user,this.lazy=!!r.lazy,this.sync=!!r.sync):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++an,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new st,this.newDepIds=new st,this.expression=\"\",\"function\"===typeof e?this.getter=e:(this.getter=B(e),this.getter||(this.getter=function(){})),this.value=this.lazy?void 0:this.get()};un.prototype.get=function(){var t;dt(this);var e=this.vm;try{t=this.getter.call(e,e)}catch(t){if(!this.user)throw t;Jt(t,e,'getter for watcher \"'+this.expression+'\"')}finally{this.deep&&pe(t),vt(),this.cleanupDeps()}return t},un.prototype.addDep=function(t){var e=t.id;this.newDepIds.has(e)||(this.newDepIds.add(e),this.newDeps.push(t),this.depIds.has(e)||t.addSub(this))},un.prototype.cleanupDeps=function(){var t=this,e=this.deps.length;while(e--){var n=t.deps[e];t.newDepIds.has(n.id)||n.removeSub(t)}var r=this.depIds;this.depIds=this.newDepIds,this.newDepIds=r,this.newDepIds.clear(),r=this.deps,this.deps=this.newDeps,this.newDeps=r,this.newDeps.length=0},un.prototype.update=function(){this.lazy?this.dirty=!0:this.sync?this.run():on(this)},un.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||s(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Jt(t,this.vm,'callback for watcher \"'+this.expression+'\"')}else this.cb.call(this.vm,t,e)}}},un.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},un.prototype.depend=function(){var t=this,e=this.deps.length;while(e--)t.deps[e].depend()},un.prototype.teardown=function(){var t=this;if(this.active){this.vm._isBeingDestroyed||g(this.vm._watchers,this);var e=this.deps.length;while(e--)t.deps[e].removeSub(t);this.active=!1}};var sn={enumerable:!0,configurable:!0,get:R,set:R};function cn(t,e,n){sn.get=function(){return this[e][n]},sn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,sn)}function ln(t){t._watchers=[];var e=t.$options;e.props&&fn(t,e.props),e.methods&&_n(t,e.methods),e.data?pn(t):$t(t._data={},!0),e.computed&&vn(t,e.computed),e.watch&&e.watch!==nt&&mn(t,e.watch)}function fn(t,e){var n=t.$options.propsData||{},r=t._props={},i=t.$options._propKeys=[],o=!t.$parent;o||Ct(!1);var a=function(o){i.push(o);var a=Kt(o,e,n,t);Tt(r,o,a),o in t||cn(t,\"_props\",o)};for(var u in e)a(u);Ct(!0)}function pn(t){var e=t.$options.data;e=t._data=\"function\"===typeof e?hn(e,t):e||{},l(e)||(e={});var n=Object.keys(e),r=t.$options.props,i=(t.$options.methods,n.length);while(i--){var o=n[i];0,r&&m(r,o)||F(o)||cn(t,\"_data\",o)}$t(e,!0)}function hn(t,e){dt();try{return t.call(e,e)}catch(t){return Jt(t,e,\"data()\"),{}}finally{vt()}}var dn={lazy:!0};function vn(t,e){var n=t._computedWatchers=Object.create(null),r=ot();for(var i in e){var o=e[i],a=\"function\"===typeof o?o:o.get;0,r||(n[i]=new un(t,a||R,R,dn)),i in t||yn(t,i,o)}}function yn(t,e,n){var r=!ot();\"function\"===typeof n?(sn.get=r?gn(e):n,sn.set=R):(sn.get=n.get?r&&!1!==n.cache?gn(e):n.get:R,sn.set=n.set?n.set:R),Object.defineProperty(t,e,sn)}function gn(t){return function(){var e=this._computedWatchers&&this._computedWatchers[t];if(e)return e.dirty&&e.evaluate(),pt.target&&e.depend(),e.value}}function _n(t,e){t.$options.props;for(var n in e)t[n]=null==e[n]?R:j(e[n],t)}function mn(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var i=0;i<r.length;i++)bn(t,n,r[i]);else bn(t,n,r)}}function bn(t,e,n,r){return l(n)&&(r=n,n=n.handler),\"string\"===typeof n&&(n=t[n]),t.$watch(e,n,r)}function wn(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,\"$data\",e),Object.defineProperty(t.prototype,\"$props\",n),t.prototype.$set=Rt,t.prototype.$delete=Lt,t.prototype.$watch=function(t,e,n){var r=this;if(l(e))return bn(r,t,e,n);n=n||{},n.user=!0;var i=new un(r,t,e,n);return n.immediate&&e.call(r,i.value),function(){i.teardown()}}}function xn(t){var e=t.$options.provide;e&&(t._provided=\"function\"===typeof e?e.call(t):e)}function kn(t){var e=An(t.$options.inject,t);e&&(Ct(!1),Object.keys(e).forEach(function(n){Tt(t,n,e[n])}),Ct(!0))}function An(t,e){if(t){for(var n=Object.create(null),r=ct?Reflect.ownKeys(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}):Object.keys(t),i=0;i<r.length;i++){var o=r[i],a=t[o].from,u=e;while(u){if(u._provided&&m(u._provided,a)){n[o]=u._provided[a];break}u=u.$parent}if(!u)if(\"default\"in t[o]){var s=t[o].default;n[o]=\"function\"===typeof s?s.call(e):s}else 0}return n}}function On(t,e){var n,r,o,a,u;if(Array.isArray(t)||\"string\"===typeof t)for(n=new Array(t.length),r=0,o=t.length;r<o;r++)n[r]=e(t[r],r);else if(\"number\"===typeof t)for(n=new Array(t),r=0;r<t;r++)n[r]=e(r+1,r);else if(s(t))for(a=Object.keys(t),n=new Array(a.length),r=0,o=a.length;r<o;r++)u=a[r],n[r]=e(t[u],u,r);return i(n)&&(n._isVList=!0),n}function Cn(t,e,n,r){var i,o=this.$scopedSlots[t];if(o)n=n||{},r&&(n=$($({},r),n)),i=o(n)||e;else{var a=this.$slots[t];a&&(a._rendered=!0),i=a||e}var u=n&&n.slot;return u?this.$createElement(\"template\",{slot:u},i):i}function En(t){return Bt(this.$options,\"filters\",t,!0)||I}function jn(t,e){return Array.isArray(t)?-1===t.indexOf(e):t!==e}function Sn(t,e,n,r,i){var o=N.keyCodes[e]||n;return i&&r&&!N.keyCodes[e]?jn(i,r):o?jn(o,t):r?O(r)!==e:void 0}function $n(t,e,n,r,i){if(n)if(s(n)){var o;Array.isArray(n)&&(n=T(n));var a=function(a){if(\"class\"===a||\"style\"===a||y(a))o=t;else{var u=t.attrs&&t.attrs.type;o=r||N.mustUseProp(e,u,a)?t.domProps||(t.domProps={}):t.attrs||(t.attrs={})}if(!(a in o)&&(o[a]=n[a],i)){var s=t.on||(t.on={});s[\"update:\"+a]=function(t){n[a]=t}}};for(var u in n)a(u)}else;return t}function Tn(t,e){var n=this._staticTrees||(this._staticTrees=[]),r=n[t];return r&&!e?r:(r=n[t]=this.$options.staticRenderFns[t].call(this._renderProxy,null,this),Ln(r,\"__static__\"+t,!1),r)}function Rn(t,e,n){return Ln(t,\"__once__\"+e+(n?\"_\"+n:\"\"),!0),t}function Ln(t,e,n){if(Array.isArray(t))for(var r=0;r<t.length;r++)t[r]&&\"string\"!==typeof t[r]&&In(t[r],e+\"_\"+r,n);else In(t,e,n)}function In(t,e,n){t.isStatic=!0,t.key=e,t.isOnce=n}function Pn(t,e){if(e)if(l(e)){var n=t.on=t.on?$({},t.on):{};for(var r in e){var i=n[r],o=e[r];n[r]=i?[].concat(i,o):o}}else;return t}function Mn(t){t._o=Rn,t._n=d,t._s=h,t._l=On,t._t=Cn,t._q=P,t._i=M,t._m=Tn,t._f=En,t._k=Sn,t._b=$n,t._v=mt,t._e=_t,t._u=De,t._g=Pn}function Dn(t,e,r,i,a){var u,s=a.options;m(i,\"_uid\")?(u=Object.create(i),u._original=i):(u=i,i=i._original);var c=o(s._compiled),l=!c;this.data=t,this.props=e,this.children=r,this.parent=i,this.listeners=t.on||n,this.injections=An(s.inject,i),this.slots=function(){return Pe(r,i)},c&&(this.$options=s,this.$slots=this.slots(),this.$scopedSlots=t.scopedSlots||n),s._scopeId?this._c=function(t,e,n,r){var o=Xn(u,t,e,n,r,l);return o&&!Array.isArray(o)&&(o.fnScopeId=s._scopeId,o.fnContext=i),o}:this._c=function(t,e,n,r){return Xn(u,t,e,n,r,l)}}function Un(t,e,r,o,a){var u=t.options,s={},c=u.props;if(i(c))for(var l in c)s[l]=Kt(l,c,e||n);else i(r.attrs)&&qn(s,r.attrs),i(r.props)&&qn(s,r.props);var f=new Dn(r,s,a,o,t),p=u.render.call(null,f._c,f);if(p instanceof yt)return zn(p,r,f.parent,u);if(Array.isArray(p)){for(var h=xe(p)||[],d=new Array(h.length),v=0;v<h.length;v++)d[v]=zn(h[v],r,f.parent,u);return d}}function zn(t,e,n,r){var i=bt(t);return i.fnContext=n,i.fnOptions=r,e.slot&&((i.data||(i.data={})).slot=e.slot),i}function qn(t,e){for(var n in e)t[x(n)]=e[n]}Mn(Dn.prototype);var Nn={init:function(t,e,n,r){if(t.componentInstance&&!t.componentInstance._isDestroyed&&t.data.keepAlive){var i=t;Nn.prepatch(i,i)}else{var o=t.componentInstance=Wn(t,Ue,n,r);o.$mount(e?t.elm:void 0,e)}},prepatch:function(t,e){var n=e.componentOptions,r=e.componentInstance=t.componentInstance;Fe(r,n.propsData,n.listeners,e,n.children)},insert:function(t){var e=t.context,n=t.componentInstance;n._isMounted||(n._isMounted=!0,Ke(n,\"mounted\")),t.data.keepAlive&&(e._isMounted?nn(n):We(n,!0))},destroy:function(t){var e=t.componentInstance;e._isDestroyed||(t.data.keepAlive?Be(e,!0):e.$destroy())}},Fn=Object.keys(Nn);function Hn(t,e,n,a,u){if(!r(t)){var c=n.$options._base;if(s(t)&&(t=c.extend(t)),\"function\"===typeof t){var l;if(r(t.cid)&&(l=t,t=Ee(l,c,n),void 0===t))return Ce(l,e,n,a,u);e=e||{},ir(t),i(e.model)&&Kn(t.options,e);var f=me(e,t,u);if(o(t.options.functional))return Un(t,f,e,n,a);var p=e.on;if(e.on=e.nativeOn,o(t.options.abstract)){var h=e.slot;e={},h&&(e.slot=h)}Bn(e);var d=t.options.name||u,v=new yt(\"vue-component-\"+t.cid+(d?\"-\"+d:\"\"),e,void 0,void 0,void 0,n,{Ctor:t,propsData:f,listeners:p,tag:u,children:a},l);return v}}}function Wn(t,e,n,r){var o={_isComponent:!0,parent:e,_parentVnode:t,_parentElm:n||null,_refElm:r||null},a=t.data.inlineTemplate;return i(a)&&(o.render=a.render,o.staticRenderFns=a.staticRenderFns),new t.componentOptions.Ctor(o)}function Bn(t){for(var e=t.hook||(t.hook={}),n=0;n<Fn.length;n++){var r=Fn[n];e[r]=Nn[r]}}function Kn(t,e){var n=t.model&&t.model.prop||\"value\",r=t.model&&t.model.event||\"input\";(e.props||(e.props={}))[n]=e.model.value;var o=e.on||(e.on={});i(o[r])?o[r]=[e.model.callback].concat(o[r]):o[r]=e.model.callback}var Vn=1,Zn=2;function Xn(t,e,n,r,i,a){return(Array.isArray(n)||u(n))&&(i=r,r=n,n=void 0),o(a)&&(i=Zn),Gn(t,e,n,r,i)}function Gn(t,e,n,r,o){if(i(n)&&i(n.__ob__))return _t();if(i(n)&&i(n.is)&&(e=n.is),!e)return _t();var a,u,s;(Array.isArray(r)&&\"function\"===typeof r[0]&&(n=n||{},n.scopedSlots={default:r[0]},r.length=0),o===Zn?r=xe(r):o===Vn&&(r=we(r)),\"string\"===typeof e)?(u=t.$vnode&&t.$vnode.ns||N.getTagNamespace(e),a=N.isReservedTag(e)?new yt(N.parsePlatformTagName(e),n,r,void 0,void 0,t):i(s=Bt(t.$options,\"components\",e))?Hn(s,n,t,r,e):new yt(e,n,r,void 0,void 0,t)):a=Hn(e,n,t,r);return Array.isArray(a)?a:i(a)?(i(u)&&Jn(a,u),i(n)&&Yn(n),a):_t()}function Jn(t,e,n){if(t.ns=e,\"foreignObject\"===t.tag&&(e=void 0,n=!0),i(t.children))for(var a=0,u=t.children.length;a<u;a++){var s=t.children[a];i(s.tag)&&(r(s.ns)||o(n)&&\"svg\"!==s.tag)&&Jn(s,e,n)}}function Yn(t){s(t.style)&&pe(t.style),s(t.class)&&pe(t.class)}function Qn(t){t._vnode=null,t._staticTrees=null;var e=t.$options,r=t.$vnode=e._parentVnode,i=r&&r.context;t.$slots=Pe(e._renderChildren,i),t.$scopedSlots=n,t._c=function(e,n,r,i){return Xn(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return Xn(t,e,n,r,i,!0)};var o=r&&r.data;Tt(t,\"$attrs\",o&&o.attrs||n,null,!0),Tt(t,\"$listeners\",e._parentListeners||n,null,!0)}function tr(t){Mn(t.prototype),t.prototype.$nextTick=function(t){return le(t,this)},t.prototype._render=function(){var t,e=this,r=e.$options,i=r.render,o=r._parentVnode;o&&(e.$scopedSlots=o.data.scopedSlots||n),e.$vnode=o;try{t=i.call(e._renderProxy,e.$createElement)}catch(n){Jt(n,e,\"render\"),t=e._vnode}return t instanceof yt||(t=_t()),t.parent=o,t}}var er=0;function nr(t){t.prototype._init=function(t){var e=this;e._uid=er++,e._isVue=!0,t&&t._isComponent?rr(e,t):e.$options=Wt(ir(e.constructor),t||{},e),e._renderProxy=e,e._self=e,ze(e),$e(e),Qn(e),Ke(e,\"beforeCreate\"),kn(e),ln(e),xn(e),Ke(e,\"created\"),e.$options.el&&e.$mount(e.$options.el)}}function rr(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r,n._parentElm=e._parentElm,n._refElm=e._refElm;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}function ir(t){var e=t.options;if(t.super){var n=ir(t.super),r=t.superOptions;if(n!==r){t.superOptions=n;var i=or(t);i&&$(t.extendOptions,i),e=t.options=Wt(n,t.extendOptions),e.name&&(e.components[e.name]=t)}}return e}function or(t){var e,n=t.options,r=t.extendOptions,i=t.sealedOptions;for(var o in n)n[o]!==i[o]&&(e||(e={}),e[o]=ar(n[o],r[o],i[o]));return e}function ar(t,e,n){if(Array.isArray(t)){var r=[];n=Array.isArray(n)?n:[n],e=Array.isArray(e)?e:[e];for(var i=0;i<t.length;i++)(e.indexOf(t[i])>=0||n.indexOf(t[i])<0)&&r.push(t[i]);return r}return t}function ur(t){this._init(t)}function sr(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=S(arguments,1);return n.unshift(this),\"function\"===typeof t.install?t.install.apply(t,n):\"function\"===typeof t&&t.apply(null,n),e.push(t),this}}function cr(t){t.mixin=function(t){return this.options=Wt(this.options,t),this}}function lr(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i[r])return i[r];var o=t.name||n.options.name;var a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=Wt(n.options,t),a[\"super\"]=n,a.options.props&&fr(a),a.options.computed&&pr(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,z.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=$({},a.options),i[r]=a,a}}function fr(t){var e=t.options.props;for(var n in e)cn(t.prototype,\"_props\",n)}function pr(t){var e=t.options.computed;for(var n in e)yn(t.prototype,n,e[n])}function hr(t){z.forEach(function(e){t[e]=function(t,n){return n?(\"component\"===e&&l(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),\"directive\"===e&&\"function\"===typeof n&&(n={bind:n,update:n}),this.options[e+\"s\"][t]=n,n):this.options[e+\"s\"][t]}})}function dr(t){return t&&(t.Ctor.options.name||t.tag)}function vr(t,e){return Array.isArray(t)?t.indexOf(e)>-1:\"string\"===typeof t?t.split(\",\").indexOf(e)>-1:!!f(t)&&t.test(e)}function yr(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var u=dr(a.componentOptions);u&&!e(u)&&gr(n,o,r,i)}}}function gr(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,g(n,e)}nr(ur),wn(ur),Ie(ur),qe(ur),tr(ur);var _r=[String,RegExp,Array],mr={name:\"keep-alive\",abstract:!0,props:{include:_r,exclude:_r,max:[String,Number]},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){var t=this;for(var e in t.cache)gr(t.cache,e,t.keys)},mounted:function(){var t=this;this.$watch(\"include\",function(e){yr(t,function(t){return vr(e,t)})}),this.$watch(\"exclude\",function(e){yr(t,function(t){return!vr(e,t)})})},render:function(){var t=this.$slots.default,e=Se(t),n=e&&e.componentOptions;if(n){var r=dr(n),i=this,o=i.include,a=i.exclude;if(o&&(!r||!vr(o,r))||a&&r&&vr(a,r))return e;var u=this,s=u.cache,c=u.keys,l=null==e.key?n.Ctor.cid+(n.tag?\"::\"+n.tag:\"\"):e.key;s[l]?(e.componentInstance=s[l].componentInstance,g(c,l),c.push(l)):(s[l]=e,c.push(l),this.max&&c.length>parseInt(this.max)&&gr(s,c[0],c,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}},br={KeepAlive:mr};function wr(t){var e={get:function(){return N}};Object.defineProperty(t,\"config\",e),t.util={warn:lt,extend:$,mergeOptions:Wt,defineReactive:Tt},t.set=Rt,t.delete=Lt,t.nextTick=le,t.options=Object.create(null),z.forEach(function(e){t.options[e+\"s\"]=Object.create(null)}),t.options._base=t,$(t.options.components,br),sr(t),cr(t),lr(t),hr(t)}wr(ur),Object.defineProperty(ur.prototype,\"$isServer\",{get:ot}),Object.defineProperty(ur.prototype,\"$ssrContext\",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(ur,\"FunctionalRenderContext\",{value:Dn}),ur.version=\"2.5.16\";var xr=v(\"style,class\"),kr=v(\"input,textarea,option,select,progress\"),Ar=function(t,e,n){return\"value\"===n&&kr(t)&&\"button\"!==e||\"selected\"===n&&\"option\"===t||\"checked\"===n&&\"input\"===t||\"muted\"===n&&\"video\"===t},Or=v(\"contenteditable,draggable,spellcheck\"),Cr=v(\"allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible\"),Er=\"http://www.w3.org/1999/xlink\",jr=function(t){return\":\"===t.charAt(5)&&\"xlink\"===t.slice(0,5)},Sr=function(t){return jr(t)?t.slice(6,t.length):\"\"},$r=function(t){return null==t||!1===t};function Tr(t){var e=t.data,n=t,r=t;while(i(r.componentInstance))r=r.componentInstance._vnode,r&&r.data&&(e=Rr(r.data,e));while(i(n=n.parent))n&&n.data&&(e=Rr(e,n.data));return Lr(e.staticClass,e.class)}function Rr(t,e){return{staticClass:Ir(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function Lr(t,e){return i(t)||i(e)?Ir(t,Pr(e)):\"\"}function Ir(t,e){return t?e?t+\" \"+e:t:e||\"\"}function Pr(t){return Array.isArray(t)?Mr(t):s(t)?Dr(t):\"string\"===typeof t?t:\"\"}function Mr(t){for(var e,n=\"\",r=0,o=t.length;r<o;r++)i(e=Pr(t[r]))&&\"\"!==e&&(n&&(n+=\" \"),n+=e);return n}function Dr(t){var e=\"\";for(var n in t)t[n]&&(e&&(e+=\" \"),e+=n);return e}var Ur={svg:\"http://www.w3.org/2000/svg\",math:\"http://www.w3.org/1998/Math/MathML\"},zr=v(\"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot\"),qr=v(\"svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view\",!0),Nr=function(t){return zr(t)||qr(t)};function Fr(t){return qr(t)?\"svg\":\"math\"===t?\"math\":void 0}var Hr=Object.create(null);function Wr(t){if(!Z)return!0;if(Nr(t))return!1;if(t=t.toLowerCase(),null!=Hr[t])return Hr[t];var e=document.createElement(t);return t.indexOf(\"-\")>-1?Hr[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Hr[t]=/HTMLUnknownElement/.test(e.toString())}var Br=v(\"text,number,password,search,email,tel,url\");function Kr(t){if(\"string\"===typeof t){var e=document.querySelector(t);return e||document.createElement(\"div\")}return t}function Vr(t,e){var n=document.createElement(t);return\"select\"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute(\"multiple\",\"multiple\"),n)}function Zr(t,e){return document.createElementNS(Ur[t],e)}function Xr(t){return document.createTextNode(t)}function Gr(t){return document.createComment(t)}function Jr(t,e,n){t.insertBefore(e,n)}function Yr(t,e){t.removeChild(e)}function Qr(t,e){t.appendChild(e)}function ti(t){return t.parentNode}function ei(t){return t.nextSibling}function ni(t){return t.tagName}function ri(t,e){t.textContent=e}function ii(t,e){t.setAttribute(e,\"\")}var oi=Object.freeze({createElement:Vr,createElementNS:Zr,createTextNode:Xr,createComment:Gr,insertBefore:Jr,removeChild:Yr,appendChild:Qr,parentNode:ti,nextSibling:ei,tagName:ni,setTextContent:ri,setStyleScope:ii}),ai={create:function(t,e){ui(e)},update:function(t,e){t.data.ref!==e.data.ref&&(ui(t,!0),ui(e))},destroy:function(t){ui(t,!0)}};function ui(t,e){var n=t.data.ref;if(i(n)){var r=t.context,o=t.componentInstance||t.elm,a=r.$refs;e?Array.isArray(a[n])?g(a[n],o):a[n]===o&&(a[n]=void 0):t.data.refInFor?Array.isArray(a[n])?a[n].indexOf(o)<0&&a[n].push(o):a[n]=[o]:a[n]=o}}var si=new yt(\"\",{},[]),ci=[\"create\",\"activate\",\"update\",\"remove\",\"destroy\"];function li(t,e){return t.key===e.key&&(t.tag===e.tag&&t.isComment===e.isComment&&i(t.data)===i(e.data)&&fi(t,e)||o(t.isAsyncPlaceholder)&&t.asyncFactory===e.asyncFactory&&r(e.asyncFactory.error))}function fi(t,e){if(\"input\"!==t.tag)return!0;var n,r=i(n=t.data)&&i(n=n.attrs)&&n.type,o=i(n=e.data)&&i(n=n.attrs)&&n.type;return r===o||Br(r)&&Br(o)}function pi(t,e,n){var r,o,a={};for(r=e;r<=n;++r)o=t[r].key,i(o)&&(a[o]=r);return a}function hi(t){var e,n,a={},s=t.modules,c=t.nodeOps;for(e=0;e<ci.length;++e)for(a[ci[e]]=[],n=0;n<s.length;++n)i(s[n][ci[e]])&&a[ci[e]].push(s[n][ci[e]]);function l(t){return new yt(c.tagName(t).toLowerCase(),{},[],void 0,t)}function f(t,e){function n(){0===--n.listeners&&p(t)}return n.listeners=e,n}function p(t){var e=c.parentNode(t);i(e)&&c.removeChild(e,t)}function h(t,e,n,r,a,u,s){if(i(t.elm)&&i(u)&&(t=u[s]=bt(t)),t.isRootInsert=!a,!d(t,e,n,r)){var l=t.data,f=t.children,p=t.tag;i(p)?(t.elm=t.ns?c.createElementNS(t.ns,p):c.createElement(p,t),x(t),m(t,f,e),i(l)&&w(t,e),_(n,t.elm,r)):o(t.isComment)?(t.elm=c.createComment(t.text),_(n,t.elm,r)):(t.elm=c.createTextNode(t.text),_(n,t.elm,r))}}function d(t,e,n,r){var a=t.data;if(i(a)){var u=i(t.componentInstance)&&a.keepAlive;if(i(a=a.hook)&&i(a=a.init)&&a(t,!1,n,r),i(t.componentInstance))return y(t,e),o(u)&&g(t,e,n,r),!0}}function y(t,e){i(t.data.pendingInsert)&&(e.push.apply(e,t.data.pendingInsert),t.data.pendingInsert=null),t.elm=t.componentInstance.$el,b(t)?(w(t,e),x(t)):(ui(t),e.push(t))}function g(t,e,n,r){var o,u=t;while(u.componentInstance)if(u=u.componentInstance._vnode,i(o=u.data)&&i(o=o.transition)){for(o=0;o<a.activate.length;++o)a.activate[o](si,u);e.push(u);break}_(n,t.elm,r)}function _(t,e,n){i(t)&&(i(n)?n.parentNode===t&&c.insertBefore(t,e,n):c.appendChild(t,e))}function m(t,e,n){if(Array.isArray(e)){0;for(var r=0;r<e.length;++r)h(e[r],n,t.elm,null,!0,e,r)}else u(t.text)&&c.appendChild(t.elm,c.createTextNode(String(t.text)))}function b(t){while(t.componentInstance)t=t.componentInstance._vnode;return i(t.tag)}function w(t,n){for(var r=0;r<a.create.length;++r)a.create[r](si,t);e=t.data.hook,i(e)&&(i(e.create)&&e.create(si,t),i(e.insert)&&n.push(t))}function x(t){var e;if(i(e=t.fnScopeId))c.setStyleScope(t.elm,e);else{var n=t;while(n)i(e=n.context)&&i(e=e.$options._scopeId)&&c.setStyleScope(t.elm,e),n=n.parent}i(e=Ue)&&e!==t.context&&e!==t.fnContext&&i(e=e.$options._scopeId)&&c.setStyleScope(t.elm,e)}function k(t,e,n,r,i,o){for(;r<=i;++r)h(n[r],o,t,e,!1,n,r)}function A(t){var e,n,r=t.data;if(i(r))for(i(e=r.hook)&&i(e=e.destroy)&&e(t),e=0;e<a.destroy.length;++e)a.destroy[e](t);if(i(e=t.children))for(n=0;n<t.children.length;++n)A(t.children[n])}function O(t,e,n,r){for(;n<=r;++n){var o=e[n];i(o)&&(i(o.tag)?(C(o),A(o)):p(o.elm))}}function C(t,e){if(i(e)||i(t.data)){var n,r=a.remove.length+1;for(i(e)?e.listeners+=r:e=f(t.elm,r),i(n=t.componentInstance)&&i(n=n._vnode)&&i(n.data)&&C(n,e),n=0;n<a.remove.length;++n)a.remove[n](t,e);i(n=t.data.hook)&&i(n=n.remove)?n(t,e):e()}else p(t.elm)}function E(t,e,n,o,a){var u,s,l,f,p=0,d=0,v=e.length-1,y=e[0],g=e[v],_=n.length-1,m=n[0],b=n[_],w=!a;while(p<=v&&d<=_)r(y)?y=e[++p]:r(g)?g=e[--v]:li(y,m)?(S(y,m,o),y=e[++p],m=n[++d]):li(g,b)?(S(g,b,o),g=e[--v],b=n[--_]):li(y,b)?(S(y,b,o),w&&c.insertBefore(t,y.elm,c.nextSibling(g.elm)),y=e[++p],b=n[--_]):li(g,m)?(S(g,m,o),w&&c.insertBefore(t,g.elm,y.elm),g=e[--v],m=n[++d]):(r(u)&&(u=pi(e,p,v)),s=i(m.key)?u[m.key]:j(m,e,p,v),r(s)?h(m,o,t,y.elm,!1,n,d):(l=e[s],li(l,m)?(S(l,m,o),e[s]=void 0,w&&c.insertBefore(t,l.elm,y.elm)):h(m,o,t,y.elm,!1,n,d)),m=n[++d]);p>v?(f=r(n[_+1])?null:n[_+1].elm,k(t,f,n,d,_,o)):d>_&&O(t,e,p,v)}function j(t,e,n,r){for(var o=n;o<r;o++){var a=e[o];if(i(a)&&li(t,a))return o}}function S(t,e,n,u){if(t!==e){var s=e.elm=t.elm;if(o(t.isAsyncPlaceholder))i(e.asyncFactory.resolved)?R(t.elm,e,n):e.isAsyncPlaceholder=!0;else if(o(e.isStatic)&&o(t.isStatic)&&e.key===t.key&&(o(e.isCloned)||o(e.isOnce)))e.componentInstance=t.componentInstance;else{var l,f=e.data;i(f)&&i(l=f.hook)&&i(l=l.prepatch)&&l(t,e);var p=t.children,h=e.children;if(i(f)&&b(e)){for(l=0;l<a.update.length;++l)a.update[l](t,e);i(l=f.hook)&&i(l=l.update)&&l(t,e)}r(e.text)?i(p)&&i(h)?p!==h&&E(s,p,h,n,u):i(h)?(i(t.text)&&c.setTextContent(s,\"\"),k(s,null,h,0,h.length-1,n)):i(p)?O(s,p,0,p.length-1):i(t.text)&&c.setTextContent(s,\"\"):t.text!==e.text&&c.setTextContent(s,e.text),i(f)&&i(l=f.hook)&&i(l=l.postpatch)&&l(t,e)}}}function $(t,e,n){if(o(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r<e.length;++r)e[r].data.hook.insert(e[r])}var T=v(\"attrs,class,staticClass,staticStyle,key\");function R(t,e,n,r){var a,u=e.tag,s=e.data,c=e.children;if(r=r||s&&s.pre,e.elm=t,o(e.isComment)&&i(e.asyncFactory))return e.isAsyncPlaceholder=!0,!0;if(i(s)&&(i(a=s.hook)&&i(a=a.init)&&a(e,!0),i(a=e.componentInstance)))return y(e,n),!0;if(i(u)){if(i(c))if(t.hasChildNodes())if(i(a=s)&&i(a=a.domProps)&&i(a=a.innerHTML)){if(a!==t.innerHTML)return!1}else{for(var l=!0,f=t.firstChild,p=0;p<c.length;p++){if(!f||!R(f,c[p],n,r)){l=!1;break}f=f.nextSibling}if(!l||f)return!1}else m(e,c,n);if(i(s)){var h=!1;for(var d in s)if(!T(d)){h=!0,w(e,n);break}!h&&s[\"class\"]&&pe(s[\"class\"])}}else t.data!==e.text&&(t.data=e.text);return!0}return function(t,e,n,u,s,f){if(!r(e)){var p=!1,d=[];if(r(t))p=!0,h(e,d,s,f);else{var v=i(t.nodeType);if(!v&&li(t,e))S(t,e,d,u);else{if(v){if(1===t.nodeType&&t.hasAttribute(U)&&(t.removeAttribute(U),n=!0),o(n)&&R(t,e,d))return $(e,d,!0),t;t=l(t)}var y=t.elm,g=c.parentNode(y);if(h(e,d,y._leaveCb?null:g,c.nextSibling(y)),i(e.parent)){var _=e.parent,m=b(e);while(_){for(var w=0;w<a.destroy.length;++w)a.destroy[w](_);if(_.elm=e.elm,m){for(var x=0;x<a.create.length;++x)a.create[x](si,_);var k=_.data.hook.insert;if(k.merged)for(var C=1;C<k.fns.length;C++)k.fns[C]()}else ui(_);_=_.parent}}i(g)?O(g,[t],0,0):i(t.tag)&&A(t)}}return $(e,d,p),e.elm}i(t)&&A(t)}}var di={create:vi,update:vi,destroy:function(t){vi(t,si)}};function vi(t,e){(t.data.directives||e.data.directives)&&yi(t,e)}function yi(t,e){var n,r,i,o=t===si,a=e===si,u=_i(t.data.directives,t.context),s=_i(e.data.directives,e.context),c=[],l=[];for(n in s)r=u[n],i=s[n],r?(i.oldValue=r.value,bi(i,\"update\",e,t),i.def&&i.def.componentUpdated&&l.push(i)):(bi(i,\"bind\",e,t),i.def&&i.def.inserted&&c.push(i));if(c.length){var f=function(){for(var n=0;n<c.length;n++)bi(c[n],\"inserted\",e,t)};o?_e(e,\"insert\",f):f()}if(l.length&&_e(e,\"postpatch\",function(){for(var n=0;n<l.length;n++)bi(l[n],\"componentUpdated\",e,t)}),!o)for(n in u)s[n]||bi(u[n],\"unbind\",t,t,a)}var gi=Object.create(null);function _i(t,e){var n,r,i=Object.create(null);if(!t)return i;for(n=0;n<t.length;n++)r=t[n],r.modifiers||(r.modifiers=gi),i[mi(r)]=r,r.def=Bt(e.$options,\"directives\",r.name,!0);return i}function mi(t){return t.rawName||t.name+\".\"+Object.keys(t.modifiers||{}).join(\".\")}function bi(t,e,n,r,i){var o=t.def&&t.def[e];if(o)try{o(n.elm,t,n,r,i)}catch(r){Jt(r,n.context,\"directive \"+t.name+\" \"+e+\" hook\")}}var wi=[ai,di];function xi(t,e){var n=e.componentOptions;if((!i(n)||!1!==n.Ctor.options.inheritAttrs)&&(!r(t.data.attrs)||!r(e.data.attrs))){var o,a,u,s=e.elm,c=t.data.attrs||{},l=e.data.attrs||{};for(o in i(l.__ob__)&&(l=e.data.attrs=$({},l)),l)a=l[o],u=c[o],u!==a&&ki(s,o,a);for(o in(Y||tt)&&l.value!==c.value&&ki(s,\"value\",l.value),c)r(l[o])&&(jr(o)?s.removeAttributeNS(Er,Sr(o)):Or(o)||s.removeAttribute(o))}}function ki(t,e,n){t.tagName.indexOf(\"-\")>-1?Ai(t,e,n):Cr(e)?$r(n)?t.removeAttribute(e):(n=\"allowfullscreen\"===e&&\"EMBED\"===t.tagName?\"true\":e,t.setAttribute(e,n)):Or(e)?t.setAttribute(e,$r(n)||\"false\"===n?\"false\":\"true\"):jr(e)?$r(n)?t.removeAttributeNS(Er,Sr(e)):t.setAttributeNS(Er,e,n):Ai(t,e,n)}function Ai(t,e,n){if($r(n))t.removeAttribute(e);else{if(Y&&!Q&&\"TEXTAREA\"===t.tagName&&\"placeholder\"===e&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener(\"input\",r)};t.addEventListener(\"input\",r),t.__ieph=!0}t.setAttribute(e,n)}}var Oi={create:xi,update:xi};function Ci(t,e){var n=e.elm,o=e.data,a=t.data;if(!(r(o.staticClass)&&r(o.class)&&(r(a)||r(a.staticClass)&&r(a.class)))){var u=Tr(e),s=n._transitionClasses;i(s)&&(u=Ir(u,Pr(s))),u!==n._prevClass&&(n.setAttribute(\"class\",u),n._prevClass=u)}}var Ei,ji={create:Ci,update:Ci},Si=\"__r\",$i=\"__c\";function Ti(t){if(i(t[Si])){var e=Y?\"change\":\"input\";t[e]=[].concat(t[Si],t[e]||[]),delete t[Si]}i(t[$i])&&(t.change=[].concat(t[$i],t.change||[]),delete t[$i])}function Ri(t,e,n){var r=Ei;return function i(){var o=t.apply(null,arguments);null!==o&&Ii(e,i,n,r)}}function Li(t,e,n,r,i){e=ce(e),n&&(e=Ri(e,t,r)),Ei.addEventListener(t,e,rt?{capture:r,passive:i}:r)}function Ii(t,e,n,r){(r||Ei).removeEventListener(t,e._withTask||e,n)}function Pi(t,e){if(!r(t.data.on)||!r(e.data.on)){var n=e.data.on||{},i=t.data.on||{};Ei=e.elm,Ti(n),ge(n,i,Li,Ii,e.context),Ei=void 0}}var Mi={create:Pi,update:Pi};function Di(t,e){if(!r(t.data.domProps)||!r(e.data.domProps)){var n,o,a=e.elm,u=t.data.domProps||{},s=e.data.domProps||{};for(n in i(s.__ob__)&&(s=e.data.domProps=$({},s)),u)r(s[n])&&(a[n]=\"\");for(n in s){if(o=s[n],\"textContent\"===n||\"innerHTML\"===n){if(e.children&&(e.children.length=0),o===u[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if(\"value\"===n){a._value=o;var c=r(o)?\"\":String(o);Ui(a,c)&&(a.value=c)}else a[n]=o}}}function Ui(t,e){return!t.composing&&(\"OPTION\"===t.tagName||zi(t,e)||qi(t,e))}function zi(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}function qi(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.lazy)return!1;if(r.number)return d(n)!==d(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}var Ni={create:Di,update:Di},Fi=b(function(t){var e={},n=/;(?![^(]*\\))/g,r=/:(.+)/;return t.split(n).forEach(function(t){if(t){var n=t.split(r);n.length>1&&(e[n[0].trim()]=n[1].trim())}}),e});function Hi(t){var e=Wi(t.style);return t.staticStyle?$(t.staticStyle,e):e}function Wi(t){return Array.isArray(t)?T(t):\"string\"===typeof t?Fi(t):t}function Bi(t,e){var n,r={};if(e){var i=t;while(i.componentInstance)i=i.componentInstance._vnode,i&&i.data&&(n=Hi(i.data))&&$(r,n)}(n=Hi(t.data))&&$(r,n);var o=t;while(o=o.parent)o.data&&(n=Hi(o.data))&&$(r,n);return r}var Ki,Vi=/^--/,Zi=/\\s*!important$/,Xi=function(t,e,n){if(Vi.test(e))t.style.setProperty(e,n);else if(Zi.test(n))t.style.setProperty(e,n.replace(Zi,\"\"),\"important\");else{var r=Ji(e);if(Array.isArray(n))for(var i=0,o=n.length;i<o;i++)t.style[r]=n[i];else t.style[r]=n}},Gi=[\"Webkit\",\"Moz\",\"ms\"],Ji=b(function(t){if(Ki=Ki||document.createElement(\"div\").style,t=x(t),\"filter\"!==t&&t in Ki)return t;for(var e=t.charAt(0).toUpperCase()+t.slice(1),n=0;n<Gi.length;n++){var r=Gi[n]+e;if(r in Ki)return r}});function Yi(t,e){var n=e.data,o=t.data;if(!(r(n.staticStyle)&&r(n.style)&&r(o.staticStyle)&&r(o.style))){var a,u,s=e.elm,c=o.staticStyle,l=o.normalizedStyle||o.style||{},f=c||l,p=Wi(e.data.style)||{};e.data.normalizedStyle=i(p.__ob__)?$({},p):p;var h=Bi(e,!0);for(u in f)r(h[u])&&Xi(s,u,\"\");for(u in h)a=h[u],a!==f[u]&&Xi(s,u,null==a?\"\":a)}}var Qi={create:Yi,update:Yi};function to(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(\" \")>-1?e.split(/\\s+/).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=\" \"+(t.getAttribute(\"class\")||\"\")+\" \";n.indexOf(\" \"+e+\" \")<0&&t.setAttribute(\"class\",(n+e).trim())}}function eo(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(\" \")>-1?e.split(/\\s+/).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute(\"class\");else{var n=\" \"+(t.getAttribute(\"class\")||\"\")+\" \",r=\" \"+e+\" \";while(n.indexOf(r)>=0)n=n.replace(r,\" \");n=n.trim(),n?t.setAttribute(\"class\",n):t.removeAttribute(\"class\")}}function no(t){if(t){if(\"object\"===typeof t){var e={};return!1!==t.css&&$(e,ro(t.name||\"v\")),$(e,t),e}return\"string\"===typeof t?ro(t):void 0}}var ro=b(function(t){return{enterClass:t+\"-enter\",enterToClass:t+\"-enter-to\",enterActiveClass:t+\"-enter-active\",leaveClass:t+\"-leave\",leaveToClass:t+\"-leave-to\",leaveActiveClass:t+\"-leave-active\"}}),io=Z&&!Q,oo=\"transition\",ao=\"animation\",uo=\"transition\",so=\"transitionend\",co=\"animation\",lo=\"animationend\";io&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(uo=\"WebkitTransition\",so=\"webkitTransitionEnd\"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(co=\"WebkitAnimation\",lo=\"webkitAnimationEnd\"));var fo=Z?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function po(t){fo(function(){fo(t)})}function ho(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),to(t,e))}function vo(t,e){t._transitionClasses&&g(t._transitionClasses,e),eo(t,e)}function yo(t,e,n){var r=_o(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var u=i===oo?so:lo,s=0,c=function(){t.removeEventListener(u,l),n()},l=function(e){e.target===t&&++s>=a&&c()};setTimeout(function(){s<a&&c()},o+1),t.addEventListener(u,l)}var go=/\\b(transform|all)(,|$)/;function _o(t,e){var n,r=window.getComputedStyle(t),i=r[uo+\"Delay\"].split(\", \"),o=r[uo+\"Duration\"].split(\", \"),a=mo(i,o),u=r[co+\"Delay\"].split(\", \"),s=r[co+\"Duration\"].split(\", \"),c=mo(u,s),l=0,f=0;e===oo?a>0&&(n=oo,l=a,f=o.length):e===ao?c>0&&(n=ao,l=c,f=s.length):(l=Math.max(a,c),n=l>0?a>c?oo:ao:null,f=n?n===oo?o.length:s.length:0);var p=n===oo&&go.test(r[uo+\"Property\"]);return{type:n,timeout:l,propCount:f,hasTransform:p}}function mo(t,e){while(t.length<e.length)t=t.concat(t);return Math.max.apply(null,e.map(function(e,n){return bo(e)+bo(t[n])}))}function bo(t){return 1e3*Number(t.slice(0,-1))}function wo(t,e){var n=t.elm;i(n._leaveCb)&&(n._leaveCb.cancelled=!0,n._leaveCb());var o=no(t.data.transition);if(!r(o)&&!i(n._enterCb)&&1===n.nodeType){var a=o.css,u=o.type,c=o.enterClass,l=o.enterToClass,f=o.enterActiveClass,p=o.appearClass,h=o.appearToClass,v=o.appearActiveClass,y=o.beforeEnter,g=o.enter,_=o.afterEnter,m=o.enterCancelled,b=o.beforeAppear,w=o.appear,x=o.afterAppear,k=o.appearCancelled,A=o.duration,O=Ue,C=Ue.$vnode;while(C&&C.parent)C=C.parent,O=C.context;var E=!O._isMounted||!t.isRootInsert;if(!E||w||\"\"===w){var j=E&&p?p:c,S=E&&v?v:f,$=E&&h?h:l,T=E&&b||y,R=E&&\"function\"===typeof w?w:g,L=E&&x||_,I=E&&k||m,P=d(s(A)?A.enter:A);0;var M=!1!==a&&!Q,U=Ao(R),z=n._enterCb=D(function(){M&&(vo(n,$),vo(n,S)),z.cancelled?(M&&vo(n,j),I&&I(n)):L&&L(n),n._enterCb=null});t.data.show||_e(t,\"insert\",function(){var e=n.parentNode,r=e&&e._pending&&e._pending[t.key];r&&r.tag===t.tag&&r.elm._leaveCb&&r.elm._leaveCb(),R&&R(n,z)}),T&&T(n),M&&(ho(n,j),ho(n,S),po(function(){vo(n,j),z.cancelled||(ho(n,$),U||(ko(P)?setTimeout(z,P):yo(n,u,z)))})),t.data.show&&(e&&e(),R&&R(n,z)),M||U||z()}}}function xo(t,e){var n=t.elm;i(n._enterCb)&&(n._enterCb.cancelled=!0,n._enterCb());var o=no(t.data.transition);if(r(o)||1!==n.nodeType)return e();if(!i(n._leaveCb)){var a=o.css,u=o.type,c=o.leaveClass,l=o.leaveToClass,f=o.leaveActiveClass,p=o.beforeLeave,h=o.leave,v=o.afterLeave,y=o.leaveCancelled,g=o.delayLeave,_=o.duration,m=!1!==a&&!Q,b=Ao(h),w=d(s(_)?_.leave:_);0;var x=n._leaveCb=D(function(){n.parentNode&&n.parentNode._pending&&(n.parentNode._pending[t.key]=null),m&&(vo(n,l),vo(n,f)),x.cancelled?(m&&vo(n,c),y&&y(n)):(e(),v&&v(n)),n._leaveCb=null});g?g(k):k()}function k(){x.cancelled||(t.data.show||((n.parentNode._pending||(n.parentNode._pending={}))[t.key]=t),p&&p(n),m&&(ho(n,c),ho(n,f),po(function(){vo(n,c),x.cancelled||(ho(n,l),b||(ko(w)?setTimeout(x,w):yo(n,u,x)))})),h&&h(n,x),m||b||x())}}function ko(t){return\"number\"===typeof t&&!isNaN(t)}function Ao(t){if(r(t))return!1;var e=t.fns;return i(e)?Ao(Array.isArray(e)?e[0]:e):(t._length||t.length)>1}function Oo(t,e){!0!==e.data.show&&wo(e)}var Co=Z?{create:Oo,activate:Oo,remove:function(t,e){!0!==t.data.show?xo(t,e):e()}}:{},Eo=[Oi,ji,Mi,Ni,Qi,Co],jo=Eo.concat(wi),So=hi({nodeOps:oi,modules:jo});Q&&document.addEventListener(\"selectionchange\",function(){var t=document.activeElement;t&&t.vmodel&&Do(t,\"input\")});var $o={inserted:function(t,e,n,r){\"select\"===n.tag?(r.elm&&!r.elm._vOptions?_e(n,\"postpatch\",function(){$o.componentUpdated(t,e,n)}):To(t,e,n.context),t._vOptions=[].map.call(t.options,Io)):(\"textarea\"===n.tag||Br(t.type))&&(t._vModifiers=e.modifiers,e.modifiers.lazy||(t.addEventListener(\"compositionstart\",Po),t.addEventListener(\"compositionend\",Mo),t.addEventListener(\"change\",Mo),Q&&(t.vmodel=!0)))},componentUpdated:function(t,e,n){if(\"select\"===n.tag){To(t,e,n.context);var r=t._vOptions,i=t._vOptions=[].map.call(t.options,Io);if(i.some(function(t,e){return!P(t,r[e])})){var o=t.multiple?e.value.some(function(t){return Lo(t,i)}):e.value!==e.oldValue&&Lo(e.value,i);o&&Do(t,\"change\")}}}};function To(t,e,n){Ro(t,e,n),(Y||tt)&&setTimeout(function(){Ro(t,e,n)},0)}function Ro(t,e,n){var r=e.value,i=t.multiple;if(!i||Array.isArray(r)){for(var o,a,u=0,s=t.options.length;u<s;u++)if(a=t.options[u],i)o=M(r,Io(a))>-1,a.selected!==o&&(a.selected=o);else if(P(Io(a),r))return void(t.selectedIndex!==u&&(t.selectedIndex=u));i||(t.selectedIndex=-1)}}function Lo(t,e){return e.every(function(e){return!P(e,t)})}function Io(t){return\"_value\"in t?t._value:t.value}function Po(t){t.target.composing=!0}function Mo(t){t.target.composing&&(t.target.composing=!1,Do(t.target,\"input\"))}function Do(t,e){var n=document.createEvent(\"HTMLEvents\");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function Uo(t){return!t.componentInstance||t.data&&t.data.transition?t:Uo(t.componentInstance._vnode)}var zo={bind:function(t,e,n){var r=e.value;n=Uo(n);var i=n.data&&n.data.transition,o=t.__vOriginalDisplay=\"none\"===t.style.display?\"\":t.style.display;r&&i?(n.data.show=!0,wo(n,function(){t.style.display=o})):t.style.display=r?o:\"none\"},update:function(t,e,n){var r=e.value,i=e.oldValue;if(!r!==!i){n=Uo(n);var o=n.data&&n.data.transition;o?(n.data.show=!0,r?wo(n,function(){t.style.display=t.__vOriginalDisplay}):xo(n,function(){t.style.display=\"none\"})):t.style.display=r?t.__vOriginalDisplay:\"none\"}},unbind:function(t,e,n,r,i){i||(t.style.display=t.__vOriginalDisplay)}},qo={model:$o,show:zo},No={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function Fo(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Fo(Se(e.children)):t}function Ho(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[x(o)]=i[o];return e}function Wo(t,e){if(/\\d-keep-alive$/.test(e.tag))return t(\"keep-alive\",{props:e.componentOptions.propsData})}function Bo(t){while(t=t.parent)if(t.data.transition)return!0}function Ko(t,e){return e.key===t.key&&e.tag===t.tag}var Vo={name:\"transition\",props:No,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(function(t){return t.tag||je(t)}),n.length)){0;var r=this.mode;0;var i=n[0];if(Bo(this.$vnode))return i;var o=Fo(i);if(!o)return i;if(this._leaving)return Wo(t,i);var a=\"__transition-\"+this._uid+\"-\";o.key=null==o.key?o.isComment?a+\"comment\":a+o.tag:u(o.key)?0===String(o.key).indexOf(a)?o.key:a+o.key:o.key;var s=(o.data||(o.data={})).transition=Ho(this),c=this._vnode,l=Fo(c);if(o.data.directives&&o.data.directives.some(function(t){return\"show\"===t.name})&&(o.data.show=!0),l&&l.data&&!Ko(o,l)&&!je(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=$({},s);if(\"out-in\"===r)return this._leaving=!0,_e(f,\"afterLeave\",function(){e._leaving=!1,e.$forceUpdate()}),Wo(t,i);if(\"in-out\"===r){if(je(o))return c;var p,h=function(){p()};_e(s,\"afterEnter\",h),_e(s,\"enterCancelled\",h),_e(f,\"delayLeave\",function(t){p=t})}}return i}}},Zo=$({tag:String,moveClass:String},No);delete Zo.mode;var Xo={props:Zo,render:function(t){for(var e=this.tag||this.$vnode.data.tag||\"span\",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=Ho(this),u=0;u<i.length;u++){var s=i[u];if(s.tag)if(null!=s.key&&0!==String(s.key).indexOf(\"__vlist\"))o.push(s),n[s.key]=s,(s.data||(s.data={})).transition=a;else;}if(r){for(var c=[],l=[],f=0;f<r.length;f++){var p=r[f];p.data.transition=a,p.data.pos=p.elm.getBoundingClientRect(),n[p.key]?c.push(p):l.push(p)}this.kept=t(e,null,c),this.removed=l}return t(e,null,o)},beforeUpdate:function(){this.__patch__(this._vnode,this.kept,!1,!0),this._vnode=this.kept},updated:function(){var t=this.prevChildren,e=this.moveClass||(this.name||\"v\")+\"-move\";t.length&&this.hasMove(t[0].elm,e)&&(t.forEach(Go),t.forEach(Jo),t.forEach(Yo),this._reflow=document.body.offsetHeight,t.forEach(function(t){if(t.data.moved){var n=t.elm,r=n.style;ho(n,e),r.transform=r.WebkitTransform=r.transitionDuration=\"\",n.addEventListener(so,n._moveCb=function t(r){r&&!/transform$/.test(r.propertyName)||(n.removeEventListener(so,t),n._moveCb=null,vo(n,e))})}}))},methods:{hasMove:function(t,e){if(!io)return!1;if(this._hasMove)return this._hasMove;var n=t.cloneNode();t._transitionClasses&&t._transitionClasses.forEach(function(t){eo(n,t)}),to(n,e),n.style.display=\"none\",this.$el.appendChild(n);var r=_o(n);return this.$el.removeChild(n),this._hasMove=r.hasTransform}}};function Go(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function Jo(t){t.data.newPos=t.elm.getBoundingClientRect()}function Yo(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform=\"translate(\"+r+\"px,\"+i+\"px)\",o.transitionDuration=\"0s\"}}var Qo={Transition:Vo,TransitionGroup:Xo};ur.config.mustUseProp=Ar,ur.config.isReservedTag=Nr,ur.config.isReservedAttr=xr,ur.config.getTagNamespace=Fr,ur.config.isUnknownElement=Wr,$(ur.options.directives,qo),$(ur.options.components,Qo),ur.prototype.__patch__=Z?So:R,ur.prototype.$mount=function(t,e){return t=t&&Z?Kr(t):void 0,Ne(this,t,e)},Z&&setTimeout(function(){N.devtools&&at&&at.emit(\"init\",ur)},0),e[\"a\"]=ur}).call(this,n(\"yLpj\"))},L2JU:function(t,e,n){\"use strict\";\n/**\n * vuex v3.0.1\n * (c) 2017 Evan You\n * @license MIT\n */var r=function(t){var e=Number(t.version.split(\".\")[0]);if(e>=2)t.mixin({beforeCreate:r});else{var n=t.prototype._init;t.prototype._init=function(t){void 0===t&&(t={}),t.init=t.init?[r].concat(t.init):r,n.call(this,t)}}function r(){var t=this.$options;t.store?this.$store=\"function\"===typeof t.store?t.store():t.store:t.parent&&t.parent.$store&&(this.$store=t.parent.$store)}},i=\"undefined\"!==typeof window&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function o(t){i&&(t._devtoolHook=i,i.emit(\"vuex:init\",t),i.on(\"vuex:travel-to-state\",function(e){t.replaceState(e)}),t.subscribe(function(t,e){i.emit(\"vuex:mutation\",t,e)}))}function a(t,e){Object.keys(t).forEach(function(n){return e(t[n],n)})}function u(t){return null!==t&&\"object\"===typeof t}function s(t){return t&&\"function\"===typeof t.then}var c=function(t,e){this.runtime=e,this._children=Object.create(null),this._rawModule=t;var n=t.state;this.state=(\"function\"===typeof n?n():n)||{}},l={namespaced:{configurable:!0}};l.namespaced.get=function(){return!!this._rawModule.namespaced},c.prototype.addChild=function(t,e){this._children[t]=e},c.prototype.removeChild=function(t){delete this._children[t]},c.prototype.getChild=function(t){return this._children[t]},c.prototype.update=function(t){this._rawModule.namespaced=t.namespaced,t.actions&&(this._rawModule.actions=t.actions),t.mutations&&(this._rawModule.mutations=t.mutations),t.getters&&(this._rawModule.getters=t.getters)},c.prototype.forEachChild=function(t){a(this._children,t)},c.prototype.forEachGetter=function(t){this._rawModule.getters&&a(this._rawModule.getters,t)},c.prototype.forEachAction=function(t){this._rawModule.actions&&a(this._rawModule.actions,t)},c.prototype.forEachMutation=function(t){this._rawModule.mutations&&a(this._rawModule.mutations,t)},Object.defineProperties(c.prototype,l);var f=function(t){this.register([],t,!1)};function p(t,e,n){if(e.update(n),n.modules)for(var r in n.modules){if(!e.getChild(r))return void 0;p(t.concat(r),e.getChild(r),n.modules[r])}}f.prototype.get=function(t){return t.reduce(function(t,e){return t.getChild(e)},this.root)},f.prototype.getNamespace=function(t){var e=this.root;return t.reduce(function(t,n){return e=e.getChild(n),t+(e.namespaced?n+\"/\":\"\")},\"\")},f.prototype.update=function(t){p([],this.root,t)},f.prototype.register=function(t,e,n){var r=this;void 0===n&&(n=!0);var i=new c(e,n);if(0===t.length)this.root=i;else{var o=this.get(t.slice(0,-1));o.addChild(t[t.length-1],i)}e.modules&&a(e.modules,function(e,i){r.register(t.concat(i),e,n)})},f.prototype.unregister=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1];e.getChild(n).runtime&&e.removeChild(n)};var h;var d=function(t){var e=this;void 0===t&&(t={}),!h&&\"undefined\"!==typeof window&&window.Vue&&j(window.Vue);var n=t.plugins;void 0===n&&(n=[]);var r=t.strict;void 0===r&&(r=!1);var i=t.state;void 0===i&&(i={}),\"function\"===typeof i&&(i=i()||{}),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new f(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new h;var a=this,u=this,s=u.dispatch,c=u.commit;this.dispatch=function(t,e){return s.call(a,t,e)},this.commit=function(t,e,n){return c.call(a,t,e,n)},this.strict=r,m(this,i,[],this._modules.root),_(this,i),n.forEach(function(t){return t(e)}),h.config.devtools&&o(this)},v={state:{configurable:!0}};function y(t,e){return e.indexOf(t)<0&&e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}function g(t,e){t._actions=Object.create(null),t._mutations=Object.create(null),t._wrappedGetters=Object.create(null),t._modulesNamespaceMap=Object.create(null);var n=t.state;m(t,n,[],t._modules.root,!0),_(t,n,e)}function _(t,e,n){var r=t._vm;t.getters={};var i=t._wrappedGetters,o={};a(i,function(e,n){o[n]=function(){return e(t)},Object.defineProperty(t.getters,n,{get:function(){return t._vm[n]},enumerable:!0})});var u=h.config.silent;h.config.silent=!0,t._vm=new h({data:{$$state:e},computed:o}),h.config.silent=u,t.strict&&O(t),r&&(n&&t._withCommit(function(){r._data.$$state=null}),h.nextTick(function(){return r.$destroy()}))}function m(t,e,n,r,i){var o=!n.length,a=t._modules.getNamespace(n);if(r.namespaced&&(t._modulesNamespaceMap[a]=r),!o&&!i){var u=C(e,n.slice(0,-1)),s=n[n.length-1];t._withCommit(function(){h.set(u,s,r.state)})}var c=r.context=b(t,a,n);r.forEachMutation(function(e,n){var r=a+n;x(t,r,e,c)}),r.forEachAction(function(e,n){var r=e.root?n:a+n,i=e.handler||e;k(t,r,i,c)}),r.forEachGetter(function(e,n){var r=a+n;A(t,r,e,c)}),r.forEachChild(function(r,o){m(t,e,n.concat(o),r,i)})}function b(t,e,n){var r=\"\"===e,i={dispatch:r?t.dispatch:function(n,r,i){var o=E(n,r,i),a=o.payload,u=o.options,s=o.type;return u&&u.root||(s=e+s),t.dispatch(s,a)},commit:r?t.commit:function(n,r,i){var o=E(n,r,i),a=o.payload,u=o.options,s=o.type;u&&u.root||(s=e+s),t.commit(s,a,u)}};return Object.defineProperties(i,{getters:{get:r?function(){return t.getters}:function(){return w(t,e)}},state:{get:function(){return C(t.state,n)}}}),i}function w(t,e){var n={},r=e.length;return Object.keys(t.getters).forEach(function(i){if(i.slice(0,r)===e){var o=i.slice(r);Object.defineProperty(n,o,{get:function(){return t.getters[i]},enumerable:!0})}}),n}function x(t,e,n,r){var i=t._mutations[e]||(t._mutations[e]=[]);i.push(function(e){n.call(t,r.state,e)})}function k(t,e,n,r){var i=t._actions[e]||(t._actions[e]=[]);i.push(function(e,i){var o=n.call(t,{dispatch:r.dispatch,commit:r.commit,getters:r.getters,state:r.state,rootGetters:t.getters,rootState:t.state},e,i);return s(o)||(o=Promise.resolve(o)),t._devtoolHook?o.catch(function(e){throw t._devtoolHook.emit(\"vuex:error\",e),e}):o})}function A(t,e,n,r){t._wrappedGetters[e]||(t._wrappedGetters[e]=function(t){return n(r.state,r.getters,t.state,t.getters)})}function O(t){t._vm.$watch(function(){return this._data.$$state},function(){0},{deep:!0,sync:!0})}function C(t,e){return e.length?e.reduce(function(t,e){return t[e]},t):t}function E(t,e,n){return u(t)&&t.type&&(n=e,e=t,t=t.type),{type:t,payload:e,options:n}}function j(t){h&&t===h||(h=t,r(h))}v.state.get=function(){return this._vm._data.$$state},v.state.set=function(t){0},d.prototype.commit=function(t,e,n){var r=this,i=E(t,e,n),o=i.type,a=i.payload,u=(i.options,{type:o,payload:a}),s=this._mutations[o];s&&(this._withCommit(function(){s.forEach(function(t){t(a)})}),this._subscribers.forEach(function(t){return t(u,r.state)}))},d.prototype.dispatch=function(t,e){var n=this,r=E(t,e),i=r.type,o=r.payload,a={type:i,payload:o},u=this._actions[i];if(u)return this._actionSubscribers.forEach(function(t){return t(a,n.state)}),u.length>1?Promise.all(u.map(function(t){return t(o)})):u[0](o)},d.prototype.subscribe=function(t){return y(t,this._subscribers)},d.prototype.subscribeAction=function(t){return y(t,this._actionSubscribers)},d.prototype.watch=function(t,e,n){var r=this;return this._watcherVM.$watch(function(){return t(r.state,r.getters)},e,n)},d.prototype.replaceState=function(t){var e=this;this._withCommit(function(){e._vm._data.$$state=t})},d.prototype.registerModule=function(t,e,n){void 0===n&&(n={}),\"string\"===typeof t&&(t=[t]),this._modules.register(t,e),m(this,this.state,t,this._modules.get(t),n.preserveState),_(this,this.state)},d.prototype.unregisterModule=function(t){var e=this;\"string\"===typeof t&&(t=[t]),this._modules.unregister(t),this._withCommit(function(){var n=C(e.state,t.slice(0,-1));h.delete(n,t[t.length-1])}),g(this)},d.prototype.hotUpdate=function(t){this._modules.update(t),g(this,!0)},d.prototype._withCommit=function(t){var e=this._committing;this._committing=!0,t(),this._committing=e},Object.defineProperties(d.prototype,v);var S=P(function(t,e){var n={};return I(e).forEach(function(e){var r=e.key,i=e.val;n[r]=function(){var e=this.$store.state,n=this.$store.getters;if(t){var r=M(this.$store,\"mapState\",t);if(!r)return;e=r.context.state,n=r.context.getters}return\"function\"===typeof i?i.call(this,e,n):e[i]},n[r].vuex=!0}),n}),$=P(function(t,e){var n={};return I(e).forEach(function(e){var r=e.key,i=e.val;n[r]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var r=this.$store.commit;if(t){var o=M(this.$store,\"mapMutations\",t);if(!o)return;r=o.context.commit}return\"function\"===typeof i?i.apply(this,[r].concat(e)):r.apply(this.$store,[i].concat(e))}}),n}),T=P(function(t,e){var n={};return I(e).forEach(function(e){var r=e.key,i=e.val;i=t+i,n[r]=function(){if(!t||M(this.$store,\"mapGetters\",t))return this.$store.getters[i]},n[r].vuex=!0}),n}),R=P(function(t,e){var n={};return I(e).forEach(function(e){var r=e.key,i=e.val;n[r]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var r=this.$store.dispatch;if(t){var o=M(this.$store,\"mapActions\",t);if(!o)return;r=o.context.dispatch}return\"function\"===typeof i?i.apply(this,[r].concat(e)):r.apply(this.$store,[i].concat(e))}}),n}),L=function(t){return{mapState:S.bind(null,t),mapGetters:T.bind(null,t),mapMutations:$.bind(null,t),mapActions:R.bind(null,t)}};function I(t){return Array.isArray(t)?t.map(function(t){return{key:t,val:t}}):Object.keys(t).map(function(e){return{key:e,val:t[e]}})}function P(t){return function(e,n){return\"string\"!==typeof e?(n=e,e=\"\"):\"/\"!==e.charAt(e.length-1)&&(e+=\"/\"),t(e,n)}}function M(t,e,n){var r=t._modulesNamespaceMap[n];return r}var D={Store:d,install:j,version:\"3.0.1\",mapState:S,mapMutations:$,mapGetters:T,mapActions:R,createNamespacedHelpers:L};e[\"a\"]=D},L9s1:function(t,e,n){\"use strict\";var r=n(\"XKFU\"),i=n(\"0sh+\"),o=\"includes\";r(r.P+r.F*n(\"UUeW\")(o),\"String\",{includes:function(t){return!!~i(this,t,o).indexOf(t,arguments.length>1?arguments[1]:void 0)}})},LQAc:function(t,e){t.exports=!1},LZWt:function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},LvDl:function(t,e,n){(function(t,r){var i;\n/**\n * @license\n * Lodash <https://lodash.com/>\n * Copyright JS Foundation and other contributors <https://js.foundation/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */(function(){var o,a=\"4.17.10\",u=200,s=\"Unsupported core-js use. Try https://npms.io/search?q=ponyfill.\",c=\"Expected a function\",l=\"__lodash_hash_undefined__\",f=500,p=\"__lodash_placeholder__\",h=1,d=2,v=4,y=1,g=2,_=1,m=2,b=4,w=8,x=16,k=32,A=64,O=128,C=256,E=512,j=30,S=\"...\",$=800,T=16,R=1,L=2,I=3,P=1/0,M=9007199254740991,D=1.7976931348623157e308,U=NaN,z=4294967295,q=z-1,N=z>>>1,F=[[\"ary\",O],[\"bind\",_],[\"bindKey\",m],[\"curry\",w],[\"curryRight\",x],[\"flip\",E],[\"partial\",k],[\"partialRight\",A],[\"rearg\",C]],H=\"[object Arguments]\",W=\"[object Array]\",B=\"[object AsyncFunction]\",K=\"[object Boolean]\",V=\"[object Date]\",Z=\"[object DOMException]\",X=\"[object Error]\",G=\"[object Function]\",J=\"[object GeneratorFunction]\",Y=\"[object Map]\",Q=\"[object Number]\",tt=\"[object Null]\",et=\"[object Object]\",nt=\"[object Promise]\",rt=\"[object Proxy]\",it=\"[object RegExp]\",ot=\"[object Set]\",at=\"[object String]\",ut=\"[object Symbol]\",st=\"[object Undefined]\",ct=\"[object WeakMap]\",lt=\"[object WeakSet]\",ft=\"[object ArrayBuffer]\",pt=\"[object DataView]\",ht=\"[object Float32Array]\",dt=\"[object Float64Array]\",vt=\"[object Int8Array]\",yt=\"[object Int16Array]\",gt=\"[object Int32Array]\",_t=\"[object Uint8Array]\",mt=\"[object Uint8ClampedArray]\",bt=\"[object Uint16Array]\",wt=\"[object Uint32Array]\",xt=/\\b__p \\+= '';/g,kt=/\\b(__p \\+=) '' \\+/g,At=/(__e\\(.*?\\)|\\b__t\\)) \\+\\n'';/g,Ot=/&(?:amp|lt|gt|quot|#39);/g,Ct=/[&<>\"']/g,Et=RegExp(Ot.source),jt=RegExp(Ct.source),St=/<%-([\\s\\S]+?)%>/g,$t=/<%([\\s\\S]+?)%>/g,Tt=/<%=([\\s\\S]+?)%>/g,Rt=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,Lt=/^\\w*$/,It=/[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g,Pt=/[\\\\^$.*+?()[\\]{}|]/g,Mt=RegExp(Pt.source),Dt=/^\\s+|\\s+$/g,Ut=/^\\s+/,zt=/\\s+$/,qt=/\\{(?:\\n\\/\\* \\[wrapped with .+\\] \\*\\/)?\\n?/,Nt=/\\{\\n\\/\\* \\[wrapped with (.+)\\] \\*/,Ft=/,? & /,Ht=/[^\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]+/g,Wt=/\\\\(\\\\)?/g,Bt=/\\$\\{([^\\\\}]*(?:\\\\.[^\\\\}]*)*)\\}/g,Kt=/\\w*$/,Vt=/^[-+]0x[0-9a-f]+$/i,Zt=/^0b[01]+$/i,Xt=/^\\[object .+?Constructor\\]$/,Gt=/^0o[0-7]+$/i,Jt=/^(?:0|[1-9]\\d*)$/,Yt=/[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g,Qt=/($^)/,te=/['\\n\\r\\u2028\\u2029\\\\]/g,ee=\"\\\\ud800-\\\\udfff\",ne=\"\\\\u0300-\\\\u036f\",re=\"\\\\ufe20-\\\\ufe2f\",ie=\"\\\\u20d0-\\\\u20ff\",oe=ne+re+ie,ae=\"\\\\u2700-\\\\u27bf\",ue=\"a-z\\\\xdf-\\\\xf6\\\\xf8-\\\\xff\",se=\"\\\\xac\\\\xb1\\\\xd7\\\\xf7\",ce=\"\\\\x00-\\\\x2f\\\\x3a-\\\\x40\\\\x5b-\\\\x60\\\\x7b-\\\\xbf\",le=\"\\\\u2000-\\\\u206f\",fe=\" \\\\t\\\\x0b\\\\f\\\\xa0\\\\ufeff\\\\n\\\\r\\\\u2028\\\\u2029\\\\u1680\\\\u180e\\\\u2000\\\\u2001\\\\u2002\\\\u2003\\\\u2004\\\\u2005\\\\u2006\\\\u2007\\\\u2008\\\\u2009\\\\u200a\\\\u202f\\\\u205f\\\\u3000\",pe=\"A-Z\\\\xc0-\\\\xd6\\\\xd8-\\\\xde\",he=\"\\\\ufe0e\\\\ufe0f\",de=se+ce+le+fe,ve=\"['’]\",ye=\"[\"+ee+\"]\",ge=\"[\"+de+\"]\",_e=\"[\"+oe+\"]\",me=\"\\\\d+\",be=\"[\"+ae+\"]\",we=\"[\"+ue+\"]\",xe=\"[^\"+ee+de+me+ae+ue+pe+\"]\",ke=\"\\\\ud83c[\\\\udffb-\\\\udfff]\",Ae=\"(?:\"+_e+\"|\"+ke+\")\",Oe=\"[^\"+ee+\"]\",Ce=\"(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}\",Ee=\"[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]\",je=\"[\"+pe+\"]\",Se=\"\\\\u200d\",$e=\"(?:\"+we+\"|\"+xe+\")\",Te=\"(?:\"+je+\"|\"+xe+\")\",Re=\"(?:\"+ve+\"(?:d|ll|m|re|s|t|ve))?\",Le=\"(?:\"+ve+\"(?:D|LL|M|RE|S|T|VE))?\",Ie=Ae+\"?\",Pe=\"[\"+he+\"]?\",Me=\"(?:\"+Se+\"(?:\"+[Oe,Ce,Ee].join(\"|\")+\")\"+Pe+Ie+\")*\",De=\"\\\\d*(?:1st|2nd|3rd|(?![123])\\\\dth)(?=\\\\b|[A-Z_])\",Ue=\"\\\\d*(?:1ST|2ND|3RD|(?![123])\\\\dTH)(?=\\\\b|[a-z_])\",ze=Pe+Ie+Me,qe=\"(?:\"+[be,Ce,Ee].join(\"|\")+\")\"+ze,Ne=\"(?:\"+[Oe+_e+\"?\",_e,Ce,Ee,ye].join(\"|\")+\")\",Fe=RegExp(ve,\"g\"),He=RegExp(_e,\"g\"),We=RegExp(ke+\"(?=\"+ke+\")|\"+Ne+ze,\"g\"),Be=RegExp([je+\"?\"+we+\"+\"+Re+\"(?=\"+[ge,je,\"$\"].join(\"|\")+\")\",Te+\"+\"+Le+\"(?=\"+[ge,je+$e,\"$\"].join(\"|\")+\")\",je+\"?\"+$e+\"+\"+Re,je+\"+\"+Le,Ue,De,me,qe].join(\"|\"),\"g\"),Ke=RegExp(\"[\"+Se+ee+oe+he+\"]\"),Ve=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Ze=[\"Array\",\"Buffer\",\"DataView\",\"Date\",\"Error\",\"Float32Array\",\"Float64Array\",\"Function\",\"Int8Array\",\"Int16Array\",\"Int32Array\",\"Map\",\"Math\",\"Object\",\"Promise\",\"RegExp\",\"Set\",\"String\",\"Symbol\",\"TypeError\",\"Uint8Array\",\"Uint8ClampedArray\",\"Uint16Array\",\"Uint32Array\",\"WeakMap\",\"_\",\"clearTimeout\",\"isFinite\",\"parseInt\",\"setTimeout\"],Xe=-1,Ge={};Ge[ht]=Ge[dt]=Ge[vt]=Ge[yt]=Ge[gt]=Ge[_t]=Ge[mt]=Ge[bt]=Ge[wt]=!0,Ge[H]=Ge[W]=Ge[ft]=Ge[K]=Ge[pt]=Ge[V]=Ge[X]=Ge[G]=Ge[Y]=Ge[Q]=Ge[et]=Ge[it]=Ge[ot]=Ge[at]=Ge[ct]=!1;var Je={};Je[H]=Je[W]=Je[ft]=Je[pt]=Je[K]=Je[V]=Je[ht]=Je[dt]=Je[vt]=Je[yt]=Je[gt]=Je[Y]=Je[Q]=Je[et]=Je[it]=Je[ot]=Je[at]=Je[ut]=Je[_t]=Je[mt]=Je[bt]=Je[wt]=!0,Je[X]=Je[G]=Je[ct]=!1;var Ye={\"À\":\"A\",\"Á\":\"A\",\"Â\":\"A\",\"Ã\":\"A\",\"Ä\":\"A\",\"Å\":\"A\",\"à\":\"a\",\"á\":\"a\",\"â\":\"a\",\"ã\":\"a\",\"ä\":\"a\",\"å\":\"a\",\"Ç\":\"C\",\"ç\":\"c\",\"Ð\":\"D\",\"ð\":\"d\",\"È\":\"E\",\"É\":\"E\",\"Ê\":\"E\",\"Ë\":\"E\",\"è\":\"e\",\"é\":\"e\",\"ê\":\"e\",\"ë\":\"e\",\"Ì\":\"I\",\"Í\":\"I\",\"Î\":\"I\",\"Ï\":\"I\",\"ì\":\"i\",\"í\":\"i\",\"î\":\"i\",\"ï\":\"i\",\"Ñ\":\"N\",\"ñ\":\"n\",\"Ò\":\"O\",\"Ó\":\"O\",\"Ô\":\"O\",\"Õ\":\"O\",\"Ö\":\"O\",\"Ø\":\"O\",\"ò\":\"o\",\"ó\":\"o\",\"ô\":\"o\",\"õ\":\"o\",\"ö\":\"o\",\"ø\":\"o\",\"Ù\":\"U\",\"Ú\":\"U\",\"Û\":\"U\",\"Ü\":\"U\",\"ù\":\"u\",\"ú\":\"u\",\"û\":\"u\",\"ü\":\"u\",\"Ý\":\"Y\",\"ý\":\"y\",\"ÿ\":\"y\",\"Æ\":\"Ae\",\"æ\":\"ae\",\"Þ\":\"Th\",\"þ\":\"th\",\"ß\":\"ss\",\"Ā\":\"A\",\"Ă\":\"A\",\"Ą\":\"A\",\"ā\":\"a\",\"ă\":\"a\",\"ą\":\"a\",\"Ć\":\"C\",\"Ĉ\":\"C\",\"Ċ\":\"C\",\"Č\":\"C\",\"ć\":\"c\",\"ĉ\":\"c\",\"ċ\":\"c\",\"č\":\"c\",\"Ď\":\"D\",\"Đ\":\"D\",\"ď\":\"d\",\"đ\":\"d\",\"Ē\":\"E\",\"Ĕ\":\"E\",\"Ė\":\"E\",\"Ę\":\"E\",\"Ě\":\"E\",\"ē\":\"e\",\"ĕ\":\"e\",\"ė\":\"e\",\"ę\":\"e\",\"ě\":\"e\",\"Ĝ\":\"G\",\"Ğ\":\"G\",\"Ġ\":\"G\",\"Ģ\":\"G\",\"ĝ\":\"g\",\"ğ\":\"g\",\"ġ\":\"g\",\"ģ\":\"g\",\"Ĥ\":\"H\",\"Ħ\":\"H\",\"ĥ\":\"h\",\"ħ\":\"h\",\"Ĩ\":\"I\",\"Ī\":\"I\",\"Ĭ\":\"I\",\"Į\":\"I\",\"İ\":\"I\",\"ĩ\":\"i\",\"ī\":\"i\",\"ĭ\":\"i\",\"į\":\"i\",\"ı\":\"i\",\"Ĵ\":\"J\",\"ĵ\":\"j\",\"Ķ\":\"K\",\"ķ\":\"k\",\"ĸ\":\"k\",\"Ĺ\":\"L\",\"Ļ\":\"L\",\"Ľ\":\"L\",\"Ŀ\":\"L\",\"Ł\":\"L\",\"ĺ\":\"l\",\"ļ\":\"l\",\"ľ\":\"l\",\"ŀ\":\"l\",\"ł\":\"l\",\"Ń\":\"N\",\"Ņ\":\"N\",\"Ň\":\"N\",\"Ŋ\":\"N\",\"ń\":\"n\",\"ņ\":\"n\",\"ň\":\"n\",\"ŋ\":\"n\",\"Ō\":\"O\",\"Ŏ\":\"O\",\"Ő\":\"O\",\"ō\":\"o\",\"ŏ\":\"o\",\"ő\":\"o\",\"Ŕ\":\"R\",\"Ŗ\":\"R\",\"Ř\":\"R\",\"ŕ\":\"r\",\"ŗ\":\"r\",\"ř\":\"r\",\"Ś\":\"S\",\"Ŝ\":\"S\",\"Ş\":\"S\",\"Š\":\"S\",\"ś\":\"s\",\"ŝ\":\"s\",\"ş\":\"s\",\"š\":\"s\",\"Ţ\":\"T\",\"Ť\":\"T\",\"Ŧ\":\"T\",\"ţ\":\"t\",\"ť\":\"t\",\"ŧ\":\"t\",\"Ũ\":\"U\",\"Ū\":\"U\",\"Ŭ\":\"U\",\"Ů\":\"U\",\"Ű\":\"U\",\"Ų\":\"U\",\"ũ\":\"u\",\"ū\":\"u\",\"ŭ\":\"u\",\"ů\":\"u\",\"ű\":\"u\",\"ų\":\"u\",\"Ŵ\":\"W\",\"ŵ\":\"w\",\"Ŷ\":\"Y\",\"ŷ\":\"y\",\"Ÿ\":\"Y\",\"Ź\":\"Z\",\"Ż\":\"Z\",\"Ž\":\"Z\",\"ź\":\"z\",\"ż\":\"z\",\"ž\":\"z\",\"Ĳ\":\"IJ\",\"ĳ\":\"ij\",\"Œ\":\"Oe\",\"œ\":\"oe\",\"ŉ\":\"'n\",\"ſ\":\"s\"},Qe={\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#39;\"},tn={\"&amp;\":\"&\",\"&lt;\":\"<\",\"&gt;\":\">\",\"&quot;\":'\"',\"&#39;\":\"'\"},en={\"\\\\\":\"\\\\\",\"'\":\"'\",\"\\n\":\"n\",\"\\r\":\"r\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},nn=parseFloat,rn=parseInt,on=\"object\"==typeof t&&t&&t.Object===Object&&t,an=\"object\"==typeof self&&self&&self.Object===Object&&self,un=on||an||Function(\"return this\")(),sn=\"object\"==typeof e&&e&&!e.nodeType&&e,cn=sn&&\"object\"==typeof r&&r&&!r.nodeType&&r,ln=cn&&cn.exports===sn,fn=ln&&on.process,pn=function(){try{var t=cn&&cn.require&&cn.require(\"util\").types;return t||fn&&fn.binding&&fn.binding(\"util\")}catch(t){}}(),hn=pn&&pn.isArrayBuffer,dn=pn&&pn.isDate,vn=pn&&pn.isMap,yn=pn&&pn.isRegExp,gn=pn&&pn.isSet,_n=pn&&pn.isTypedArray;function mn(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function bn(t,e,n,r){var i=-1,o=null==t?0:t.length;while(++i<o){var a=t[i];e(r,a,n(a),t)}return r}function wn(t,e){var n=-1,r=null==t?0:t.length;while(++n<r)if(!1===e(t[n],n,t))break;return t}function xn(t,e){var n=null==t?0:t.length;while(n--)if(!1===e(t[n],n,t))break;return t}function kn(t,e){var n=-1,r=null==t?0:t.length;while(++n<r)if(!e(t[n],n,t))return!1;return!0}function An(t,e){var n=-1,r=null==t?0:t.length,i=0,o=[];while(++n<r){var a=t[n];e(a,n,t)&&(o[i++]=a)}return o}function On(t,e){var n=null==t?0:t.length;return!!n&&Dn(t,e,0)>-1}function Cn(t,e,n){var r=-1,i=null==t?0:t.length;while(++r<i)if(n(e,t[r]))return!0;return!1}function En(t,e){var n=-1,r=null==t?0:t.length,i=Array(r);while(++n<r)i[n]=e(t[n],n,t);return i}function jn(t,e){var n=-1,r=e.length,i=t.length;while(++n<r)t[i+n]=e[n];return t}function Sn(t,e,n,r){var i=-1,o=null==t?0:t.length;r&&o&&(n=t[++i]);while(++i<o)n=e(n,t[i],i,t);return n}function $n(t,e,n,r){var i=null==t?0:t.length;r&&i&&(n=t[--i]);while(i--)n=e(n,t[i],i,t);return n}function Tn(t,e){var n=-1,r=null==t?0:t.length;while(++n<r)if(e(t[n],n,t))return!0;return!1}var Rn=Nn(\"length\");function Ln(t){return t.split(\"\")}function In(t){return t.match(Ht)||[]}function Pn(t,e,n){var r;return n(t,function(t,n,i){if(e(t,n,i))return r=n,!1}),r}function Mn(t,e,n,r){var i=t.length,o=n+(r?1:-1);while(r?o--:++o<i)if(e(t[o],o,t))return o;return-1}function Dn(t,e,n){return e===e?hr(t,e,n):Mn(t,zn,n)}function Un(t,e,n,r){var i=n-1,o=t.length;while(++i<o)if(r(t[i],e))return i;return-1}function zn(t){return t!==t}function qn(t,e){var n=null==t?0:t.length;return n?Bn(t,e)/n:U}function Nn(t){return function(e){return null==e?o:e[t]}}function Fn(t){return function(e){return null==t?o:t[e]}}function Hn(t,e,n,r,i){return i(t,function(t,i,o){n=r?(r=!1,t):e(n,t,i,o)}),n}function Wn(t,e){var n=t.length;t.sort(e);while(n--)t[n]=t[n].value;return t}function Bn(t,e){var n,r=-1,i=t.length;while(++r<i){var a=e(t[r]);a!==o&&(n=n===o?a:n+a)}return n}function Kn(t,e){var n=-1,r=Array(t);while(++n<t)r[n]=e(n);return r}function Vn(t,e){return En(e,function(e){return[e,t[e]]})}function Zn(t){return function(e){return t(e)}}function Xn(t,e){return En(e,function(e){return t[e]})}function Gn(t,e){return t.has(e)}function Jn(t,e){var n=-1,r=t.length;while(++n<r&&Dn(e,t[n],0)>-1);return n}function Yn(t,e){var n=t.length;while(n--&&Dn(e,t[n],0)>-1);return n}function Qn(t,e){var n=t.length,r=0;while(n--)t[n]===e&&++r;return r}var tr=Fn(Ye),er=Fn(Qe);function nr(t){return\"\\\\\"+en[t]}function rr(t,e){return null==t?o:t[e]}function ir(t){return Ke.test(t)}function or(t){return Ve.test(t)}function ar(t){var e,n=[];while(!(e=t.next()).done)n.push(e.value);return n}function ur(t){var e=-1,n=Array(t.size);return t.forEach(function(t,r){n[++e]=[r,t]}),n}function sr(t,e){return function(n){return t(e(n))}}function cr(t,e){var n=-1,r=t.length,i=0,o=[];while(++n<r){var a=t[n];a!==e&&a!==p||(t[n]=p,o[i++]=n)}return o}function lr(t,e){return\"__proto__\"==e?o:t[e]}function fr(t){var e=-1,n=Array(t.size);return t.forEach(function(t){n[++e]=t}),n}function pr(t){var e=-1,n=Array(t.size);return t.forEach(function(t){n[++e]=[t,t]}),n}function hr(t,e,n){var r=n-1,i=t.length;while(++r<i)if(t[r]===e)return r;return-1}function dr(t,e,n){var r=n+1;while(r--)if(t[r]===e)return r;return r}function vr(t){return ir(t)?_r(t):Rn(t)}function yr(t){return ir(t)?mr(t):Ln(t)}var gr=Fn(tn);function _r(t){var e=We.lastIndex=0;while(We.test(t))++e;return e}function mr(t){return t.match(We)||[]}function br(t){return t.match(Be)||[]}var wr=function t(e){e=null==e?un:xr.defaults(un.Object(),e,xr.pick(un,Ze));var n=e.Array,r=e.Date,i=e.Error,Ht=e.Function,ee=e.Math,ne=e.Object,re=e.RegExp,ie=e.String,oe=e.TypeError,ae=n.prototype,ue=Ht.prototype,se=ne.prototype,ce=e[\"__core-js_shared__\"],le=ue.toString,fe=se.hasOwnProperty,pe=0,he=function(){var t=/[^.]+$/.exec(ce&&ce.keys&&ce.keys.IE_PROTO||\"\");return t?\"Symbol(src)_1.\"+t:\"\"}(),de=se.toString,ve=le.call(ne),ye=un._,ge=re(\"^\"+le.call(fe).replace(Pt,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\"),_e=ln?e.Buffer:o,me=e.Symbol,be=e.Uint8Array,we=_e?_e.allocUnsafe:o,xe=sr(ne.getPrototypeOf,ne),ke=ne.create,Ae=se.propertyIsEnumerable,Oe=ae.splice,Ce=me?me.isConcatSpreadable:o,Ee=me?me.iterator:o,je=me?me.toStringTag:o,Se=function(){try{var t=Ka(ne,\"defineProperty\");return t({},\"\",{}),t}catch(t){}}(),$e=e.clearTimeout!==un.clearTimeout&&e.clearTimeout,Te=r&&r.now!==un.Date.now&&r.now,Re=e.setTimeout!==un.setTimeout&&e.setTimeout,Le=ee.ceil,Ie=ee.floor,Pe=ne.getOwnPropertySymbols,Me=_e?_e.isBuffer:o,De=e.isFinite,Ue=ae.join,ze=sr(ne.keys,ne),qe=ee.max,Ne=ee.min,We=r.now,Be=e.parseInt,Ke=ee.random,Ve=ae.reverse,Ye=Ka(e,\"DataView\"),Qe=Ka(e,\"Map\"),tn=Ka(e,\"Promise\"),en=Ka(e,\"Set\"),on=Ka(e,\"WeakMap\"),an=Ka(ne,\"create\"),sn=on&&new on,cn={},fn=$u(Ye),pn=$u(Qe),Rn=$u(tn),Ln=$u(en),Fn=$u(on),hr=me?me.prototype:o,_r=hr?hr.valueOf:o,mr=hr?hr.toString:o;function wr(t){if(kl(t)&&!al(t)&&!(t instanceof Cr)){if(t instanceof Or)return t;if(fe.call(t,\"__wrapped__\"))return Ru(t)}return new Or(t)}var kr=function(){function t(){}return function(e){if(!xl(e))return{};if(ke)return ke(e);t.prototype=e;var n=new t;return t.prototype=o,n}}();function Ar(){}function Or(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=o}function Cr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=z,this.__views__=[]}function Er(){var t=new Cr(this.__wrapped__);return t.__actions__=ra(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=ra(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=ra(this.__views__),t}function jr(){if(this.__filtered__){var t=new Cr(this);t.__dir__=-1,t.__filtered__=!0}else t=this.clone(),t.__dir__*=-1;return t}function Sr(){var t=this.__wrapped__.value(),e=this.__dir__,n=al(t),r=e<0,i=n?t.length:0,o=Ja(0,i,this.__views__),a=o.start,u=o.end,s=u-a,c=r?u:a-1,l=this.__iteratees__,f=l.length,p=0,h=Ne(s,this.__takeCount__);if(!n||!r&&i==s&&h==s)return Uo(t,this.__actions__);var d=[];t:while(s--&&p<h){c+=e;var v=-1,y=t[c];while(++v<f){var g=l[v],_=g.iteratee,m=g.type,b=_(y);if(m==L)y=b;else if(!b){if(m==R)continue t;break t}}d[p++]=y}return d}function $r(t){var e=-1,n=null==t?0:t.length;this.clear();while(++e<n){var r=t[e];this.set(r[0],r[1])}}function Tr(){this.__data__=an?an(null):{},this.size=0}function Rr(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}function Lr(t){var e=this.__data__;if(an){var n=e[t];return n===l?o:n}return fe.call(e,t)?e[t]:o}function Ir(t){var e=this.__data__;return an?e[t]!==o:fe.call(e,t)}function Pr(t,e){var n=this.__data__;return this.size+=this.has(t)?0:1,n[t]=an&&e===o?l:e,this}function Mr(t){var e=-1,n=null==t?0:t.length;this.clear();while(++e<n){var r=t[e];this.set(r[0],r[1])}}function Dr(){this.__data__=[],this.size=0}function Ur(t){var e=this.__data__,n=ci(e,t);if(n<0)return!1;var r=e.length-1;return n==r?e.pop():Oe.call(e,n,1),--this.size,!0}function zr(t){var e=this.__data__,n=ci(e,t);return n<0?o:e[n][1]}function qr(t){return ci(this.__data__,t)>-1}function Nr(t,e){var n=this.__data__,r=ci(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this}function Fr(t){var e=-1,n=null==t?0:t.length;this.clear();while(++e<n){var r=t[e];this.set(r[0],r[1])}}function Hr(){this.size=0,this.__data__={hash:new $r,map:new(Qe||Mr),string:new $r}}function Wr(t){var e=Wa(this,t)[\"delete\"](t);return this.size-=e?1:0,e}function Br(t){return Wa(this,t).get(t)}function Kr(t){return Wa(this,t).has(t)}function Vr(t,e){var n=Wa(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this}function Zr(t){var e=-1,n=null==t?0:t.length;this.__data__=new Fr;while(++e<n)this.add(t[e])}function Xr(t){return this.__data__.set(t,l),this}function Gr(t){return this.__data__.has(t)}function Jr(t){var e=this.__data__=new Mr(t);this.size=e.size}function Yr(){this.__data__=new Mr,this.size=0}function Qr(t){var e=this.__data__,n=e[\"delete\"](t);return this.size=e.size,n}function ti(t){return this.__data__.get(t)}function ei(t){return this.__data__.has(t)}function ni(t,e){var n=this.__data__;if(n instanceof Mr){var r=n.__data__;if(!Qe||r.length<u-1)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new Fr(r)}return n.set(t,e),this.size=n.size,this}function ri(t,e){var n=al(t),r=!n&&ol(t),i=!n&&!r&&fl(t),o=!n&&!r&&!i&&Ul(t),a=n||r||i||o,u=a?Kn(t.length,ie):[],s=u.length;for(var c in t)!e&&!fe.call(t,c)||a&&(\"length\"==c||i&&(\"offset\"==c||\"parent\"==c)||o&&(\"buffer\"==c||\"byteLength\"==c||\"byteOffset\"==c)||ou(c,s))||u.push(c);return u}function ii(t){var e=t.length;return e?t[go(0,e-1)]:o}function oi(t,e){return Eu(ra(t),vi(e,0,t.length))}function ai(t){return Eu(ra(t))}function ui(t,e,n){(n===o||nl(t[e],n))&&(n!==o||e in t)||hi(t,e,n)}function si(t,e,n){var r=t[e];fe.call(t,e)&&nl(r,n)&&(n!==o||e in t)||hi(t,e,n)}function ci(t,e){var n=t.length;while(n--)if(nl(t[n][0],e))return n;return-1}function li(t,e,n,r){return wi(t,function(t,i,o){e(r,t,n(t),o)}),r}function fi(t,e){return t&&ia(e,wf(e),t)}function pi(t,e){return t&&ia(e,xf(e),t)}function hi(t,e,n){\"__proto__\"==e&&Se?Se(t,e,{configurable:!0,enumerable:!0,value:n,writable:!0}):t[e]=n}function di(t,e){var r=-1,i=e.length,a=n(i),u=null==t;while(++r<i)a[r]=u?o:vf(t,e[r]);return a}function vi(t,e,n){return t===t&&(n!==o&&(t=t<=n?t:n),e!==o&&(t=t>=e?t:e)),t}function yi(t,e,n,r,i,a){var u,s=e&h,c=e&d,l=e&v;if(n&&(u=i?n(t,r,i,a):n(t)),u!==o)return u;if(!xl(t))return t;var f=al(t);if(f){if(u=tu(t),!s)return ra(t,u)}else{var p=Ga(t),y=p==G||p==J;if(fl(t))return Vo(t,s);if(p==et||p==H||y&&!i){if(u=c||y?{}:eu(t),!s)return c?aa(t,pi(u,t)):oa(t,fi(u,t))}else{if(!Je[p])return i?t:{};u=nu(t,p,s)}}a||(a=new Jr);var g=a.get(t);if(g)return g;if(a.set(t,u),Pl(t))return t.forEach(function(r){u.add(yi(r,e,n,r,t,a))}),u;if(Al(t))return t.forEach(function(r,i){u.set(i,yi(r,e,n,i,t,a))}),u;var _=l?c?za:Ua:c?xf:wf,m=f?o:_(t);return wn(m||t,function(r,i){m&&(i=r,r=t[i]),si(u,i,yi(r,e,n,i,t,a))}),u}function gi(t){var e=wf(t);return function(n){return _i(n,t,e)}}function _i(t,e,n){var r=n.length;if(null==t)return!r;t=ne(t);while(r--){var i=n[r],a=e[i],u=t[i];if(u===o&&!(i in t)||!a(u))return!1}return!0}function mi(t,e,n){if(\"function\"!=typeof t)throw new oe(c);return ku(function(){t.apply(o,n)},e)}function bi(t,e,n,r){var i=-1,o=On,a=!0,s=t.length,c=[],l=e.length;if(!s)return c;n&&(e=En(e,Zn(n))),r?(o=Cn,a=!1):e.length>=u&&(o=Gn,a=!1,e=new Zr(e));t:while(++i<s){var f=t[i],p=null==n?f:n(f);if(f=r||0!==f?f:0,a&&p===p){var h=l;while(h--)if(e[h]===p)continue t;c.push(f)}else o(e,p,r)||c.push(f)}return c}wr.templateSettings={escape:St,evaluate:$t,interpolate:Tt,variable:\"\",imports:{_:wr}},wr.prototype=Ar.prototype,wr.prototype.constructor=wr,Or.prototype=kr(Ar.prototype),Or.prototype.constructor=Or,Cr.prototype=kr(Ar.prototype),Cr.prototype.constructor=Cr,$r.prototype.clear=Tr,$r.prototype[\"delete\"]=Rr,$r.prototype.get=Lr,$r.prototype.has=Ir,$r.prototype.set=Pr,Mr.prototype.clear=Dr,Mr.prototype[\"delete\"]=Ur,Mr.prototype.get=zr,Mr.prototype.has=qr,Mr.prototype.set=Nr,Fr.prototype.clear=Hr,Fr.prototype[\"delete\"]=Wr,Fr.prototype.get=Br,Fr.prototype.has=Kr,Fr.prototype.set=Vr,Zr.prototype.add=Zr.prototype.push=Xr,Zr.prototype.has=Gr,Jr.prototype.clear=Yr,Jr.prototype[\"delete\"]=Qr,Jr.prototype.get=ti,Jr.prototype.has=ei,Jr.prototype.set=ni;var wi=ca($i),xi=ca(Ti,!0);function ki(t,e){var n=!0;return wi(t,function(t,r,i){return n=!!e(t,r,i),n}),n}function Ai(t,e,n){var r=-1,i=t.length;while(++r<i){var a=t[r],u=e(a);if(null!=u&&(s===o?u===u&&!Dl(u):n(u,s)))var s=u,c=a}return c}function Oi(t,e,n,r){var i=t.length;n=Kl(n),n<0&&(n=-n>i?0:i+n),r=r===o||r>i?i:Kl(r),r<0&&(r+=i),r=n>r?0:Vl(r);while(n<r)t[n++]=e;return t}function Ci(t,e){var n=[];return wi(t,function(t,r,i){e(t,r,i)&&n.push(t)}),n}function Ei(t,e,n,r,i){var o=-1,a=t.length;n||(n=iu),i||(i=[]);while(++o<a){var u=t[o];e>0&&n(u)?e>1?Ei(u,e-1,n,r,i):jn(i,u):r||(i[i.length]=u)}return i}var ji=la(),Si=la(!0);function $i(t,e){return t&&ji(t,e,wf)}function Ti(t,e){return t&&Si(t,e,wf)}function Ri(t,e){return An(e,function(e){return ml(t[e])})}function Li(t,e){e=Ho(e,t);var n=0,r=e.length;while(null!=t&&n<r)t=t[Su(e[n++])];return n&&n==r?t:o}function Ii(t,e,n){var r=e(t);return al(t)?r:jn(r,n(t))}function Pi(t){return null==t?t===o?st:tt:je&&je in ne(t)?Va(t):_u(t)}function Mi(t,e){return t>e}function Di(t,e){return null!=t&&fe.call(t,e)}function Ui(t,e){return null!=t&&e in ne(t)}function zi(t,e,n){return t>=Ne(e,n)&&t<qe(e,n)}function qi(t,e,r){var i=r?Cn:On,a=t[0].length,u=t.length,s=u,c=n(u),l=1/0,f=[];while(s--){var p=t[s];s&&e&&(p=En(p,Zn(e))),l=Ne(p.length,l),c[s]=!r&&(e||a>=120&&p.length>=120)?new Zr(s&&p):o}p=t[0];var h=-1,d=c[0];t:while(++h<a&&f.length<l){var v=p[h],y=e?e(v):v;if(v=r||0!==v?v:0,!(d?Gn(d,y):i(f,y,r))){s=u;while(--s){var g=c[s];if(!(g?Gn(g,y):i(t[s],y,r)))continue t}d&&d.push(y),f.push(v)}}return f}function Ni(t,e,n,r){return $i(t,function(t,i,o){e(r,n(t),i,o)}),r}function Fi(t,e,n){e=Ho(e,t),t=bu(t,e);var r=null==t?t:t[Su(rs(e))];return null==r?o:mn(r,t,n)}function Hi(t){return kl(t)&&Pi(t)==H}function Wi(t){return kl(t)&&Pi(t)==ft}function Bi(t){return kl(t)&&Pi(t)==V}function Ki(t,e,n,r,i){return t===e||(null==t||null==e||!kl(t)&&!kl(e)?t!==t&&e!==e:Vi(t,e,n,r,Ki,i))}function Vi(t,e,n,r,i,o){var a=al(t),u=al(e),s=a?W:Ga(t),c=u?W:Ga(e);s=s==H?et:s,c=c==H?et:c;var l=s==et,f=c==et,p=s==c;if(p&&fl(t)){if(!fl(e))return!1;a=!0,l=!1}if(p&&!l)return o||(o=new Jr),a||Ul(t)?Ia(t,e,n,r,i,o):Pa(t,e,s,n,r,i,o);if(!(n&y)){var h=l&&fe.call(t,\"__wrapped__\"),d=f&&fe.call(e,\"__wrapped__\");if(h||d){var v=h?t.value():t,g=d?e.value():e;return o||(o=new Jr),i(v,g,n,r,o)}}return!!p&&(o||(o=new Jr),Ma(t,e,n,r,i,o))}function Zi(t){return kl(t)&&Ga(t)==Y}function Xi(t,e,n,r){var i=n.length,a=i,u=!r;if(null==t)return!a;t=ne(t);while(i--){var s=n[i];if(u&&s[2]?s[1]!==t[s[0]]:!(s[0]in t))return!1}while(++i<a){s=n[i];var c=s[0],l=t[c],f=s[1];if(u&&s[2]){if(l===o&&!(c in t))return!1}else{var p=new Jr;if(r)var h=r(l,f,c,t,e,p);if(!(h===o?Ki(f,l,y|g,r,p):h))return!1}}return!0}function Gi(t){if(!xl(t)||lu(t))return!1;var e=ml(t)?ge:Xt;return e.test($u(t))}function Ji(t){return kl(t)&&Pi(t)==it}function Yi(t){return kl(t)&&Ga(t)==ot}function Qi(t){return kl(t)&&wl(t.length)&&!!Ge[Pi(t)]}function to(t){return\"function\"==typeof t?t:null==t?Sp:\"object\"==typeof t?al(t)?ao(t[0],t[1]):oo(t):Fp(t)}function eo(t){if(!pu(t))return ze(t);var e=[];for(var n in ne(t))fe.call(t,n)&&\"constructor\"!=n&&e.push(n);return e}function no(t){if(!xl(t))return gu(t);var e=pu(t),n=[];for(var r in t)(\"constructor\"!=r||!e&&fe.call(t,r))&&n.push(r);return n}function ro(t,e){return t<e}function io(t,e){var r=-1,i=sl(t)?n(t.length):[];return wi(t,function(t,n,o){i[++r]=e(t,n,o)}),i}function oo(t){var e=Ba(t);return 1==e.length&&e[0][2]?du(e[0][0],e[0][1]):function(n){return n===t||Xi(n,t,e)}}function ao(t,e){return uu(t)&&hu(e)?du(Su(t),e):function(n){var r=vf(n,t);return r===o&&r===e?gf(n,t):Ki(e,r,y|g)}}function uo(t,e,n,r,i){t!==e&&ji(e,function(a,u){if(xl(a))i||(i=new Jr),so(t,e,u,n,uo,r,i);else{var s=r?r(lr(t,u),a,u+\"\",t,e,i):o;s===o&&(s=a),ui(t,u,s)}},xf)}function so(t,e,n,r,i,a,u){var s=lr(t,n),c=lr(e,n),l=u.get(c);if(l)ui(t,n,l);else{var f=a?a(s,c,n+\"\",t,e,u):o,p=f===o;if(p){var h=al(c),d=!h&&fl(c),v=!h&&!d&&Ul(c);f=c,h||d||v?al(s)?f=s:cl(s)?f=ra(s):d?(p=!1,f=Vo(c,!0)):v?(p=!1,f=Yo(c,!0)):f=[]:Rl(c)||ol(c)?(f=s,ol(s)?f=Xl(s):(!xl(s)||r&&ml(s))&&(f=eu(c))):p=!1}p&&(u.set(c,f),i(f,c,r,a,u),u[\"delete\"](c)),ui(t,n,f)}}function co(t,e){var n=t.length;if(n)return e+=e<0?n:0,ou(e,n)?t[e]:o}function lo(t,e,n){var r=-1;e=En(e.length?e:[Sp],Zn(Ha()));var i=io(t,function(t,n,i){var o=En(e,function(e){return e(t)});return{criteria:o,index:++r,value:t}});return Wn(i,function(t,e){return ta(t,e,n)})}function fo(t,e){return po(t,e,function(e,n){return gf(t,n)})}function po(t,e,n){var r=-1,i=e.length,o={};while(++r<i){var a=e[r],u=Li(t,a);n(u,a)&&ko(o,Ho(a,t),u)}return o}function ho(t){return function(e){return Li(e,t)}}function vo(t,e,n,r){var i=r?Un:Dn,o=-1,a=e.length,u=t;t===e&&(e=ra(e)),n&&(u=En(t,Zn(n)));while(++o<a){var s=0,c=e[o],l=n?n(c):c;while((s=i(u,l,s,r))>-1)u!==t&&Oe.call(u,s,1),Oe.call(t,s,1)}return t}function yo(t,e){var n=t?e.length:0,r=n-1;while(n--){var i=e[n];if(n==r||i!==o){var o=i;ou(i)?Oe.call(t,i,1):Po(t,i)}}return t}function go(t,e){return t+Ie(Ke()*(e-t+1))}function _o(t,e,r,i){var o=-1,a=qe(Le((e-t)/(r||1)),0),u=n(a);while(a--)u[i?a:++o]=t,t+=r;return u}function mo(t,e){var n=\"\";if(!t||e<1||e>M)return n;do{e%2&&(n+=t),e=Ie(e/2),e&&(t+=t)}while(e);return n}function bo(t,e){return Au(mu(t,e,Sp),t+\"\")}function wo(t){return ii(qf(t))}function xo(t,e){var n=qf(t);return Eu(n,vi(e,0,n.length))}function ko(t,e,n,r){if(!xl(t))return t;e=Ho(e,t);var i=-1,a=e.length,u=a-1,s=t;while(null!=s&&++i<a){var c=Su(e[i]),l=n;if(i!=u){var f=s[c];l=r?r(f,c,s):o,l===o&&(l=xl(f)?f:ou(e[i+1])?[]:{})}si(s,c,l),s=s[c]}return t}var Ao=sn?function(t,e){return sn.set(t,e),t}:Sp,Oo=Se?function(t,e){return Se(t,\"toString\",{configurable:!0,enumerable:!1,value:Op(e),writable:!0})}:Sp;function Co(t){return Eu(qf(t))}function Eo(t,e,r){var i=-1,o=t.length;e<0&&(e=-e>o?0:o+e),r=r>o?o:r,r<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;var a=n(o);while(++i<o)a[i]=t[i+e];return a}function jo(t,e){var n;return wi(t,function(t,r,i){return n=e(t,r,i),!n}),!!n}function So(t,e,n){var r=0,i=null==t?r:t.length;if(\"number\"==typeof e&&e===e&&i<=N){while(r<i){var o=r+i>>>1,a=t[o];null!==a&&!Dl(a)&&(n?a<=e:a<e)?r=o+1:i=o}return i}return $o(t,e,Sp,n)}function $o(t,e,n,r){e=n(e);var i=0,a=null==t?0:t.length,u=e!==e,s=null===e,c=Dl(e),l=e===o;while(i<a){var f=Ie((i+a)/2),p=n(t[f]),h=p!==o,d=null===p,v=p===p,y=Dl(p);if(u)var g=r||v;else g=l?v&&(r||h):s?v&&h&&(r||!d):c?v&&h&&!d&&(r||!y):!d&&!y&&(r?p<=e:p<e);g?i=f+1:a=f}return Ne(a,q)}function To(t,e){var n=-1,r=t.length,i=0,o=[];while(++n<r){var a=t[n],u=e?e(a):a;if(!n||!nl(u,s)){var s=u;o[i++]=0===a?0:a}}return o}function Ro(t){return\"number\"==typeof t?t:Dl(t)?U:+t}function Lo(t){if(\"string\"==typeof t)return t;if(al(t))return En(t,Lo)+\"\";if(Dl(t))return mr?mr.call(t):\"\";var e=t+\"\";return\"0\"==e&&1/t==-P?\"-0\":e}function Io(t,e,n){var r=-1,i=On,o=t.length,a=!0,s=[],c=s;if(n)a=!1,i=Cn;else if(o>=u){var l=e?null:ja(t);if(l)return fr(l);a=!1,i=Gn,c=new Zr}else c=e?[]:s;t:while(++r<o){var f=t[r],p=e?e(f):f;if(f=n||0!==f?f:0,a&&p===p){var h=c.length;while(h--)if(c[h]===p)continue t;e&&c.push(p),s.push(f)}else i(c,p,n)||(c!==s&&c.push(p),s.push(f))}return s}function Po(t,e){return e=Ho(e,t),t=bu(t,e),null==t||delete t[Su(rs(e))]}function Mo(t,e,n,r){return ko(t,e,n(Li(t,e)),r)}function Do(t,e,n,r){var i=t.length,o=r?i:-1;while((r?o--:++o<i)&&e(t[o],o,t));return n?Eo(t,r?0:o,r?o+1:i):Eo(t,r?o+1:0,r?i:o)}function Uo(t,e){var n=t;return n instanceof Cr&&(n=n.value()),Sn(e,function(t,e){return e.func.apply(e.thisArg,jn([t],e.args))},n)}function zo(t,e,r){var i=t.length;if(i<2)return i?Io(t[0]):[];var o=-1,a=n(i);while(++o<i){var u=t[o],s=-1;while(++s<i)s!=o&&(a[o]=bi(a[o]||u,t[s],e,r))}return Io(Ei(a,1),e,r)}function qo(t,e,n){var r=-1,i=t.length,a=e.length,u={};while(++r<i){var s=r<a?e[r]:o;n(u,t[r],s)}return u}function No(t){return cl(t)?t:[]}function Fo(t){return\"function\"==typeof t?t:Sp}function Ho(t,e){return al(t)?t:uu(t,e)?[t]:ju(Jl(t))}var Wo=bo;function Bo(t,e,n){var r=t.length;return n=n===o?r:n,!e&&n>=r?t:Eo(t,e,n)}var Ko=$e||function(t){return un.clearTimeout(t)};function Vo(t,e){if(e)return t.slice();var n=t.length,r=we?we(n):new t.constructor(n);return t.copy(r),r}function Zo(t){var e=new t.constructor(t.byteLength);return new be(e).set(new be(t)),e}function Xo(t,e){var n=e?Zo(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}function Go(t){var e=new t.constructor(t.source,Kt.exec(t));return e.lastIndex=t.lastIndex,e}function Jo(t){return _r?ne(_r.call(t)):{}}function Yo(t,e){var n=e?Zo(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function Qo(t,e){if(t!==e){var n=t!==o,r=null===t,i=t===t,a=Dl(t),u=e!==o,s=null===e,c=e===e,l=Dl(e);if(!s&&!l&&!a&&t>e||a&&u&&c&&!s&&!l||r&&u&&c||!n&&c||!i)return 1;if(!r&&!a&&!l&&t<e||l&&n&&i&&!r&&!a||s&&n&&i||!u&&i||!c)return-1}return 0}function ta(t,e,n){var r=-1,i=t.criteria,o=e.criteria,a=i.length,u=n.length;while(++r<a){var s=Qo(i[r],o[r]);if(s){if(r>=u)return s;var c=n[r];return s*(\"desc\"==c?-1:1)}}return t.index-e.index}function ea(t,e,r,i){var o=-1,a=t.length,u=r.length,s=-1,c=e.length,l=qe(a-u,0),f=n(c+l),p=!i;while(++s<c)f[s]=e[s];while(++o<u)(p||o<a)&&(f[r[o]]=t[o]);while(l--)f[s++]=t[o++];return f}function na(t,e,r,i){var o=-1,a=t.length,u=-1,s=r.length,c=-1,l=e.length,f=qe(a-s,0),p=n(f+l),h=!i;while(++o<f)p[o]=t[o];var d=o;while(++c<l)p[d+c]=e[c];while(++u<s)(h||o<a)&&(p[d+r[u]]=t[o++]);return p}function ra(t,e){var r=-1,i=t.length;e||(e=n(i));while(++r<i)e[r]=t[r];return e}function ia(t,e,n,r){var i=!n;n||(n={});var a=-1,u=e.length;while(++a<u){var s=e[a],c=r?r(n[s],t[s],s,n,t):o;c===o&&(c=t[s]),i?hi(n,s,c):si(n,s,c)}return n}function oa(t,e){return ia(t,Za(t),e)}function aa(t,e){return ia(t,Xa(t),e)}function ua(t,e){return function(n,r){var i=al(n)?bn:li,o=e?e():{};return i(n,t,Ha(r,2),o)}}function sa(t){return bo(function(e,n){var r=-1,i=n.length,a=i>1?n[i-1]:o,u=i>2?n[2]:o;a=t.length>3&&\"function\"==typeof a?(i--,a):o,u&&au(n[0],n[1],u)&&(a=i<3?o:a,i=1),e=ne(e);while(++r<i){var s=n[r];s&&t(e,s,r,a)}return e})}function ca(t,e){return function(n,r){if(null==n)return n;if(!sl(n))return t(n,r);var i=n.length,o=e?i:-1,a=ne(n);while(e?o--:++o<i)if(!1===r(a[o],o,a))break;return n}}function la(t){return function(e,n,r){var i=-1,o=ne(e),a=r(e),u=a.length;while(u--){var s=a[t?u:++i];if(!1===n(o[s],s,o))break}return e}}function fa(t,e,n){var r=e&_,i=da(t);function o(){var e=this&&this!==un&&this instanceof o?i:t;return e.apply(r?n:this,arguments)}return o}function pa(t){return function(e){e=Jl(e);var n=ir(e)?yr(e):o,r=n?n[0]:e.charAt(0),i=n?Bo(n,1).join(\"\"):e.slice(1);return r[t]()+i}}function ha(t){return function(e){return Sn(bp(Vf(e).replace(Fe,\"\")),t,\"\")}}function da(t){return function(){var e=arguments;switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3]);case 5:return new t(e[0],e[1],e[2],e[3],e[4]);case 6:return new t(e[0],e[1],e[2],e[3],e[4],e[5]);case 7:return new t(e[0],e[1],e[2],e[3],e[4],e[5],e[6])}var n=kr(t.prototype),r=t.apply(n,e);return xl(r)?r:n}}function va(t,e,r){var i=da(t);function a(){var u=arguments.length,s=n(u),c=u,l=Fa(a);while(c--)s[c]=arguments[c];var f=u<3&&s[0]!==l&&s[u-1]!==l?[]:cr(s,l);if(u-=f.length,u<r)return Ca(t,e,_a,a.placeholder,o,s,f,o,o,r-u);var p=this&&this!==un&&this instanceof a?i:t;return mn(p,this,s)}return a}function ya(t){return function(e,n,r){var i=ne(e);if(!sl(e)){var a=Ha(n,3);e=wf(e),n=function(t){return a(i[t],t,i)}}var u=t(e,n,r);return u>-1?i[a?e[u]:u]:o}}function ga(t){return Da(function(e){var n=e.length,r=n,i=Or.prototype.thru;t&&e.reverse();while(r--){var a=e[r];if(\"function\"!=typeof a)throw new oe(c);if(i&&!u&&\"wrapper\"==Na(a))var u=new Or([],!0)}r=u?r:n;while(++r<n){a=e[r];var s=Na(a),l=\"wrapper\"==s?qa(a):o;u=l&&cu(l[0])&&l[1]==(O|w|k|C)&&!l[4].length&&1==l[9]?u[Na(l[0])].apply(u,l[3]):1==a.length&&cu(a)?u[s]():u.thru(a)}return function(){var t=arguments,r=t[0];if(u&&1==t.length&&al(r))return u.plant(r).value();var i=0,o=n?e[i].apply(this,t):r;while(++i<n)o=e[i].call(this,o);return o}})}function _a(t,e,r,i,a,u,s,c,l,f){var p=e&O,h=e&_,d=e&m,v=e&(w|x),y=e&E,g=d?o:da(t);function b(){var o=arguments.length,_=n(o),m=o;while(m--)_[m]=arguments[m];if(v)var w=Fa(b),x=Qn(_,w);if(i&&(_=ea(_,i,a,v)),u&&(_=na(_,u,s,v)),o-=x,v&&o<f){var k=cr(_,w);return Ca(t,e,_a,b.placeholder,r,_,k,c,l,f-o)}var A=h?r:this,O=d?A[t]:t;return o=_.length,c?_=wu(_,c):y&&o>1&&_.reverse(),p&&l<o&&(_.length=l),this&&this!==un&&this instanceof b&&(O=g||da(O)),O.apply(A,_)}return b}function ma(t,e){return function(n,r){return Ni(n,t,e(r),{})}}function ba(t,e){return function(n,r){var i;if(n===o&&r===o)return e;if(n!==o&&(i=n),r!==o){if(i===o)return r;\"string\"==typeof n||\"string\"==typeof r?(n=Lo(n),r=Lo(r)):(n=Ro(n),r=Ro(r)),i=t(n,r)}return i}}function wa(t){return Da(function(e){return e=En(e,Zn(Ha())),bo(function(n){var r=this;return t(e,function(t){return mn(t,r,n)})})})}function xa(t,e){e=e===o?\" \":Lo(e);var n=e.length;if(n<2)return n?mo(e,t):e;var r=mo(e,Le(t/vr(e)));return ir(e)?Bo(yr(r),0,t).join(\"\"):r.slice(0,t)}function ka(t,e,r,i){var o=e&_,a=da(t);function u(){var e=-1,s=arguments.length,c=-1,l=i.length,f=n(l+s),p=this&&this!==un&&this instanceof u?a:t;while(++c<l)f[c]=i[c];while(s--)f[c++]=arguments[++e];return mn(p,o?r:this,f)}return u}function Aa(t){return function(e,n,r){return r&&\"number\"!=typeof r&&au(e,n,r)&&(n=r=o),e=Bl(e),n===o?(n=e,e=0):n=Bl(n),r=r===o?e<n?1:-1:Bl(r),_o(e,n,r,t)}}function Oa(t){return function(e,n){return\"string\"==typeof e&&\"string\"==typeof n||(e=Zl(e),n=Zl(n)),t(e,n)}}function Ca(t,e,n,r,i,a,u,s,c,l){var f=e&w,p=f?u:o,h=f?o:u,d=f?a:o,v=f?o:a;e|=f?k:A,e&=~(f?A:k),e&b||(e&=~(_|m));var y=[t,e,i,d,p,v,h,s,c,l],g=n.apply(o,y);return cu(t)&&xu(g,y),g.placeholder=r,Ou(g,t,e)}function Ea(t){var e=ee[t];return function(t,n){if(t=Zl(t),n=null==n?0:Ne(Kl(n),292),n){var r=(Jl(t)+\"e\").split(\"e\"),i=e(r[0]+\"e\"+(+r[1]+n));return r=(Jl(i)+\"e\").split(\"e\"),+(r[0]+\"e\"+(+r[1]-n))}return e(t)}}var ja=en&&1/fr(new en([,-0]))[1]==P?function(t){return new en(t)}:Dp;function Sa(t){return function(e){var n=Ga(e);return n==Y?ur(e):n==ot?pr(e):Vn(e,t(e))}}function $a(t,e,n,r,i,a,u,s){var l=e&m;if(!l&&\"function\"!=typeof t)throw new oe(c);var f=r?r.length:0;if(f||(e&=~(k|A),r=i=o),u=u===o?u:qe(Kl(u),0),s=s===o?s:Kl(s),f-=i?i.length:0,e&A){var p=r,h=i;r=i=o}var d=l?o:qa(t),v=[t,e,n,r,i,p,h,a,u,s];if(d&&yu(v,d),t=v[0],e=v[1],n=v[2],r=v[3],i=v[4],s=v[9]=v[9]===o?l?0:t.length:qe(v[9]-f,0),!s&&e&(w|x)&&(e&=~(w|x)),e&&e!=_)y=e==w||e==x?va(t,e,s):e!=k&&e!=(_|k)||i.length?_a.apply(o,v):ka(t,e,n,r);else var y=fa(t,e,n);var g=d?Ao:xu;return Ou(g(y,v),t,e)}function Ta(t,e,n,r){return t===o||nl(t,se[n])&&!fe.call(r,n)?e:t}function Ra(t,e,n,r,i,a){return xl(t)&&xl(e)&&(a.set(e,t),uo(t,e,o,Ra,a),a[\"delete\"](e)),t}function La(t){return Rl(t)?o:t}function Ia(t,e,n,r,i,a){var u=n&y,s=t.length,c=e.length;if(s!=c&&!(u&&c>s))return!1;var l=a.get(t);if(l&&a.get(e))return l==e;var f=-1,p=!0,h=n&g?new Zr:o;a.set(t,e),a.set(e,t);while(++f<s){var d=t[f],v=e[f];if(r)var _=u?r(v,d,f,e,t,a):r(d,v,f,t,e,a);if(_!==o){if(_)continue;p=!1;break}if(h){if(!Tn(e,function(t,e){if(!Gn(h,e)&&(d===t||i(d,t,n,r,a)))return h.push(e)})){p=!1;break}}else if(d!==v&&!i(d,v,n,r,a)){p=!1;break}}return a[\"delete\"](t),a[\"delete\"](e),p}function Pa(t,e,n,r,i,o,a){switch(n){case pt:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case ft:return!(t.byteLength!=e.byteLength||!o(new be(t),new be(e)));case K:case V:case Q:return nl(+t,+e);case X:return t.name==e.name&&t.message==e.message;case it:case at:return t==e+\"\";case Y:var u=ur;case ot:var s=r&y;if(u||(u=fr),t.size!=e.size&&!s)return!1;var c=a.get(t);if(c)return c==e;r|=g,a.set(t,e);var l=Ia(u(t),u(e),r,i,o,a);return a[\"delete\"](t),l;case ut:if(_r)return _r.call(t)==_r.call(e)}return!1}function Ma(t,e,n,r,i,a){var u=n&y,s=Ua(t),c=s.length,l=Ua(e),f=l.length;if(c!=f&&!u)return!1;var p=c;while(p--){var h=s[p];if(!(u?h in e:fe.call(e,h)))return!1}var d=a.get(t);if(d&&a.get(e))return d==e;var v=!0;a.set(t,e),a.set(e,t);var g=u;while(++p<c){h=s[p];var _=t[h],m=e[h];if(r)var b=u?r(m,_,h,e,t,a):r(_,m,h,t,e,a);if(!(b===o?_===m||i(_,m,n,r,a):b)){v=!1;break}g||(g=\"constructor\"==h)}if(v&&!g){var w=t.constructor,x=e.constructor;w!=x&&\"constructor\"in t&&\"constructor\"in e&&!(\"function\"==typeof w&&w instanceof w&&\"function\"==typeof x&&x instanceof x)&&(v=!1)}return a[\"delete\"](t),a[\"delete\"](e),v}function Da(t){return Au(mu(t,o,Ku),t+\"\")}function Ua(t){return Ii(t,wf,Za)}function za(t){return Ii(t,xf,Xa)}var qa=sn?function(t){return sn.get(t)}:Dp;function Na(t){var e=t.name+\"\",n=cn[e],r=fe.call(cn,e)?n.length:0;while(r--){var i=n[r],o=i.func;if(null==o||o==t)return i.name}return e}function Fa(t){var e=fe.call(wr,\"placeholder\")?wr:t;return e.placeholder}function Ha(){var t=wr.iteratee||$p;return t=t===$p?to:t,arguments.length?t(arguments[0],arguments[1]):t}function Wa(t,e){var n=t.__data__;return su(e)?n[\"string\"==typeof e?\"string\":\"hash\"]:n.map}function Ba(t){var e=wf(t),n=e.length;while(n--){var r=e[n],i=t[r];e[n]=[r,i,hu(i)]}return e}function Ka(t,e){var n=rr(t,e);return Gi(n)?n:o}function Va(t){var e=fe.call(t,je),n=t[je];try{t[je]=o;var r=!0}catch(t){}var i=de.call(t);return r&&(e?t[je]=n:delete t[je]),i}var Za=Pe?function(t){return null==t?[]:(t=ne(t),An(Pe(t),function(e){return Ae.call(t,e)}))}:Kp,Xa=Pe?function(t){var e=[];while(t)jn(e,Za(t)),t=xe(t);return e}:Kp,Ga=Pi;function Ja(t,e,n){var r=-1,i=n.length;while(++r<i){var o=n[r],a=o.size;switch(o.type){case\"drop\":t+=a;break;case\"dropRight\":e-=a;break;case\"take\":e=Ne(e,t+a);break;case\"takeRight\":t=qe(t,e-a);break}}return{start:t,end:e}}function Ya(t){var e=t.match(Nt);return e?e[1].split(Ft):[]}function Qa(t,e,n){e=Ho(e,t);var r=-1,i=e.length,o=!1;while(++r<i){var a=Su(e[r]);if(!(o=null!=t&&n(t,a)))break;t=t[a]}return o||++r!=i?o:(i=null==t?0:t.length,!!i&&wl(i)&&ou(a,i)&&(al(t)||ol(t)))}function tu(t){var e=t.length,n=new t.constructor(e);return e&&\"string\"==typeof t[0]&&fe.call(t,\"index\")&&(n.index=t.index,n.input=t.input),n}function eu(t){return\"function\"!=typeof t.constructor||pu(t)?{}:kr(xe(t))}function nu(t,e,n){var r=t.constructor;switch(e){case ft:return Zo(t);case K:case V:return new r(+t);case pt:return Xo(t,n);case ht:case dt:case vt:case yt:case gt:case _t:case mt:case bt:case wt:return Yo(t,n);case Y:return new r;case Q:case at:return new r(t);case it:return Go(t);case ot:return new r;case ut:return Jo(t)}}function ru(t,e){var n=e.length;if(!n)return t;var r=n-1;return e[r]=(n>1?\"& \":\"\")+e[r],e=e.join(n>2?\", \":\" \"),t.replace(qt,\"{\\n/* [wrapped with \"+e+\"] */\\n\")}function iu(t){return al(t)||ol(t)||!!(Ce&&t&&t[Ce])}function ou(t,e){var n=typeof t;return e=null==e?M:e,!!e&&(\"number\"==n||\"symbol\"!=n&&Jt.test(t))&&t>-1&&t%1==0&&t<e}function au(t,e,n){if(!xl(n))return!1;var r=typeof e;return!!(\"number\"==r?sl(n)&&ou(e,n.length):\"string\"==r&&e in n)&&nl(n[e],t)}function uu(t,e){if(al(t))return!1;var n=typeof t;return!(\"number\"!=n&&\"symbol\"!=n&&\"boolean\"!=n&&null!=t&&!Dl(t))||(Lt.test(t)||!Rt.test(t)||null!=e&&t in ne(e))}function su(t){var e=typeof t;return\"string\"==e||\"number\"==e||\"symbol\"==e||\"boolean\"==e?\"__proto__\"!==t:null===t}function cu(t){var e=Na(t),n=wr[e];if(\"function\"!=typeof n||!(e in Cr.prototype))return!1;if(t===n)return!0;var r=qa(n);return!!r&&t===r[0]}function lu(t){return!!he&&he in t}(Ye&&Ga(new Ye(new ArrayBuffer(1)))!=pt||Qe&&Ga(new Qe)!=Y||tn&&Ga(tn.resolve())!=nt||en&&Ga(new en)!=ot||on&&Ga(new on)!=ct)&&(Ga=function(t){var e=Pi(t),n=e==et?t.constructor:o,r=n?$u(n):\"\";if(r)switch(r){case fn:return pt;case pn:return Y;case Rn:return nt;case Ln:return ot;case Fn:return ct}return e});var fu=ce?ml:Vp;function pu(t){var e=t&&t.constructor,n=\"function\"==typeof e&&e.prototype||se;return t===n}function hu(t){return t===t&&!xl(t)}function du(t,e){return function(n){return null!=n&&(n[t]===e&&(e!==o||t in ne(n)))}}function vu(t){var e=Uc(t,function(t){return n.size===f&&n.clear(),t}),n=e.cache;return e}function yu(t,e){var n=t[1],r=e[1],i=n|r,o=i<(_|m|O),a=r==O&&n==w||r==O&&n==C&&t[7].length<=e[8]||r==(O|C)&&e[7].length<=e[8]&&n==w;if(!o&&!a)return t;r&_&&(t[2]=e[2],i|=n&_?0:b);var u=e[3];if(u){var s=t[3];t[3]=s?ea(s,u,e[4]):u,t[4]=s?cr(t[3],p):e[4]}return u=e[5],u&&(s=t[5],t[5]=s?na(s,u,e[6]):u,t[6]=s?cr(t[5],p):e[6]),u=e[7],u&&(t[7]=u),r&O&&(t[8]=null==t[8]?e[8]:Ne(t[8],e[8])),null==t[9]&&(t[9]=e[9]),t[0]=e[0],t[1]=i,t}function gu(t){var e=[];if(null!=t)for(var n in ne(t))e.push(n);return e}function _u(t){return de.call(t)}function mu(t,e,r){return e=qe(e===o?t.length-1:e,0),function(){var i=arguments,o=-1,a=qe(i.length-e,0),u=n(a);while(++o<a)u[o]=i[e+o];o=-1;var s=n(e+1);while(++o<e)s[o]=i[o];return s[e]=r(u),mn(t,this,s)}}function bu(t,e){return e.length<2?t:Li(t,Eo(e,0,-1))}function wu(t,e){var n=t.length,r=Ne(e.length,n),i=ra(t);while(r--){var a=e[r];t[r]=ou(a,n)?i[a]:o}return t}var xu=Cu(Ao),ku=Re||function(t,e){return un.setTimeout(t,e)},Au=Cu(Oo);function Ou(t,e,n){var r=e+\"\";return Au(t,ru(r,Tu(Ya(r),n)))}function Cu(t){var e=0,n=0;return function(){var r=We(),i=T-(r-n);if(n=r,i>0){if(++e>=$)return arguments[0]}else e=0;return t.apply(o,arguments)}}function Eu(t,e){var n=-1,r=t.length,i=r-1;e=e===o?r:e;while(++n<e){var a=go(n,i),u=t[a];t[a]=t[n],t[n]=u}return t.length=e,t}var ju=vu(function(t){var e=[];return 46===t.charCodeAt(0)&&e.push(\"\"),t.replace(It,function(t,n,r,i){e.push(r?i.replace(Wt,\"$1\"):n||t)}),e});function Su(t){if(\"string\"==typeof t||Dl(t))return t;var e=t+\"\";return\"0\"==e&&1/t==-P?\"-0\":e}function $u(t){if(null!=t){try{return le.call(t)}catch(t){}try{return t+\"\"}catch(t){}}return\"\"}function Tu(t,e){return wn(F,function(n){var r=\"_.\"+n[0];e&n[1]&&!On(t,r)&&t.push(r)}),t.sort()}function Ru(t){if(t instanceof Cr)return t.clone();var e=new Or(t.__wrapped__,t.__chain__);return e.__actions__=ra(t.__actions__),e.__index__=t.__index__,e.__values__=t.__values__,e}function Lu(t,e,r){e=(r?au(t,e,r):e===o)?1:qe(Kl(e),0);var i=null==t?0:t.length;if(!i||e<1)return[];var a=0,u=0,s=n(Le(i/e));while(a<i)s[u++]=Eo(t,a,a+=e);return s}function Iu(t){var e=-1,n=null==t?0:t.length,r=0,i=[];while(++e<n){var o=t[e];o&&(i[r++]=o)}return i}function Pu(){var t=arguments.length;if(!t)return[];var e=n(t-1),r=arguments[0],i=t;while(i--)e[i-1]=arguments[i];return jn(al(r)?ra(r):[r],Ei(e,1))}var Mu=bo(function(t,e){return cl(t)?bi(t,Ei(e,1,cl,!0)):[]}),Du=bo(function(t,e){var n=rs(e);return cl(n)&&(n=o),cl(t)?bi(t,Ei(e,1,cl,!0),Ha(n,2)):[]}),Uu=bo(function(t,e){var n=rs(e);return cl(n)&&(n=o),cl(t)?bi(t,Ei(e,1,cl,!0),o,n):[]});function zu(t,e,n){var r=null==t?0:t.length;return r?(e=n||e===o?1:Kl(e),Eo(t,e<0?0:e,r)):[]}function qu(t,e,n){var r=null==t?0:t.length;return r?(e=n||e===o?1:Kl(e),e=r-e,Eo(t,0,e<0?0:e)):[]}function Nu(t,e){return t&&t.length?Do(t,Ha(e,3),!0,!0):[]}function Fu(t,e){return t&&t.length?Do(t,Ha(e,3),!0):[]}function Hu(t,e,n,r){var i=null==t?0:t.length;return i?(n&&\"number\"!=typeof n&&au(t,e,n)&&(n=0,r=i),Oi(t,e,n,r)):[]}function Wu(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:Kl(n);return i<0&&(i=qe(r+i,0)),Mn(t,Ha(e,3),i)}function Bu(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=r-1;return n!==o&&(i=Kl(n),i=n<0?qe(r+i,0):Ne(i,r-1)),Mn(t,Ha(e,3),i,!0)}function Ku(t){var e=null==t?0:t.length;return e?Ei(t,1):[]}function Vu(t){var e=null==t?0:t.length;return e?Ei(t,P):[]}function Zu(t,e){var n=null==t?0:t.length;return n?(e=e===o?1:Kl(e),Ei(t,e)):[]}function Xu(t){var e=-1,n=null==t?0:t.length,r={};while(++e<n){var i=t[e];r[i[0]]=i[1]}return r}function Gu(t){return t&&t.length?t[0]:o}function Ju(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:Kl(n);return i<0&&(i=qe(r+i,0)),Dn(t,e,i)}function Yu(t){var e=null==t?0:t.length;return e?Eo(t,0,-1):[]}var Qu=bo(function(t){var e=En(t,No);return e.length&&e[0]===t[0]?qi(e):[]}),ts=bo(function(t){var e=rs(t),n=En(t,No);return e===rs(n)?e=o:n.pop(),n.length&&n[0]===t[0]?qi(n,Ha(e,2)):[]}),es=bo(function(t){var e=rs(t),n=En(t,No);return e=\"function\"==typeof e?e:o,e&&n.pop(),n.length&&n[0]===t[0]?qi(n,o,e):[]});function ns(t,e){return null==t?\"\":Ue.call(t,e)}function rs(t){var e=null==t?0:t.length;return e?t[e-1]:o}function is(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=r;return n!==o&&(i=Kl(n),i=i<0?qe(r+i,0):Ne(i,r-1)),e===e?dr(t,e,i):Mn(t,zn,i,!0)}function os(t,e){return t&&t.length?co(t,Kl(e)):o}var as=bo(us);function us(t,e){return t&&t.length&&e&&e.length?vo(t,e):t}function ss(t,e,n){return t&&t.length&&e&&e.length?vo(t,e,Ha(n,2)):t}function cs(t,e,n){return t&&t.length&&e&&e.length?vo(t,e,o,n):t}var ls=Da(function(t,e){var n=null==t?0:t.length,r=di(t,e);return yo(t,En(e,function(t){return ou(t,n)?+t:t}).sort(Qo)),r});function fs(t,e){var n=[];if(!t||!t.length)return n;var r=-1,i=[],o=t.length;e=Ha(e,3);while(++r<o){var a=t[r];e(a,r,t)&&(n.push(a),i.push(r))}return yo(t,i),n}function ps(t){return null==t?t:Ve.call(t)}function hs(t,e,n){var r=null==t?0:t.length;return r?(n&&\"number\"!=typeof n&&au(t,e,n)?(e=0,n=r):(e=null==e?0:Kl(e),n=n===o?r:Kl(n)),Eo(t,e,n)):[]}function ds(t,e){return So(t,e)}function vs(t,e,n){return $o(t,e,Ha(n,2))}function ys(t,e){var n=null==t?0:t.length;if(n){var r=So(t,e);if(r<n&&nl(t[r],e))return r}return-1}function gs(t,e){return So(t,e,!0)}function _s(t,e,n){return $o(t,e,Ha(n,2),!0)}function ms(t,e){var n=null==t?0:t.length;if(n){var r=So(t,e,!0)-1;if(nl(t[r],e))return r}return-1}function bs(t){return t&&t.length?To(t):[]}function ws(t,e){return t&&t.length?To(t,Ha(e,2)):[]}function xs(t){var e=null==t?0:t.length;return e?Eo(t,1,e):[]}function ks(t,e,n){return t&&t.length?(e=n||e===o?1:Kl(e),Eo(t,0,e<0?0:e)):[]}function As(t,e,n){var r=null==t?0:t.length;return r?(e=n||e===o?1:Kl(e),e=r-e,Eo(t,e<0?0:e,r)):[]}function Os(t,e){return t&&t.length?Do(t,Ha(e,3),!1,!0):[]}function Cs(t,e){return t&&t.length?Do(t,Ha(e,3)):[]}var Es=bo(function(t){return Io(Ei(t,1,cl,!0))}),js=bo(function(t){var e=rs(t);return cl(e)&&(e=o),Io(Ei(t,1,cl,!0),Ha(e,2))}),Ss=bo(function(t){var e=rs(t);return e=\"function\"==typeof e?e:o,Io(Ei(t,1,cl,!0),o,e)});function $s(t){return t&&t.length?Io(t):[]}function Ts(t,e){return t&&t.length?Io(t,Ha(e,2)):[]}function Rs(t,e){return e=\"function\"==typeof e?e:o,t&&t.length?Io(t,o,e):[]}function Ls(t){if(!t||!t.length)return[];var e=0;return t=An(t,function(t){if(cl(t))return e=qe(t.length,e),!0}),Kn(e,function(e){return En(t,Nn(e))})}function Is(t,e){if(!t||!t.length)return[];var n=Ls(t);return null==e?n:En(n,function(t){return mn(e,o,t)})}var Ps=bo(function(t,e){return cl(t)?bi(t,e):[]}),Ms=bo(function(t){return zo(An(t,cl))}),Ds=bo(function(t){var e=rs(t);return cl(e)&&(e=o),zo(An(t,cl),Ha(e,2))}),Us=bo(function(t){var e=rs(t);return e=\"function\"==typeof e?e:o,zo(An(t,cl),o,e)}),zs=bo(Ls);function qs(t,e){return qo(t||[],e||[],si)}function Ns(t,e){return qo(t||[],e||[],ko)}var Fs=bo(function(t){var e=t.length,n=e>1?t[e-1]:o;return n=\"function\"==typeof n?(t.pop(),n):o,Is(t,n)});function Hs(t){var e=wr(t);return e.__chain__=!0,e}function Ws(t,e){return e(t),t}function Bs(t,e){return e(t)}var Ks=Da(function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,i=function(e){return di(e,t)};return!(e>1||this.__actions__.length)&&r instanceof Cr&&ou(n)?(r=r.slice(n,+n+(e?1:0)),r.__actions__.push({func:Bs,args:[i],thisArg:o}),new Or(r,this.__chain__).thru(function(t){return e&&!t.length&&t.push(o),t})):this.thru(i)});function Vs(){return Hs(this)}function Zs(){return new Or(this.value(),this.__chain__)}function Xs(){this.__values__===o&&(this.__values__=Wl(this.value()));var t=this.__index__>=this.__values__.length,e=t?o:this.__values__[this.__index__++];return{done:t,value:e}}function Gs(){return this}function Js(t){var e,n=this;while(n instanceof Ar){var r=Ru(n);r.__index__=0,r.__values__=o,e?i.__wrapped__=r:e=r;var i=r;n=n.__wrapped__}return i.__wrapped__=t,e}function Ys(){var t=this.__wrapped__;if(t instanceof Cr){var e=t;return this.__actions__.length&&(e=new Cr(this)),e=e.reverse(),e.__actions__.push({func:Bs,args:[ps],thisArg:o}),new Or(e,this.__chain__)}return this.thru(ps)}function Qs(){return Uo(this.__wrapped__,this.__actions__)}var tc=ua(function(t,e,n){fe.call(t,n)?++t[n]:hi(t,n,1)});function ec(t,e,n){var r=al(t)?kn:ki;return n&&au(t,e,n)&&(e=o),r(t,Ha(e,3))}function nc(t,e){var n=al(t)?An:Ci;return n(t,Ha(e,3))}var rc=ya(Wu),ic=ya(Bu);function oc(t,e){return Ei(dc(t,e),1)}function ac(t,e){return Ei(dc(t,e),P)}function uc(t,e,n){return n=n===o?1:Kl(n),Ei(dc(t,e),n)}function sc(t,e){var n=al(t)?wn:wi;return n(t,Ha(e,3))}function cc(t,e){var n=al(t)?xn:xi;return n(t,Ha(e,3))}var lc=ua(function(t,e,n){fe.call(t,n)?t[n].push(e):hi(t,n,[e])});function fc(t,e,n,r){t=sl(t)?t:qf(t),n=n&&!r?Kl(n):0;var i=t.length;return n<0&&(n=qe(i+n,0)),Ml(t)?n<=i&&t.indexOf(e,n)>-1:!!i&&Dn(t,e,n)>-1}var pc=bo(function(t,e,r){var i=-1,o=\"function\"==typeof e,a=sl(t)?n(t.length):[];return wi(t,function(t){a[++i]=o?mn(e,t,r):Fi(t,e,r)}),a}),hc=ua(function(t,e,n){hi(t,n,e)});function dc(t,e){var n=al(t)?En:io;return n(t,Ha(e,3))}function vc(t,e,n,r){return null==t?[]:(al(e)||(e=null==e?[]:[e]),n=r?o:n,al(n)||(n=null==n?[]:[n]),lo(t,e,n))}var yc=ua(function(t,e,n){t[n?0:1].push(e)},function(){return[[],[]]});function gc(t,e,n){var r=al(t)?Sn:Hn,i=arguments.length<3;return r(t,Ha(e,4),n,i,wi)}function _c(t,e,n){var r=al(t)?$n:Hn,i=arguments.length<3;return r(t,Ha(e,4),n,i,xi)}function mc(t,e){var n=al(t)?An:Ci;return n(t,zc(Ha(e,3)))}function bc(t){var e=al(t)?ii:wo;return e(t)}function wc(t,e,n){e=(n?au(t,e,n):e===o)?1:Kl(e);var r=al(t)?oi:xo;return r(t,e)}function xc(t){var e=al(t)?ai:Co;return e(t)}function kc(t){if(null==t)return 0;if(sl(t))return Ml(t)?vr(t):t.length;var e=Ga(t);return e==Y||e==ot?t.size:eo(t).length}function Ac(t,e,n){var r=al(t)?Tn:jo;return n&&au(t,e,n)&&(e=o),r(t,Ha(e,3))}var Oc=bo(function(t,e){if(null==t)return[];var n=e.length;return n>1&&au(t,e[0],e[1])?e=[]:n>2&&au(e[0],e[1],e[2])&&(e=[e[0]]),lo(t,Ei(e,1),[])}),Cc=Te||function(){return un.Date.now()};function Ec(t,e){if(\"function\"!=typeof e)throw new oe(c);return t=Kl(t),function(){if(--t<1)return e.apply(this,arguments)}}function jc(t,e,n){return e=n?o:e,e=t&&null==e?t.length:e,$a(t,O,o,o,o,o,e)}function Sc(t,e){var n;if(\"function\"!=typeof e)throw new oe(c);return t=Kl(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=o),n}}var $c=bo(function(t,e,n){var r=_;if(n.length){var i=cr(n,Fa($c));r|=k}return $a(t,r,e,n,i)}),Tc=bo(function(t,e,n){var r=_|m;if(n.length){var i=cr(n,Fa(Tc));r|=k}return $a(e,r,t,n,i)});function Rc(t,e,n){e=n?o:e;var r=$a(t,w,o,o,o,o,o,e);return r.placeholder=Rc.placeholder,r}function Lc(t,e,n){e=n?o:e;var r=$a(t,x,o,o,o,o,o,e);return r.placeholder=Lc.placeholder,r}function Ic(t,e,n){var r,i,a,u,s,l,f=0,p=!1,h=!1,d=!0;if(\"function\"!=typeof t)throw new oe(c);function v(e){var n=r,a=i;return r=i=o,f=e,u=t.apply(a,n),u}function y(t){return f=t,s=ku(m,e),p?v(t):u}function g(t){var n=t-l,r=t-f,i=e-n;return h?Ne(i,a-r):i}function _(t){var n=t-l,r=t-f;return l===o||n>=e||n<0||h&&r>=a}function m(){var t=Cc();if(_(t))return b(t);s=ku(m,g(t))}function b(t){return s=o,d&&r?v(t):(r=i=o,u)}function w(){s!==o&&Ko(s),f=0,r=l=i=s=o}function x(){return s===o?u:b(Cc())}function k(){var t=Cc(),n=_(t);if(r=arguments,i=this,l=t,n){if(s===o)return y(l);if(h)return s=ku(m,e),v(l)}return s===o&&(s=ku(m,e)),u}return e=Zl(e)||0,xl(n)&&(p=!!n.leading,h=\"maxWait\"in n,a=h?qe(Zl(n.maxWait)||0,e):a,d=\"trailing\"in n?!!n.trailing:d),k.cancel=w,k.flush=x,k}var Pc=bo(function(t,e){return mi(t,1,e)}),Mc=bo(function(t,e,n){return mi(t,Zl(e)||0,n)});function Dc(t){return $a(t,E)}function Uc(t,e){if(\"function\"!=typeof t||null!=e&&\"function\"!=typeof e)throw new oe(c);var n=function(){var r=arguments,i=e?e.apply(this,r):r[0],o=n.cache;if(o.has(i))return o.get(i);var a=t.apply(this,r);return n.cache=o.set(i,a)||o,a};return n.cache=new(Uc.Cache||Fr),n}function zc(t){if(\"function\"!=typeof t)throw new oe(c);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}function qc(t){return Sc(2,t)}Uc.Cache=Fr;var Nc=Wo(function(t,e){e=1==e.length&&al(e[0])?En(e[0],Zn(Ha())):En(Ei(e,1),Zn(Ha()));var n=e.length;return bo(function(r){var i=-1,o=Ne(r.length,n);while(++i<o)r[i]=e[i].call(this,r[i]);return mn(t,this,r)})}),Fc=bo(function(t,e){var n=cr(e,Fa(Fc));return $a(t,k,o,e,n)}),Hc=bo(function(t,e){var n=cr(e,Fa(Hc));return $a(t,A,o,e,n)}),Wc=Da(function(t,e){return $a(t,C,o,o,o,e)});function Bc(t,e){if(\"function\"!=typeof t)throw new oe(c);return e=e===o?e:Kl(e),bo(t,e)}function Kc(t,e){if(\"function\"!=typeof t)throw new oe(c);return e=null==e?0:qe(Kl(e),0),bo(function(n){var r=n[e],i=Bo(n,0,e);return r&&jn(i,r),mn(t,this,i)})}function Vc(t,e,n){var r=!0,i=!0;if(\"function\"!=typeof t)throw new oe(c);return xl(n)&&(r=\"leading\"in n?!!n.leading:r,i=\"trailing\"in n?!!n.trailing:i),Ic(t,e,{leading:r,maxWait:e,trailing:i})}function Zc(t){return jc(t,1)}function Xc(t,e){return Fc(Fo(e),t)}function Gc(){if(!arguments.length)return[];var t=arguments[0];return al(t)?t:[t]}function Jc(t){return yi(t,v)}function Yc(t,e){return e=\"function\"==typeof e?e:o,yi(t,v,e)}function Qc(t){return yi(t,h|v)}function tl(t,e){return e=\"function\"==typeof e?e:o,yi(t,h|v,e)}function el(t,e){return null==e||_i(t,e,wf(e))}function nl(t,e){return t===e||t!==t&&e!==e}var rl=Oa(Mi),il=Oa(function(t,e){return t>=e}),ol=Hi(function(){return arguments}())?Hi:function(t){return kl(t)&&fe.call(t,\"callee\")&&!Ae.call(t,\"callee\")},al=n.isArray,ul=hn?Zn(hn):Wi;function sl(t){return null!=t&&wl(t.length)&&!ml(t)}function cl(t){return kl(t)&&sl(t)}function ll(t){return!0===t||!1===t||kl(t)&&Pi(t)==K}var fl=Me||Vp,pl=dn?Zn(dn):Bi;function hl(t){return kl(t)&&1===t.nodeType&&!Rl(t)}function dl(t){if(null==t)return!0;if(sl(t)&&(al(t)||\"string\"==typeof t||\"function\"==typeof t.splice||fl(t)||Ul(t)||ol(t)))return!t.length;var e=Ga(t);if(e==Y||e==ot)return!t.size;if(pu(t))return!eo(t).length;for(var n in t)if(fe.call(t,n))return!1;return!0}function vl(t,e){return Ki(t,e)}function yl(t,e,n){n=\"function\"==typeof n?n:o;var r=n?n(t,e):o;return r===o?Ki(t,e,o,n):!!r}function gl(t){if(!kl(t))return!1;var e=Pi(t);return e==X||e==Z||\"string\"==typeof t.message&&\"string\"==typeof t.name&&!Rl(t)}function _l(t){return\"number\"==typeof t&&De(t)}function ml(t){if(!xl(t))return!1;var e=Pi(t);return e==G||e==J||e==B||e==rt}function bl(t){return\"number\"==typeof t&&t==Kl(t)}function wl(t){return\"number\"==typeof t&&t>-1&&t%1==0&&t<=M}function xl(t){var e=typeof t;return null!=t&&(\"object\"==e||\"function\"==e)}function kl(t){return null!=t&&\"object\"==typeof t}var Al=vn?Zn(vn):Zi;function Ol(t,e){return t===e||Xi(t,e,Ba(e))}function Cl(t,e,n){return n=\"function\"==typeof n?n:o,Xi(t,e,Ba(e),n)}function El(t){return Tl(t)&&t!=+t}function jl(t){if(fu(t))throw new i(s);return Gi(t)}function Sl(t){return null===t}function $l(t){return null==t}function Tl(t){return\"number\"==typeof t||kl(t)&&Pi(t)==Q}function Rl(t){if(!kl(t)||Pi(t)!=et)return!1;var e=xe(t);if(null===e)return!0;var n=fe.call(e,\"constructor\")&&e.constructor;return\"function\"==typeof n&&n instanceof n&&le.call(n)==ve}var Ll=yn?Zn(yn):Ji;function Il(t){return bl(t)&&t>=-M&&t<=M}var Pl=gn?Zn(gn):Yi;function Ml(t){return\"string\"==typeof t||!al(t)&&kl(t)&&Pi(t)==at}function Dl(t){return\"symbol\"==typeof t||kl(t)&&Pi(t)==ut}var Ul=_n?Zn(_n):Qi;function zl(t){return t===o}function ql(t){return kl(t)&&Ga(t)==ct}function Nl(t){return kl(t)&&Pi(t)==lt}var Fl=Oa(ro),Hl=Oa(function(t,e){return t<=e});function Wl(t){if(!t)return[];if(sl(t))return Ml(t)?yr(t):ra(t);if(Ee&&t[Ee])return ar(t[Ee]());var e=Ga(t),n=e==Y?ur:e==ot?fr:qf;return n(t)}function Bl(t){if(!t)return 0===t?t:0;if(t=Zl(t),t===P||t===-P){var e=t<0?-1:1;return e*D}return t===t?t:0}function Kl(t){var e=Bl(t),n=e%1;return e===e?n?e-n:e:0}function Vl(t){return t?vi(Kl(t),0,z):0}function Zl(t){if(\"number\"==typeof t)return t;if(Dl(t))return U;if(xl(t)){var e=\"function\"==typeof t.valueOf?t.valueOf():t;t=xl(e)?e+\"\":e}if(\"string\"!=typeof t)return 0===t?t:+t;t=t.replace(Dt,\"\");var n=Zt.test(t);return n||Gt.test(t)?rn(t.slice(2),n?2:8):Vt.test(t)?U:+t}function Xl(t){return ia(t,xf(t))}function Gl(t){return t?vi(Kl(t),-M,M):0===t?t:0}function Jl(t){return null==t?\"\":Lo(t)}var Yl=sa(function(t,e){if(pu(e)||sl(e))ia(e,wf(e),t);else for(var n in e)fe.call(e,n)&&si(t,n,e[n])}),Ql=sa(function(t,e){ia(e,xf(e),t)}),tf=sa(function(t,e,n,r){ia(e,xf(e),t,r)}),ef=sa(function(t,e,n,r){ia(e,wf(e),t,r)}),nf=Da(di);function rf(t,e){var n=kr(t);return null==e?n:fi(n,e)}var of=bo(function(t,e){t=ne(t);var n=-1,r=e.length,i=r>2?e[2]:o;i&&au(e[0],e[1],i)&&(r=1);while(++n<r){var a=e[n],u=xf(a),s=-1,c=u.length;while(++s<c){var l=u[s],f=t[l];(f===o||nl(f,se[l])&&!fe.call(t,l))&&(t[l]=a[l])}}return t}),af=bo(function(t){return t.push(o,Ra),mn(Cf,o,t)});function uf(t,e){return Pn(t,Ha(e,3),$i)}function sf(t,e){return Pn(t,Ha(e,3),Ti)}function cf(t,e){return null==t?t:ji(t,Ha(e,3),xf)}function lf(t,e){return null==t?t:Si(t,Ha(e,3),xf)}function ff(t,e){return t&&$i(t,Ha(e,3))}function pf(t,e){return t&&Ti(t,Ha(e,3))}function hf(t){return null==t?[]:Ri(t,wf(t))}function df(t){return null==t?[]:Ri(t,xf(t))}function vf(t,e,n){var r=null==t?o:Li(t,e);return r===o?n:r}function yf(t,e){return null!=t&&Qa(t,e,Di)}function gf(t,e){return null!=t&&Qa(t,e,Ui)}var _f=ma(function(t,e,n){null!=e&&\"function\"!=typeof e.toString&&(e=de.call(e)),t[e]=n},Op(Sp)),mf=ma(function(t,e,n){null!=e&&\"function\"!=typeof e.toString&&(e=de.call(e)),fe.call(t,e)?t[e].push(n):t[e]=[n]},Ha),bf=bo(Fi);function wf(t){return sl(t)?ri(t):eo(t)}function xf(t){return sl(t)?ri(t,!0):no(t)}function kf(t,e){var n={};return e=Ha(e,3),$i(t,function(t,r,i){hi(n,e(t,r,i),t)}),n}function Af(t,e){var n={};return e=Ha(e,3),$i(t,function(t,r,i){hi(n,r,e(t,r,i))}),n}var Of=sa(function(t,e,n){uo(t,e,n)}),Cf=sa(function(t,e,n,r){uo(t,e,n,r)}),Ef=Da(function(t,e){var n={};if(null==t)return n;var r=!1;e=En(e,function(e){return e=Ho(e,t),r||(r=e.length>1),e}),ia(t,za(t),n),r&&(n=yi(n,h|d|v,La));var i=e.length;while(i--)Po(n,e[i]);return n});function jf(t,e){return $f(t,zc(Ha(e)))}var Sf=Da(function(t,e){return null==t?{}:fo(t,e)});function $f(t,e){if(null==t)return{};var n=En(za(t),function(t){return[t]});return e=Ha(e),po(t,n,function(t,n){return e(t,n[0])})}function Tf(t,e,n){e=Ho(e,t);var r=-1,i=e.length;i||(i=1,t=o);while(++r<i){var a=null==t?o:t[Su(e[r])];a===o&&(r=i,a=n),t=ml(a)?a.call(t):a}return t}function Rf(t,e,n){return null==t?t:ko(t,e,n)}function Lf(t,e,n,r){return r=\"function\"==typeof r?r:o,null==t?t:ko(t,e,n,r)}var If=Sa(wf),Pf=Sa(xf);function Mf(t,e,n){var r=al(t),i=r||fl(t)||Ul(t);if(e=Ha(e,4),null==n){var o=t&&t.constructor;n=i?r?new o:[]:xl(t)&&ml(o)?kr(xe(t)):{}}return(i?wn:$i)(t,function(t,r,i){return e(n,t,r,i)}),n}function Df(t,e){return null==t||Po(t,e)}function Uf(t,e,n){return null==t?t:Mo(t,e,Fo(n))}function zf(t,e,n,r){return r=\"function\"==typeof r?r:o,null==t?t:Mo(t,e,Fo(n),r)}function qf(t){return null==t?[]:Xn(t,wf(t))}function Nf(t){return null==t?[]:Xn(t,xf(t))}function Ff(t,e,n){return n===o&&(n=e,e=o),n!==o&&(n=Zl(n),n=n===n?n:0),e!==o&&(e=Zl(e),e=e===e?e:0),vi(Zl(t),e,n)}function Hf(t,e,n){return e=Bl(e),n===o?(n=e,e=0):n=Bl(n),t=Zl(t),zi(t,e,n)}function Wf(t,e,n){if(n&&\"boolean\"!=typeof n&&au(t,e,n)&&(e=n=o),n===o&&(\"boolean\"==typeof e?(n=e,e=o):\"boolean\"==typeof t&&(n=t,t=o)),t===o&&e===o?(t=0,e=1):(t=Bl(t),e===o?(e=t,t=0):e=Bl(e)),t>e){var r=t;t=e,e=r}if(n||t%1||e%1){var i=Ke();return Ne(t+i*(e-t+nn(\"1e-\"+((i+\"\").length-1))),e)}return go(t,e)}var Bf=ha(function(t,e,n){return e=e.toLowerCase(),t+(n?Kf(e):e)});function Kf(t){return mp(Jl(t).toLowerCase())}function Vf(t){return t=Jl(t),t&&t.replace(Yt,tr).replace(He,\"\")}function Zf(t,e,n){t=Jl(t),e=Lo(e);var r=t.length;n=n===o?r:vi(Kl(n),0,r);var i=n;return n-=e.length,n>=0&&t.slice(n,i)==e}function Xf(t){return t=Jl(t),t&&jt.test(t)?t.replace(Ct,er):t}function Gf(t){return t=Jl(t),t&&Mt.test(t)?t.replace(Pt,\"\\\\$&\"):t}var Jf=ha(function(t,e,n){return t+(n?\"-\":\"\")+e.toLowerCase()}),Yf=ha(function(t,e,n){return t+(n?\" \":\"\")+e.toLowerCase()}),Qf=pa(\"toLowerCase\");function tp(t,e,n){t=Jl(t),e=Kl(e);var r=e?vr(t):0;if(!e||r>=e)return t;var i=(e-r)/2;return xa(Ie(i),n)+t+xa(Le(i),n)}function ep(t,e,n){t=Jl(t),e=Kl(e);var r=e?vr(t):0;return e&&r<e?t+xa(e-r,n):t}function np(t,e,n){t=Jl(t),e=Kl(e);var r=e?vr(t):0;return e&&r<e?xa(e-r,n)+t:t}function rp(t,e,n){return n||null==e?e=0:e&&(e=+e),Be(Jl(t).replace(Ut,\"\"),e||0)}function ip(t,e,n){return e=(n?au(t,e,n):e===o)?1:Kl(e),mo(Jl(t),e)}function op(){var t=arguments,e=Jl(t[0]);return t.length<3?e:e.replace(t[1],t[2])}var ap=ha(function(t,e,n){return t+(n?\"_\":\"\")+e.toLowerCase()});function up(t,e,n){return n&&\"number\"!=typeof n&&au(t,e,n)&&(e=n=o),n=n===o?z:n>>>0,n?(t=Jl(t),t&&(\"string\"==typeof e||null!=e&&!Ll(e))&&(e=Lo(e),!e&&ir(t))?Bo(yr(t),0,n):t.split(e,n)):[]}var sp=ha(function(t,e,n){return t+(n?\" \":\"\")+mp(e)});function cp(t,e,n){return t=Jl(t),n=null==n?0:vi(Kl(n),0,t.length),e=Lo(e),t.slice(n,n+e.length)==e}function lp(t,e,n){var r=wr.templateSettings;n&&au(t,e,n)&&(e=o),t=Jl(t),e=tf({},e,r,Ta);var i,a,u=tf({},e.imports,r.imports,Ta),s=wf(u),c=Xn(u,s),l=0,f=e.interpolate||Qt,p=\"__p += '\",h=re((e.escape||Qt).source+\"|\"+f.source+\"|\"+(f===Tt?Bt:Qt).source+\"|\"+(e.evaluate||Qt).source+\"|$\",\"g\"),d=\"//# sourceURL=\"+(\"sourceURL\"in e?e.sourceURL:\"lodash.templateSources[\"+ ++Xe+\"]\")+\"\\n\";t.replace(h,function(e,n,r,o,u,s){return r||(r=o),p+=t.slice(l,s).replace(te,nr),n&&(i=!0,p+=\"' +\\n__e(\"+n+\") +\\n'\"),u&&(a=!0,p+=\"';\\n\"+u+\";\\n__p += '\"),r&&(p+=\"' +\\n((__t = (\"+r+\")) == null ? '' : __t) +\\n'\"),l=s+e.length,e}),p+=\"';\\n\";var v=e.variable;v||(p=\"with (obj) {\\n\"+p+\"\\n}\\n\"),p=(a?p.replace(xt,\"\"):p).replace(kt,\"$1\").replace(At,\"$1;\"),p=\"function(\"+(v||\"obj\")+\") {\\n\"+(v?\"\":\"obj || (obj = {});\\n\")+\"var __t, __p = ''\"+(i?\", __e = _.escape\":\"\")+(a?\", __j = Array.prototype.join;\\nfunction print() { __p += __j.call(arguments, '') }\\n\":\";\\n\")+p+\"return __p\\n}\";var y=wp(function(){return Ht(s,d+\"return \"+p).apply(o,c)});if(y.source=p,gl(y))throw y;return y}function fp(t){return Jl(t).toLowerCase()}function pp(t){return Jl(t).toUpperCase()}function hp(t,e,n){if(t=Jl(t),t&&(n||e===o))return t.replace(Dt,\"\");if(!t||!(e=Lo(e)))return t;var r=yr(t),i=yr(e),a=Jn(r,i),u=Yn(r,i)+1;return Bo(r,a,u).join(\"\")}function dp(t,e,n){if(t=Jl(t),t&&(n||e===o))return t.replace(zt,\"\");if(!t||!(e=Lo(e)))return t;var r=yr(t),i=Yn(r,yr(e))+1;return Bo(r,0,i).join(\"\")}function vp(t,e,n){if(t=Jl(t),t&&(n||e===o))return t.replace(Ut,\"\");if(!t||!(e=Lo(e)))return t;var r=yr(t),i=Jn(r,yr(e));return Bo(r,i).join(\"\")}function yp(t,e){var n=j,r=S;if(xl(e)){var i=\"separator\"in e?e.separator:i;n=\"length\"in e?Kl(e.length):n,r=\"omission\"in e?Lo(e.omission):r}t=Jl(t);var a=t.length;if(ir(t)){var u=yr(t);a=u.length}if(n>=a)return t;var s=n-vr(r);if(s<1)return r;var c=u?Bo(u,0,s).join(\"\"):t.slice(0,s);if(i===o)return c+r;if(u&&(s+=c.length-s),Ll(i)){if(t.slice(s).search(i)){var l,f=c;i.global||(i=re(i.source,Jl(Kt.exec(i))+\"g\")),i.lastIndex=0;while(l=i.exec(f))var p=l.index;c=c.slice(0,p===o?s:p)}}else if(t.indexOf(Lo(i),s)!=s){var h=c.lastIndexOf(i);h>-1&&(c=c.slice(0,h))}return c+r}function gp(t){return t=Jl(t),t&&Et.test(t)?t.replace(Ot,gr):t}var _p=ha(function(t,e,n){return t+(n?\" \":\"\")+e.toUpperCase()}),mp=pa(\"toUpperCase\");function bp(t,e,n){return t=Jl(t),e=n?o:e,e===o?or(t)?br(t):In(t):t.match(e)||[]}var wp=bo(function(t,e){try{return mn(t,o,e)}catch(t){return gl(t)?t:new i(t)}}),xp=Da(function(t,e){return wn(e,function(e){e=Su(e),hi(t,e,$c(t[e],t))}),t});function kp(t){var e=null==t?0:t.length,n=Ha();return t=e?En(t,function(t){if(\"function\"!=typeof t[1])throw new oe(c);return[n(t[0]),t[1]]}):[],bo(function(n){var r=-1;while(++r<e){var i=t[r];if(mn(i[0],this,n))return mn(i[1],this,n)}})}function Ap(t){return gi(yi(t,h))}function Op(t){return function(){return t}}function Cp(t,e){return null==t||t!==t?e:t}var Ep=ga(),jp=ga(!0);function Sp(t){return t}function $p(t){return to(\"function\"==typeof t?t:yi(t,h))}function Tp(t){return oo(yi(t,h))}function Rp(t,e){return ao(t,yi(e,h))}var Lp=bo(function(t,e){return function(n){return Fi(n,t,e)}}),Ip=bo(function(t,e){return function(n){return Fi(t,n,e)}});function Pp(t,e,n){var r=wf(e),i=Ri(e,r);null!=n||xl(e)&&(i.length||!r.length)||(n=e,e=t,t=this,i=Ri(e,wf(e)));var o=!(xl(n)&&\"chain\"in n)||!!n.chain,a=ml(t);return wn(i,function(n){var r=e[n];t[n]=r,a&&(t.prototype[n]=function(){var e=this.__chain__;if(o||e){var n=t(this.__wrapped__),i=n.__actions__=ra(this.__actions__);return i.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.apply(t,jn([this.value()],arguments))})}),t}function Mp(){return un._===this&&(un._=ye),this}function Dp(){}function Up(t){return t=Kl(t),bo(function(e){return co(e,t)})}var zp=wa(En),qp=wa(kn),Np=wa(Tn);function Fp(t){return uu(t)?Nn(Su(t)):ho(t)}function Hp(t){return function(e){return null==t?o:Li(t,e)}}var Wp=Aa(),Bp=Aa(!0);function Kp(){return[]}function Vp(){return!1}function Zp(){return{}}function Xp(){return\"\"}function Gp(){return!0}function Jp(t,e){if(t=Kl(t),t<1||t>M)return[];var n=z,r=Ne(t,z);e=Ha(e),t-=z;var i=Kn(r,e);while(++n<t)e(n);return i}function Yp(t){return al(t)?En(t,Su):Dl(t)?[t]:ra(ju(Jl(t)))}function Qp(t){var e=++pe;return Jl(t)+e}var th=ba(function(t,e){return t+e},0),eh=Ea(\"ceil\"),nh=ba(function(t,e){return t/e},1),rh=Ea(\"floor\");function ih(t){return t&&t.length?Ai(t,Sp,Mi):o}function oh(t,e){return t&&t.length?Ai(t,Ha(e,2),Mi):o}function ah(t){return qn(t,Sp)}function uh(t,e){return qn(t,Ha(e,2))}function sh(t){return t&&t.length?Ai(t,Sp,ro):o}function ch(t,e){return t&&t.length?Ai(t,Ha(e,2),ro):o}var lh=ba(function(t,e){return t*e},1),fh=Ea(\"round\"),ph=ba(function(t,e){return t-e},0);function hh(t){return t&&t.length?Bn(t,Sp):0}function dh(t,e){return t&&t.length?Bn(t,Ha(e,2)):0}return wr.after=Ec,wr.ary=jc,wr.assign=Yl,wr.assignIn=Ql,wr.assignInWith=tf,wr.assignWith=ef,wr.at=nf,wr.before=Sc,wr.bind=$c,wr.bindAll=xp,wr.bindKey=Tc,wr.castArray=Gc,wr.chain=Hs,wr.chunk=Lu,wr.compact=Iu,wr.concat=Pu,wr.cond=kp,wr.conforms=Ap,wr.constant=Op,wr.countBy=tc,wr.create=rf,wr.curry=Rc,wr.curryRight=Lc,wr.debounce=Ic,wr.defaults=of,wr.defaultsDeep=af,wr.defer=Pc,wr.delay=Mc,wr.difference=Mu,wr.differenceBy=Du,wr.differenceWith=Uu,wr.drop=zu,wr.dropRight=qu,wr.dropRightWhile=Nu,wr.dropWhile=Fu,wr.fill=Hu,wr.filter=nc,wr.flatMap=oc,wr.flatMapDeep=ac,wr.flatMapDepth=uc,wr.flatten=Ku,wr.flattenDeep=Vu,wr.flattenDepth=Zu,wr.flip=Dc,wr.flow=Ep,wr.flowRight=jp,wr.fromPairs=Xu,wr.functions=hf,wr.functionsIn=df,wr.groupBy=lc,wr.initial=Yu,wr.intersection=Qu,wr.intersectionBy=ts,wr.intersectionWith=es,wr.invert=_f,wr.invertBy=mf,wr.invokeMap=pc,wr.iteratee=$p,wr.keyBy=hc,wr.keys=wf,wr.keysIn=xf,wr.map=dc,wr.mapKeys=kf,wr.mapValues=Af,wr.matches=Tp,wr.matchesProperty=Rp,wr.memoize=Uc,wr.merge=Of,wr.mergeWith=Cf,wr.method=Lp,wr.methodOf=Ip,wr.mixin=Pp,wr.negate=zc,wr.nthArg=Up,wr.omit=Ef,wr.omitBy=jf,wr.once=qc,wr.orderBy=vc,wr.over=zp,wr.overArgs=Nc,wr.overEvery=qp,wr.overSome=Np,wr.partial=Fc,wr.partialRight=Hc,wr.partition=yc,wr.pick=Sf,wr.pickBy=$f,wr.property=Fp,wr.propertyOf=Hp,wr.pull=as,wr.pullAll=us,wr.pullAllBy=ss,wr.pullAllWith=cs,wr.pullAt=ls,wr.range=Wp,wr.rangeRight=Bp,wr.rearg=Wc,wr.reject=mc,wr.remove=fs,wr.rest=Bc,wr.reverse=ps,wr.sampleSize=wc,wr.set=Rf,wr.setWith=Lf,wr.shuffle=xc,wr.slice=hs,wr.sortBy=Oc,wr.sortedUniq=bs,wr.sortedUniqBy=ws,wr.split=up,wr.spread=Kc,wr.tail=xs,wr.take=ks,wr.takeRight=As,wr.takeRightWhile=Os,wr.takeWhile=Cs,wr.tap=Ws,wr.throttle=Vc,wr.thru=Bs,wr.toArray=Wl,wr.toPairs=If,wr.toPairsIn=Pf,wr.toPath=Yp,wr.toPlainObject=Xl,wr.transform=Mf,wr.unary=Zc,wr.union=Es,wr.unionBy=js,wr.unionWith=Ss,wr.uniq=$s,wr.uniqBy=Ts,wr.uniqWith=Rs,wr.unset=Df,wr.unzip=Ls,wr.unzipWith=Is,wr.update=Uf,wr.updateWith=zf,wr.values=qf,wr.valuesIn=Nf,wr.without=Ps,wr.words=bp,wr.wrap=Xc,wr.xor=Ms,wr.xorBy=Ds,wr.xorWith=Us,wr.zip=zs,wr.zipObject=qs,wr.zipObjectDeep=Ns,wr.zipWith=Fs,wr.entries=If,wr.entriesIn=Pf,wr.extend=Ql,wr.extendWith=tf,Pp(wr,wr),wr.add=th,wr.attempt=wp,wr.camelCase=Bf,wr.capitalize=Kf,wr.ceil=eh,wr.clamp=Ff,wr.clone=Jc,wr.cloneDeep=Qc,wr.cloneDeepWith=tl,wr.cloneWith=Yc,wr.conformsTo=el,wr.deburr=Vf,wr.defaultTo=Cp,wr.divide=nh,wr.endsWith=Zf,wr.eq=nl,wr.escape=Xf,wr.escapeRegExp=Gf,wr.every=ec,wr.find=rc,wr.findIndex=Wu,wr.findKey=uf,wr.findLast=ic,wr.findLastIndex=Bu,wr.findLastKey=sf,wr.floor=rh,wr.forEach=sc,wr.forEachRight=cc,wr.forIn=cf,wr.forInRight=lf,wr.forOwn=ff,wr.forOwnRight=pf,wr.get=vf,wr.gt=rl,wr.gte=il,wr.has=yf,wr.hasIn=gf,wr.head=Gu,wr.identity=Sp,wr.includes=fc,wr.indexOf=Ju,wr.inRange=Hf,wr.invoke=bf,wr.isArguments=ol,wr.isArray=al,wr.isArrayBuffer=ul,wr.isArrayLike=sl,wr.isArrayLikeObject=cl,wr.isBoolean=ll,wr.isBuffer=fl,wr.isDate=pl,wr.isElement=hl,wr.isEmpty=dl,wr.isEqual=vl,wr.isEqualWith=yl,wr.isError=gl,wr.isFinite=_l,wr.isFunction=ml,wr.isInteger=bl,wr.isLength=wl,wr.isMap=Al,wr.isMatch=Ol,wr.isMatchWith=Cl,wr.isNaN=El,wr.isNative=jl,wr.isNil=$l,wr.isNull=Sl,wr.isNumber=Tl,wr.isObject=xl,wr.isObjectLike=kl,wr.isPlainObject=Rl,wr.isRegExp=Ll,wr.isSafeInteger=Il,wr.isSet=Pl,wr.isString=Ml,wr.isSymbol=Dl,wr.isTypedArray=Ul,wr.isUndefined=zl,wr.isWeakMap=ql,wr.isWeakSet=Nl,wr.join=ns,wr.kebabCase=Jf,wr.last=rs,wr.lastIndexOf=is,wr.lowerCase=Yf,wr.lowerFirst=Qf,wr.lt=Fl,wr.lte=Hl,wr.max=ih,wr.maxBy=oh,wr.mean=ah,wr.meanBy=uh,wr.min=sh,wr.minBy=ch,wr.stubArray=Kp,wr.stubFalse=Vp,wr.stubObject=Zp,wr.stubString=Xp,wr.stubTrue=Gp,wr.multiply=lh,wr.nth=os,wr.noConflict=Mp,wr.noop=Dp,wr.now=Cc,wr.pad=tp,wr.padEnd=ep,wr.padStart=np,wr.parseInt=rp,wr.random=Wf,wr.reduce=gc,wr.reduceRight=_c,wr.repeat=ip,wr.replace=op,wr.result=Tf,wr.round=fh,wr.runInContext=t,wr.sample=bc,wr.size=kc,wr.snakeCase=ap,wr.some=Ac,wr.sortedIndex=ds,wr.sortedIndexBy=vs,wr.sortedIndexOf=ys,wr.sortedLastIndex=gs,wr.sortedLastIndexBy=_s,wr.sortedLastIndexOf=ms,wr.startCase=sp,wr.startsWith=cp,wr.subtract=ph,wr.sum=hh,wr.sumBy=dh,wr.template=lp,wr.times=Jp,wr.toFinite=Bl,wr.toInteger=Kl,wr.toLength=Vl,wr.toLower=fp,wr.toNumber=Zl,wr.toSafeInteger=Gl,wr.toString=Jl,wr.toUpper=pp,wr.trim=hp,wr.trimEnd=dp,wr.trimStart=vp,wr.truncate=yp,wr.unescape=gp,wr.uniqueId=Qp,wr.upperCase=_p,wr.upperFirst=mp,wr.each=sc,wr.eachRight=cc,wr.first=Gu,Pp(wr,function(){var t={};return $i(wr,function(e,n){fe.call(wr.prototype,n)||(t[n]=e)}),t}(),{chain:!1}),wr.VERSION=a,wn([\"bind\",\"bindKey\",\"curry\",\"curryRight\",\"partial\",\"partialRight\"],function(t){wr[t].placeholder=wr}),wn([\"drop\",\"take\"],function(t,e){Cr.prototype[t]=function(n){n=n===o?1:qe(Kl(n),0);var r=this.__filtered__&&!e?new Cr(this):this.clone();return r.__filtered__?r.__takeCount__=Ne(n,r.__takeCount__):r.__views__.push({size:Ne(n,z),type:t+(r.__dir__<0?\"Right\":\"\")}),r},Cr.prototype[t+\"Right\"]=function(e){return this.reverse()[t](e).reverse()}}),wn([\"filter\",\"map\",\"takeWhile\"],function(t,e){var n=e+1,r=n==R||n==I;Cr.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ha(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}}),wn([\"head\",\"last\"],function(t,e){var n=\"take\"+(e?\"Right\":\"\");Cr.prototype[t]=function(){return this[n](1).value()[0]}}),wn([\"initial\",\"tail\"],function(t,e){var n=\"drop\"+(e?\"\":\"Right\");Cr.prototype[t]=function(){return this.__filtered__?new Cr(this):this[n](1)}}),Cr.prototype.compact=function(){return this.filter(Sp)},Cr.prototype.find=function(t){return this.filter(t).head()},Cr.prototype.findLast=function(t){return this.reverse().find(t)},Cr.prototype.invokeMap=bo(function(t,e){return\"function\"==typeof t?new Cr(this):this.map(function(n){return Fi(n,t,e)})}),Cr.prototype.reject=function(t){return this.filter(zc(Ha(t)))},Cr.prototype.slice=function(t,e){t=Kl(t);var n=this;return n.__filtered__&&(t>0||e<0)?new Cr(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),e!==o&&(e=Kl(e),n=e<0?n.dropRight(-e):n.take(e-t)),n)},Cr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Cr.prototype.toArray=function(){return this.take(z)},$i(Cr.prototype,function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),i=wr[r?\"take\"+(\"last\"==e?\"Right\":\"\"):e],a=r||/^find/.test(e);i&&(wr.prototype[e]=function(){var e=this.__wrapped__,u=r?[1]:arguments,s=e instanceof Cr,c=u[0],l=s||al(e),f=function(t){var e=i.apply(wr,jn([t],u));return r&&p?e[0]:e};l&&n&&\"function\"==typeof c&&1!=c.length&&(s=l=!1);var p=this.__chain__,h=!!this.__actions__.length,d=a&&!p,v=s&&!h;if(!a&&l){e=v?e:new Cr(this);var y=t.apply(e,u);return y.__actions__.push({func:Bs,args:[f],thisArg:o}),new Or(y,p)}return d&&v?t.apply(this,u):(y=this.thru(f),d?r?y.value()[0]:y.value():y)})}),wn([\"pop\",\"push\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(t){var e=ae[t],n=/^(?:push|sort|unshift)$/.test(t)?\"tap\":\"thru\",r=/^(?:pop|shift)$/.test(t);wr.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return e.apply(al(i)?i:[],t)}return this[n](function(n){return e.apply(al(n)?n:[],t)})}}),$i(Cr.prototype,function(t,e){var n=wr[e];if(n){var r=n.name+\"\",i=cn[r]||(cn[r]=[]);i.push({name:e,func:n})}}),cn[_a(o,m).name]=[{name:\"wrapper\",func:o}],Cr.prototype.clone=Er,Cr.prototype.reverse=jr,Cr.prototype.value=Sr,wr.prototype.at=Ks,wr.prototype.chain=Vs,wr.prototype.commit=Zs,wr.prototype.next=Xs,wr.prototype.plant=Js,wr.prototype.reverse=Ys,wr.prototype.toJSON=wr.prototype.valueOf=wr.prototype.value=Qs,wr.prototype.first=wr.prototype.head,Ee&&(wr.prototype[Ee]=Gs),wr},xr=wr();un._=xr,i=function(){return xr}.call(e,n,e,r),i===o||(r.exports=i)}).call(this)}).call(this,n(\"yLpj\"),n(\"YuTi\")(t))},LyE8:function(t,e,n){\"use strict\";var r=n(\"eeVq\");t.exports=function(t,e){return!!t&&r(function(){e?t.call(null,function(){},1):t.call(null)})}},M6Qj:function(t,e,n){var r=n(\"hPIQ\"),i=n(\"K0xU\")(\"iterator\"),o=Array.prototype;t.exports=function(t){return void 0!==t&&(r.Array===t||o[i]===t)}},MfQN:function(t,e){t.exports=function(t,e,n){var r=void 0===n;switch(e.length){case 0:return r?t():t.call(n);case 1:return r?t(e[0]):t.call(n,e[0]);case 2:return r?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return r?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return r?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},Mukb:function(t,e,n){var r=n(\"hswa\"),i=n(\"RjD/\");t.exports=n(\"nh4g\")?function(t,e,n){return r.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},OEbY:function(t,e,n){n(\"nh4g\")&&\"g\"!=/./g.flags&&n(\"hswa\").f(RegExp.prototype,\"flags\",{configurable:!0,get:n(\"C/va\")})},OP3Y:function(t,e,n){var r=n(\"aagx\"),i=n(\"S/j/\"),o=n(\"YTvA\")(\"IE_PROTO\"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=i(t),r(t,o)?t[o]:\"function\"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},QaDb:function(t,e,n){\"use strict\";var r=n(\"Kuth\"),i=n(\"RjD/\"),o=n(\"fyDq\"),a={};n(\"Mukb\")(a,n(\"K0xU\")(\"iterator\"),function(){return this}),t.exports=function(t,e,n){t.prototype=r(a,{next:i(1,n)}),o(t,e+\" Iterator\")}},RYi7:function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},\"RjD/\":function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},\"S/j/\":function(t,e,n){var r=n(\"vhPU\");t.exports=function(t){return Object(r(t))}},SlkY:function(t,e,n){var r=n(\"m0Pp\"),i=n(\"H6hf\"),o=n(\"M6Qj\"),a=n(\"y3w9\"),u=n(\"ne8i\"),s=n(\"J+6e\"),c={},l={};e=t.exports=function(t,e,n,f,p){var h,d,v,y,g=p?function(){return t}:s(t),_=r(n,f,e?2:1),m=0;if(\"function\"!=typeof g)throw TypeError(t+\" is not iterable!\");if(o(g)){for(h=u(t.length);h>m;m++)if(y=e?_(a(d=t[m])[0],d[1]):_(t[m]),y===c||y===l)return y}else for(v=g.call(t);!(d=v.next()).done;)if(y=i(v,_,d.value,e),y===c||y===l)return y};e.BREAK=c,e.RETURN=l},TrxG:function(t,e,n){var r=n(\"hcir\");function i(t){return t._query=[Date.now().toString()],t}t.exports=function(t,e){return t.set(\"X-Requested-With\",\"XMLHttpRequest\"),t.set(\"Expires\",\"-1\"),t.set(\"Cache-Control\",\"no-cache,no-store,must-revalidate,max-age=-1,private\"),(r||e)&&i(t),t}},UUeW:function(t,e,n){var r=n(\"K0xU\")(\"match\");t.exports=function(t){var e=/./;try{\"/./\"[t](e)}catch(n){try{return e[r]=!1,!\"/./\"[t](e)}catch(t){}}return!0}},UqcF:function(t,e){e.f={}.propertyIsEnumerable},VRzm:function(t,e,n){\"use strict\";var r,i,o,a,u=n(\"LQAc\"),s=n(\"dyZX\"),c=n(\"m0Pp\"),l=n(\"I8a+\"),f=n(\"XKFU\"),p=n(\"0/R4\"),h=n(\"2OiF\"),d=n(\"9gX7\"),v=n(\"SlkY\"),y=n(\"69bn\"),g=n(\"GZEu\").set,_=n(\"gHnn\")(),m=n(\"pbhE\"),b=n(\"nICZ\"),w=n(\"ol8x\"),x=n(\"vKrd\"),k=\"Promise\",A=s.TypeError,O=s.process,C=O&&O.versions,E=C&&C.v8||\"\",j=s[k],S=\"process\"==l(O),$=function(){},T=i=m.f,R=!!function(){try{var t=j.resolve(1),e=(t.constructor={})[n(\"K0xU\")(\"species\")]=function(t){t($,$)};return(S||\"function\"==typeof PromiseRejectionEvent)&&t.then($)instanceof e&&0!==E.indexOf(\"6.6\")&&-1===w.indexOf(\"Chrome/66\")}catch(t){}}(),L=function(t){var e;return!(!p(t)||\"function\"!=typeof(e=t.then))&&e},I=function(t,e){if(!t._n){t._n=!0;var n=t._c;_(function(){var r=t._v,i=1==t._s,o=0,a=function(e){var n,o,a,u=i?e.ok:e.fail,s=e.resolve,c=e.reject,l=e.domain;try{u?(i||(2==t._h&&D(t),t._h=1),!0===u?n=r:(l&&l.enter(),n=u(r),l&&(l.exit(),a=!0)),n===e.promise?c(A(\"Promise-chain cycle\")):(o=L(n))?o.call(n,s,c):s(n)):c(r)}catch(t){l&&!a&&l.exit(),c(t)}};while(n.length>o)a(n[o++]);t._c=[],t._n=!1,e&&!t._h&&P(t)})}},P=function(t){g.call(s,function(){var e,n,r,i=t._v,o=M(t);if(o&&(e=b(function(){S?O.emit(\"unhandledRejection\",i,t):(n=s.onunhandledrejection)?n({promise:t,reason:i}):(r=s.console)&&r.error&&r.error(\"Unhandled promise rejection\",i)}),t._h=S||M(t)?2:1),t._a=void 0,o&&e.e)throw e.v})},M=function(t){return 1!==t._h&&0===(t._a||t._c).length},D=function(t){g.call(s,function(){var e;S?O.emit(\"rejectionHandled\",t):(e=s.onrejectionhandled)&&e({promise:t,reason:t._v})})},U=function(t){var e=this;e._d||(e._d=!0,e=e._w||e,e._v=t,e._s=2,e._a||(e._a=e._c.slice()),I(e,!0))},z=function(t){var e,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===t)throw A(\"Promise can't be resolved itself\");(e=L(t))?_(function(){var r={_w:n,_d:!1};try{e.call(t,c(z,r,1),c(U,r,1))}catch(t){U.call(r,t)}}):(n._v=t,n._s=1,I(n,!1))}catch(t){U.call({_w:n,_d:!1},t)}}};R||(j=function(t){d(this,j,k,\"_h\"),h(t),r.call(this);try{t(c(z,this,1),c(U,this,1))}catch(t){U.call(this,t)}},r=function(t){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1},r.prototype=n(\"3Lyj\")(j.prototype,{then:function(t,e){var n=T(y(this,j));return n.ok=\"function\"!=typeof t||t,n.fail=\"function\"==typeof e&&e,n.domain=S?O.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&I(this,!1),n.promise},catch:function(t){return this.then(void 0,t)}}),o=function(){var t=new r;this.promise=t,this.resolve=c(z,t,1),this.reject=c(U,t,1)},m.f=T=function(t){return t===j||t===a?new o(t):i(t)}),f(f.G+f.W+f.F*!R,{Promise:j}),n(\"fyDq\")(j,k),n(\"elZq\")(k),a=n(\"g3g5\")[k],f(f.S+f.F*!R,k,{reject:function(t){var e=T(this),n=e.reject;return n(t),e.promise}}),f(f.S+f.F*(u||!R),k,{resolve:function(t){return x(u&&this===a?j:this,t)}}),f(f.S+f.F*!(R&&n(\"XMVh\")(function(t){j.all(t)[\"catch\"]($)})),k,{all:function(t){var e=this,n=T(e),r=n.resolve,i=n.reject,o=b(function(){var n=[],o=0,a=1;v(t,!1,function(t){var u=o++,s=!1;n.push(void 0),a++,e.resolve(t).then(function(t){s||(s=!0,n[u]=t,--a||r(n))},i)}),--a||r(n)});return o.e&&i(o.v),n.promise},race:function(t){var e=this,n=T(e),r=n.reject,i=b(function(){v(t,!1,function(t){e.resolve(t).then(n.resolve,r)})});return i.e&&r(i.v),n.promise}})},VTer:function(t,e,n){var r=n(\"g3g5\"),i=n(\"dyZX\"),o=\"__core-js_shared__\",a=i[o]||(i[o]={});(t.exports=function(t,e){return a[t]||(a[t]=void 0!==e?e:{})})(\"versions\",[]).push({version:r.version,mode:n(\"LQAc\")?\"pure\":\"global\",copyright:\"© 2018 Denis Pushkarev (zloirock.ru)\"})},Vd3H:function(t,e,n){\"use strict\";var r=n(\"XKFU\"),i=n(\"2OiF\"),o=n(\"S/j/\"),a=n(\"eeVq\"),u=[].sort,s=[1,2,3];r(r.P+r.F*(a(function(){s.sort(void 0)})||!a(function(){s.sort(null)})||!n(\"LyE8\")(u)),\"Array\",{sort:function(t){return void 0===t?u.call(o(this)):u.call(o(this),i(t))}})},XKFU:function(t,e,n){var r=n(\"dyZX\"),i=n(\"g3g5\"),o=n(\"Mukb\"),a=n(\"KroJ\"),u=n(\"m0Pp\"),s=\"prototype\",c=function(t,e,n){var l,f,p,h,d=t&c.F,v=t&c.G,y=t&c.S,g=t&c.P,_=t&c.B,m=v?r:y?r[e]||(r[e]={}):(r[e]||{})[s],b=v?i:i[e]||(i[e]={}),w=b[s]||(b[s]={});for(l in v&&(n=e),n)f=!d&&m&&void 0!==m[l],p=(f?m:n)[l],h=_&&f?u(p,r):g&&\"function\"==typeof p?u(Function.call,p):p,m&&a(m,l,p,t&c.U),b[l]!=p&&o(b,l,h),g&&w[l]!=p&&(w[l]=p)};r.core=i,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,t.exports=c},XMVh:function(t,e,n){var r=n(\"K0xU\")(\"iterator\"),i=!1;try{var o=[7][r]();o[\"return\"]=function(){i=!0},Array.from(o,function(){throw 2})}catch(t){}t.exports=function(t,e){if(!e&&!i)return!1;var n=!1;try{var o=[7],a=o[r]();a.next=function(){return{done:n=!0}},o[r]=function(){return a},t(o)}catch(t){}return n}},YTvA:function(t,e,n){var r=n(\"VTer\")(\"keys\"),i=n(\"ylqs\");t.exports=function(t){return r[t]||(r[t]=i(t))}},Ymqv:function(t,e,n){var r=n(\"LZWt\");t.exports=Object(\"z\").propertyIsEnumerable(0)?Object:function(t){return\"String\"==r(t)?t.split(\"\"):Object(t)}},YuTi:function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,\"loaded\",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,\"id\",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},Z2Ku:function(t,e,n){\"use strict\";var r=n(\"XKFU\"),i=n(\"w2a5\")(!0);r(r.P,\"Array\",{includes:function(t){return i(this,t,arguments.length>1?arguments[1]:void 0)}}),n(\"nGyu\")(\"includes\")},a1Th:function(t,e,n){\"use strict\";n(\"OEbY\");var r=n(\"y3w9\"),i=n(\"C/va\"),o=n(\"nh4g\"),a=\"toString\",u=/./[a],s=function(t){n(\"KroJ\")(RegExp.prototype,a,t,!0)};n(\"eeVq\")(function(){return\"/a/b\"!=u.call({source:\"a\",flags:\"b\"})})?s(function(){var t=r(this);return\"/\".concat(t.source,\"/\",\"flags\"in t?t.flags:!o&&t instanceof RegExp?i.call(t):void 0)}):u.name!=a&&s(function(){return u.call(this)})},aCFj:function(t,e,n){var r=n(\"Ymqv\"),i=n(\"vhPU\");t.exports=function(t){return r(i(t))}},aagx:function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},apmT:function(t,e,n){var r=n(\"0/R4\");t.exports=function(t,e){if(!r(t))return t;var n,i;if(e&&\"function\"==typeof(n=t.toString)&&!r(i=n.call(t)))return i;if(\"function\"==typeof(n=t.valueOf)&&!r(i=n.call(t)))return i;if(!e&&\"function\"==typeof(n=t.toString)&&!r(i=n.call(t)))return i;throw TypeError(\"Can't convert object to primitive value\")}},cpc2:function(t,e,n){function r(t){if(t)return i(t)}function i(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks[\"$\"+t]=this._callbacks[\"$\"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks[\"$\"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks[\"$\"+t],this;for(var i=0;i<r.length;i++)if(n=r[i],n===e||n.fn===e){r.splice(i,1);break}return this},r.prototype.emit=function(t){this._callbacks=this._callbacks||{};var e=[].slice.call(arguments,1),n=this._callbacks[\"$\"+t];if(n){n=n.slice(0);for(var r=0,i=n.length;r<i;++r)n[r].apply(this,e)}return this},r.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[\"$\"+t]||[]},r.prototype.hasListeners=function(t){return!!this.listeners(t).length}},czNK:function(t,e,n){\"use strict\";var r=n(\"DVgA\"),i=n(\"JiEa\"),o=n(\"UqcF\"),a=n(\"S/j/\"),u=n(\"Ymqv\"),s=Object.assign;t.exports=!s||n(\"eeVq\")(function(){var t={},e={},n=Symbol(),r=\"abcdefghijklmnopqrst\";return t[n]=7,r.split(\"\").forEach(function(t){e[t]=t}),7!=s({},t)[n]||Object.keys(s({},e)).join(\"\")!=r})?function(t,e){var n=a(t),s=arguments.length,c=1,l=i.f,f=o.f;while(s>c){var p,h=u(arguments[c++]),d=l?r(h).concat(l(h)):r(h),v=d.length,y=0;while(v>y)f.call(h,p=d[y++])&&(n[p]=h[p])}return n}:s},\"d/Gc\":function(t,e,n){var r=n(\"RYi7\"),i=Math.max,o=Math.min;t.exports=function(t,e){return t=r(t),t<0?i(t+e,0):o(t,e)}},dRSK:function(t,e,n){\"use strict\";var r=n(\"XKFU\"),i=n(\"CkkT\")(5),o=\"find\",a=!0;o in[]&&Array(1)[o](function(){a=!1}),r(r.P+r.F*a,\"Array\",{find:function(t){return i(this,t,arguments.length>1?arguments[1]:void 0)}}),n(\"nGyu\")(o)},dyZX:function(t,e){var n=t.exports=\"undefined\"!=typeof window&&window.Math==Math?window:\"undefined\"!=typeof self&&self.Math==Math?self:Function(\"return this\")();\"number\"==typeof __g&&(__g=n)},eeVq:function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},elZq:function(t,e,n){\"use strict\";var r=n(\"dyZX\"),i=n(\"hswa\"),o=n(\"nh4g\"),a=n(\"K0xU\")(\"species\");t.exports=function(t){var e=r[t];o&&e&&!e[a]&&i.f(e,a,{configurable:!0,get:function(){return this}})}},\"f3/d\":function(t,e,n){var r=n(\"hswa\").f,i=Function.prototype,o=/^\\s*function ([^ (]*)/,a=\"name\";a in i||n(\"nh4g\")&&r(i,a,{configurable:!0,get:function(){try{return(\"\"+this).match(o)[1]}catch(t){return\"\"}}})},fyDq:function(t,e,n){var r=n(\"hswa\").f,i=n(\"aagx\"),o=n(\"K0xU\")(\"toStringTag\");t.exports=function(t,e,n){t&&!i(t=n?t:t.prototype,o)&&r(t,o,{configurable:!0,value:e})}},g3g5:function(t,e){var n=t.exports={version:\"2.5.7\"};\"number\"==typeof __e&&(__e=n)},gHnn:function(t,e,n){var r=n(\"dyZX\"),i=n(\"GZEu\").set,o=r.MutationObserver||r.WebKitMutationObserver,a=r.process,u=r.Promise,s=\"process\"==n(\"LZWt\")(a);t.exports=function(){var t,e,n,c=function(){var r,i;s&&(r=a.domain)&&r.exit();while(t){i=t.fn,t=t.next;try{i()}catch(r){throw t?n():e=void 0,r}}e=void 0,r&&r.enter()};if(s)n=function(){a.nextTick(c)};else if(!o||r.navigator&&r.navigator.standalone)if(u&&u.resolve){var l=u.resolve(void 0);n=function(){l.then(c)}}else n=function(){i.call(r,c)};else{var f=!0,p=document.createTextNode(\"\");new o(c).observe(p,{characterData:!0}),n=function(){p.data=f=!f}}return function(r){var i={fn:r,next:void 0};e&&(e.next=i),t||(t=i,n()),e=i}}},hPIQ:function(t,e){t.exports={}},hcir:function(t,e){function n(){for(var t=3,e=document.createElement(\"b\"),n=e.all||[];e.innerHTML=\"\\x3c!--[if gt IE \"+ ++t+\"]><i><![endif]--\\x3e\",n[0];);return t>4?t:document.documentMode}t.exports=n()},hswa:function(t,e,n){var r=n(\"y3w9\"),i=n(\"xpql\"),o=n(\"apmT\"),a=Object.defineProperty;e.f=n(\"nh4g\")?Object.defineProperty:function(t,e,n){if(r(t),e=o(e,!0),r(n),i)try{return a(t,e,n)}catch(t){}if(\"get\"in n||\"set\"in n)throw TypeError(\"Accessors not supported!\");return\"value\"in n&&(t[e]=n.value),t}},iv4g:function(t,e,n){\"use strict\";function r(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}function i(t){if(Symbol.iterator in Object(t)||\"[object Arguments]\"===Object.prototype.toString.call(t))return Array.from(t)}function o(){throw new TypeError(\"Invalid attempt to spread non-iterable instance\")}function a(t){return r(t)||i(t)||o()}n.d(e,\"a\",function(){return a})},jE9Z:function(t,e,n){\"use strict\";\n/**\n  * vue-router v3.0.1\n  * (c) 2017 Evan You\n  * @license MIT\n  */function r(t,e){0}function i(t){return Object.prototype.toString.call(t).indexOf(\"Error\")>-1}var o={name:\"router-view\",functional:!0,props:{name:{type:String,default:\"default\"}},render:function(t,e){var n=e.props,r=e.children,i=e.parent,o=e.data;o.routerView=!0;var s=i.$createElement,c=n.name,l=i.$route,f=i._routerViewCache||(i._routerViewCache={}),p=0,h=!1;while(i&&i._routerRoot!==i)i.$vnode&&i.$vnode.data.routerView&&p++,i._inactive&&(h=!0),i=i.$parent;if(o.routerViewDepth=p,h)return s(f[c],o,r);var d=l.matched[p];if(!d)return f[c]=null,s();var v=f[c]=d.components[c];o.registerRouteInstance=function(t,e){var n=d.instances[c];(e&&n!==t||!e&&n===t)&&(d.instances[c]=e)},(o.hook||(o.hook={})).prepatch=function(t,e){d.instances[c]=e.componentInstance};var y=o.props=a(l,d.props&&d.props[c]);if(y){y=o.props=u({},y);var g=o.attrs=o.attrs||{};for(var _ in y)v.props&&_ in v.props||(g[_]=y[_],delete y[_])}return s(v,o,r)}};function a(t,e){switch(typeof e){case\"undefined\":return;case\"object\":return e;case\"function\":return e(t);case\"boolean\":return e?t.params:void 0;default:0}}function u(t,e){for(var n in e)t[n]=e[n];return t}var s=/[!'()*]/g,c=function(t){return\"%\"+t.charCodeAt(0).toString(16)},l=/%2C/g,f=function(t){return encodeURIComponent(t).replace(s,c).replace(l,\",\")},p=decodeURIComponent;function h(t,e,n){void 0===e&&(e={});var r,i=n||d;try{r=i(t||\"\")}catch(t){r={}}for(var o in e)r[o]=e[o];return r}function d(t){var e={};return t=t.trim().replace(/^(\\?|#|&)/,\"\"),t?(t.split(\"&\").forEach(function(t){var n=t.replace(/\\+/g,\" \").split(\"=\"),r=p(n.shift()),i=n.length>0?p(n.join(\"=\")):null;void 0===e[r]?e[r]=i:Array.isArray(e[r])?e[r].push(i):e[r]=[e[r],i]}),e):e}function v(t){var e=t?Object.keys(t).map(function(e){var n=t[e];if(void 0===n)return\"\";if(null===n)return f(e);if(Array.isArray(n)){var r=[];return n.forEach(function(t){void 0!==t&&(null===t?r.push(f(e)):r.push(f(e)+\"=\"+f(t)))}),r.join(\"&\")}return f(e)+\"=\"+f(n)}).filter(function(t){return t.length>0}).join(\"&\"):null;return e?\"?\"+e:\"\"}var y=/\\/?$/;function g(t,e,n,r){var i=r&&r.options.stringifyQuery,o=e.query||{};try{o=_(o)}catch(t){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||\"/\",hash:e.hash||\"\",query:o,params:e.params||{},fullPath:w(e,i),matched:t?b(t):[]};return n&&(a.redirectedFrom=w(n,i)),Object.freeze(a)}function _(t){if(Array.isArray(t))return t.map(_);if(t&&\"object\"===typeof t){var e={};for(var n in t)e[n]=_(t[n]);return e}return t}var m=g(null,{path:\"/\"});function b(t){var e=[];while(t)e.unshift(t),t=t.parent;return e}function w(t,e){var n=t.path,r=t.query;void 0===r&&(r={});var i=t.hash;void 0===i&&(i=\"\");var o=e||v;return(n||\"/\")+o(r)+i}function x(t,e){return e===m?t===e:!!e&&(t.path&&e.path?t.path.replace(y,\"\")===e.path.replace(y,\"\")&&t.hash===e.hash&&k(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&k(t.query,e.query)&&k(t.params,e.params)))}function k(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(function(n){var r=t[n],i=e[n];return\"object\"===typeof r&&\"object\"===typeof i?k(r,i):String(r)===String(i)})}function A(t,e){return 0===t.path.replace(y,\"/\").indexOf(e.path.replace(y,\"/\"))&&(!e.hash||t.hash===e.hash)&&O(t.query,e.query)}function O(t,e){for(var n in e)if(!(n in t))return!1;return!0}var C,E=[String,Object],j=[String,Array],S={name:\"router-link\",props:{to:{type:E,required:!0},tag:{type:String,default:\"a\"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:j,default:\"click\"}},render:function(t){var e=this,n=this.$router,r=this.$route,i=n.resolve(this.to,r,this.append),o=i.location,a=i.route,u=i.href,s={},c=n.options.linkActiveClass,l=n.options.linkExactActiveClass,f=null==c?\"router-link-active\":c,p=null==l?\"router-link-exact-active\":l,h=null==this.activeClass?f:this.activeClass,d=null==this.exactActiveClass?p:this.exactActiveClass,v=o.path?g(null,o,null,n):a;s[d]=x(r,v),s[h]=this.exact?s[d]:A(r,v);var y=function(t){$(t)&&(e.replace?n.replace(o):n.push(o))},_={click:$};Array.isArray(this.event)?this.event.forEach(function(t){_[t]=y}):_[this.event]=y;var m={class:s};if(\"a\"===this.tag)m.on=_,m.attrs={href:u};else{var b=T(this.$slots.default);if(b){b.isStatic=!1;var w=C.util.extend,k=b.data=w({},b.data);k.on=_;var O=b.data.attrs=w({},b.data.attrs);O.href=u}else m.on=_}return t(this.tag,m,this.$slots.default)}};function $(t){if(!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)&&!t.defaultPrevented&&(void 0===t.button||0===t.button)){if(t.currentTarget&&t.currentTarget.getAttribute){var e=t.currentTarget.getAttribute(\"target\");if(/\\b_blank\\b/i.test(e))return}return t.preventDefault&&t.preventDefault(),!0}}function T(t){if(t)for(var e,n=0;n<t.length;n++){if(e=t[n],\"a\"===e.tag)return e;if(e.children&&(e=T(e.children)))return e}}function R(t){if(!R.installed||C!==t){R.installed=!0,C=t;var e=function(t){return void 0!==t},n=function(t,n){var r=t.$options._parentVnode;e(r)&&e(r=r.data)&&e(r=r.registerRouteInstance)&&r(t,n)};t.mixin({beforeCreate:function(){e(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),t.util.defineReactive(this,\"_route\",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,n(this,this)},destroyed:function(){n(this)}}),Object.defineProperty(t.prototype,\"$router\",{get:function(){return this._routerRoot._router}}),Object.defineProperty(t.prototype,\"$route\",{get:function(){return this._routerRoot._route}}),t.component(\"router-view\",o),t.component(\"router-link\",S);var r=t.config.optionMergeStrategies;r.beforeRouteEnter=r.beforeRouteLeave=r.beforeRouteUpdate=r.created}}var L=\"undefined\"!==typeof window;function I(t,e,n){var r=t.charAt(0);if(\"/\"===r)return t;if(\"?\"===r||\"#\"===r)return e+t;var i=e.split(\"/\");n&&i[i.length-1]||i.pop();for(var o=t.replace(/^\\//,\"\").split(\"/\"),a=0;a<o.length;a++){var u=o[a];\"..\"===u?i.pop():\".\"!==u&&i.push(u)}return\"\"!==i[0]&&i.unshift(\"\"),i.join(\"/\")}function P(t){var e=\"\",n=\"\",r=t.indexOf(\"#\");r>=0&&(e=t.slice(r),t=t.slice(0,r));var i=t.indexOf(\"?\");return i>=0&&(n=t.slice(i+1),t=t.slice(0,i)),{path:t,query:n,hash:e}}function M(t){return t.replace(/\\/\\//g,\"/\")}var D=Array.isArray||function(t){return\"[object Array]\"==Object.prototype.toString.call(t)},U=rt,z=W,q=B,N=Z,F=nt,H=new RegExp([\"(\\\\\\\\.)\",\"([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))\"].join(\"|\"),\"g\");function W(t,e){var n,r=[],i=0,o=0,a=\"\",u=e&&e.delimiter||\"/\";while(null!=(n=H.exec(t))){var s=n[0],c=n[1],l=n.index;if(a+=t.slice(o,l),o=l+s.length,c)a+=c[1];else{var f=t[o],p=n[2],h=n[3],d=n[4],v=n[5],y=n[6],g=n[7];a&&(r.push(a),a=\"\");var _=null!=p&&null!=f&&f!==p,m=\"+\"===y||\"*\"===y,b=\"?\"===y||\"*\"===y,w=n[2]||u,x=d||v;r.push({name:h||i++,prefix:p||\"\",delimiter:w,optional:b,repeat:m,partial:_,asterisk:!!g,pattern:x?G(x):g?\".*\":\"[^\"+X(w)+\"]+?\"})}}return o<t.length&&(a+=t.substr(o)),a&&r.push(a),r}function B(t,e){return Z(W(t,e))}function K(t){return encodeURI(t).replace(/[\\/?#]/g,function(t){return\"%\"+t.charCodeAt(0).toString(16).toUpperCase()})}function V(t){return encodeURI(t).replace(/[?#]/g,function(t){return\"%\"+t.charCodeAt(0).toString(16).toUpperCase()})}function Z(t){for(var e=new Array(t.length),n=0;n<t.length;n++)\"object\"===typeof t[n]&&(e[n]=new RegExp(\"^(?:\"+t[n].pattern+\")$\"));return function(n,r){for(var i=\"\",o=n||{},a=r||{},u=a.pretty?K:encodeURIComponent,s=0;s<t.length;s++){var c=t[s];if(\"string\"!==typeof c){var l,f=o[c.name];if(null==f){if(c.optional){c.partial&&(i+=c.prefix);continue}throw new TypeError('Expected \"'+c.name+'\" to be defined')}if(D(f)){if(!c.repeat)throw new TypeError('Expected \"'+c.name+'\" to not repeat, but received `'+JSON.stringify(f)+\"`\");if(0===f.length){if(c.optional)continue;throw new TypeError('Expected \"'+c.name+'\" to not be empty')}for(var p=0;p<f.length;p++){if(l=u(f[p]),!e[s].test(l))throw new TypeError('Expected all \"'+c.name+'\" to match \"'+c.pattern+'\", but received `'+JSON.stringify(l)+\"`\");i+=(0===p?c.prefix:c.delimiter)+l}}else{if(l=c.asterisk?V(f):u(f),!e[s].test(l))throw new TypeError('Expected \"'+c.name+'\" to match \"'+c.pattern+'\", but received \"'+l+'\"');i+=c.prefix+l}}else i+=c}return i}}function X(t){return t.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g,\"\\\\$1\")}function G(t){return t.replace(/([=!:$\\/()])/g,\"\\\\$1\")}function J(t,e){return t.keys=e,t}function Y(t){return t.sensitive?\"\":\"i\"}function Q(t,e){var n=t.source.match(/\\((?!\\?)/g);if(n)for(var r=0;r<n.length;r++)e.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return J(t,e)}function tt(t,e,n){for(var r=[],i=0;i<t.length;i++)r.push(rt(t[i],e,n).source);var o=new RegExp(\"(?:\"+r.join(\"|\")+\")\",Y(n));return J(o,e)}function et(t,e,n){return nt(W(t,n),e,n)}function nt(t,e,n){D(e)||(n=e||n,e=[]),n=n||{};for(var r=n.strict,i=!1!==n.end,o=\"\",a=0;a<t.length;a++){var u=t[a];if(\"string\"===typeof u)o+=X(u);else{var s=X(u.prefix),c=\"(?:\"+u.pattern+\")\";e.push(u),u.repeat&&(c+=\"(?:\"+s+c+\")*\"),c=u.optional?u.partial?s+\"(\"+c+\")?\":\"(?:\"+s+\"(\"+c+\"))?\":s+\"(\"+c+\")\",o+=c}}var l=X(n.delimiter||\"/\"),f=o.slice(-l.length)===l;return r||(o=(f?o.slice(0,-l.length):o)+\"(?:\"+l+\"(?=$))?\"),o+=i?\"$\":r&&f?\"\":\"(?=\"+l+\"|$)\",J(new RegExp(\"^\"+o,Y(n)),e)}function rt(t,e,n){return D(e)||(n=e||n,e=[]),n=n||{},t instanceof RegExp?Q(t,e):D(t)?tt(t,e,n):et(t,e,n)}U.parse=z,U.compile=q,U.tokensToFunction=N,U.tokensToRegExp=F;var it=Object.create(null);function ot(t,e,n){try{var r=it[t]||(it[t]=U.compile(t));return r(e||{},{pretty:!0})}catch(t){return\"\"}}function at(t,e,n,r){var i=e||[],o=n||Object.create(null),a=r||Object.create(null);t.forEach(function(t){ut(i,o,a,t)});for(var u=0,s=i.length;u<s;u++)\"*\"===i[u]&&(i.push(i.splice(u,1)[0]),s--,u--);return{pathList:i,pathMap:o,nameMap:a}}function ut(t,e,n,r,i,o){var a=r.path,u=r.name;var s=r.pathToRegexpOptions||{},c=ct(a,i,s.strict);\"boolean\"===typeof r.caseSensitive&&(s.sensitive=r.caseSensitive);var l={path:c,regex:st(c,s),components:r.components||{default:r.component},instances:{},name:u,parent:i,matchAs:o,redirect:r.redirect,beforeEnter:r.beforeEnter,meta:r.meta||{},props:null==r.props?{}:r.components?r.props:{default:r.props}};if(r.children&&r.children.forEach(function(r){var i=o?M(o+\"/\"+r.path):void 0;ut(t,e,n,r,l,i)}),void 0!==r.alias){var f=Array.isArray(r.alias)?r.alias:[r.alias];f.forEach(function(o){var a={path:o,children:r.children};ut(t,e,n,a,i,l.path||\"/\")})}e[l.path]||(t.push(l.path),e[l.path]=l),u&&(n[u]||(n[u]=l))}function st(t,e){var n=U(t,[],e);return n}function ct(t,e,n){return n||(t=t.replace(/\\/$/,\"\")),\"/\"===t[0]?t:null==e?t:M(e.path+\"/\"+t)}function lt(t,e,n,r){var i=\"string\"===typeof t?{path:t}:t;if(i.name||i._normalized)return i;if(!i.path&&i.params&&e){i=ft({},i),i._normalized=!0;var o=ft(ft({},e.params),i.params);if(e.name)i.name=e.name,i.params=o;else if(e.matched.length){var a=e.matched[e.matched.length-1].path;i.path=ot(a,o,\"path \"+e.path)}else 0;return i}var u=P(i.path||\"\"),s=e&&e.path||\"/\",c=u.path?I(u.path,s,n||i.append):s,l=h(u.query,i.query,r&&r.options.parseQuery),f=i.hash||u.hash;return f&&\"#\"!==f.charAt(0)&&(f=\"#\"+f),{_normalized:!0,path:c,query:l,hash:f}}function ft(t,e){for(var n in e)t[n]=e[n];return t}function pt(t,e){var n=at(t),r=n.pathList,i=n.pathMap,o=n.nameMap;function a(t){at(t,r,i,o)}function u(t,n,a){var u=lt(t,n,!1,e),s=u.name;if(s){var c=o[s];if(!c)return l(null,u);var f=c.regex.keys.filter(function(t){return!t.optional}).map(function(t){return t.name});if(\"object\"!==typeof u.params&&(u.params={}),n&&\"object\"===typeof n.params)for(var p in n.params)!(p in u.params)&&f.indexOf(p)>-1&&(u.params[p]=n.params[p]);if(c)return u.path=ot(c.path,u.params,'named route \"'+s+'\"'),l(c,u,a)}else if(u.path){u.params={};for(var h=0;h<r.length;h++){var d=r[h],v=i[d];if(ht(v.regex,u.path,u.params))return l(v,u,a)}}return l(null,u)}function s(t,n){var r=t.redirect,i=\"function\"===typeof r?r(g(t,n,null,e)):r;if(\"string\"===typeof i&&(i={path:i}),!i||\"object\"!==typeof i)return l(null,n);var a=i,s=a.name,c=a.path,f=n.query,p=n.hash,h=n.params;if(f=a.hasOwnProperty(\"query\")?a.query:f,p=a.hasOwnProperty(\"hash\")?a.hash:p,h=a.hasOwnProperty(\"params\")?a.params:h,s){o[s];return u({_normalized:!0,name:s,query:f,hash:p,params:h},void 0,n)}if(c){var d=dt(c,t),v=ot(d,h,'redirect route with path \"'+d+'\"');return u({_normalized:!0,path:v,query:f,hash:p},void 0,n)}return l(null,n)}function c(t,e,n){var r=ot(n,e.params,'aliased route with path \"'+n+'\"'),i=u({_normalized:!0,path:r});if(i){var o=i.matched,a=o[o.length-1];return e.params=i.params,l(a,e)}return l(null,e)}function l(t,n,r){return t&&t.redirect?s(t,r||n):t&&t.matchAs?c(t,n,t.matchAs):g(t,n,r,e)}return{match:u,addRoutes:a}}function ht(t,e,n){var r=e.match(t);if(!r)return!1;if(!n)return!0;for(var i=1,o=r.length;i<o;++i){var a=t.keys[i-1],u=\"string\"===typeof r[i]?decodeURIComponent(r[i]):r[i];a&&(n[a.name]=u)}return!0}function dt(t,e){return I(t,e.parent?e.parent.path:\"/\",!0)}var vt=Object.create(null);function yt(){window.history.replaceState({key:$t()},\"\"),window.addEventListener(\"popstate\",function(t){_t(),t.state&&t.state.key&&Tt(t.state.key)})}function gt(t,e,n,r){if(t.app){var i=t.options.scrollBehavior;i&&t.app.$nextTick(function(){var t=mt(),o=i(e,n,r?t:null);o&&(\"function\"===typeof o.then?o.then(function(e){Ot(e,t)}).catch(function(t){0}):Ot(o,t))})}}function _t(){var t=$t();t&&(vt[t]={x:window.pageXOffset,y:window.pageYOffset})}function mt(){var t=$t();if(t)return vt[t]}function bt(t,e){var n=document.documentElement,r=n.getBoundingClientRect(),i=t.getBoundingClientRect();return{x:i.left-r.left-e.x,y:i.top-r.top-e.y}}function wt(t){return At(t.x)||At(t.y)}function xt(t){return{x:At(t.x)?t.x:window.pageXOffset,y:At(t.y)?t.y:window.pageYOffset}}function kt(t){return{x:At(t.x)?t.x:0,y:At(t.y)?t.y:0}}function At(t){return\"number\"===typeof t}function Ot(t,e){var n=\"object\"===typeof t;if(n&&\"string\"===typeof t.selector){var r=document.querySelector(t.selector);if(r){var i=t.offset&&\"object\"===typeof t.offset?t.offset:{};i=kt(i),e=bt(r,i)}else wt(t)&&(e=xt(t))}else n&&wt(t)&&(e=xt(t));e&&window.scrollTo(e.x,e.y)}var Ct=L&&function(){var t=window.navigator.userAgent;return(-1===t.indexOf(\"Android 2.\")&&-1===t.indexOf(\"Android 4.0\")||-1===t.indexOf(\"Mobile Safari\")||-1!==t.indexOf(\"Chrome\")||-1!==t.indexOf(\"Windows Phone\"))&&(window.history&&\"pushState\"in window.history)}(),Et=L&&window.performance&&window.performance.now?window.performance:Date,jt=St();function St(){return Et.now().toFixed(3)}function $t(){return jt}function Tt(t){jt=t}function Rt(t,e){_t();var n=window.history;try{e?n.replaceState({key:jt},\"\",t):(jt=St(),n.pushState({key:jt},\"\",t))}catch(n){window.location[e?\"replace\":\"assign\"](t)}}function Lt(t){Rt(t,!0)}function It(t,e,n){var r=function(i){i>=t.length?n():t[i]?e(t[i],function(){r(i+1)}):r(i+1)};r(0)}function Pt(t){return function(e,n,r){var o=!1,a=0,u=null;Mt(t,function(t,e,n,s){if(\"function\"===typeof t&&void 0===t.cid){o=!0,a++;var c,l=qt(function(e){zt(e)&&(e=e.default),t.resolved=\"function\"===typeof e?e:C.extend(e),n.components[s]=e,a--,a<=0&&r()}),f=qt(function(t){var e=\"Failed to resolve async component \"+s+\": \"+t;u||(u=i(t)?t:new Error(e),r(u))});try{c=t(l,f)}catch(t){f(t)}if(c)if(\"function\"===typeof c.then)c.then(l,f);else{var p=c.component;p&&\"function\"===typeof p.then&&p.then(l,f)}}}),o||r()}}function Mt(t,e){return Dt(t.map(function(t){return Object.keys(t.components).map(function(n){return e(t.components[n],t.instances[n],t,n)})}))}function Dt(t){return Array.prototype.concat.apply([],t)}var Ut=\"function\"===typeof Symbol&&\"symbol\"===typeof Symbol.toStringTag;function zt(t){return t.__esModule||Ut&&\"Module\"===t[Symbol.toStringTag]}function qt(t){var e=!1;return function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];if(!e)return e=!0,t.apply(this,n)}}var Nt=function(t,e){this.router=t,this.base=Ft(e),this.current=m,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Ft(t){if(!t)if(L){var e=document.querySelector(\"base\");t=e&&e.getAttribute(\"href\")||\"/\",t=t.replace(/^https?:\\/\\/[^\\/]+/,\"\")}else t=\"/\";return\"/\"!==t.charAt(0)&&(t=\"/\"+t),t.replace(/\\/$/,\"\")}function Ht(t,e){var n,r=Math.max(t.length,e.length);for(n=0;n<r;n++)if(t[n]!==e[n])break;return{updated:e.slice(0,n),activated:e.slice(n),deactivated:t.slice(n)}}function Wt(t,e,n,r){var i=Mt(t,function(t,r,i,o){var a=Bt(t,e);if(a)return Array.isArray(a)?a.map(function(t){return n(t,r,i,o)}):n(a,r,i,o)});return Dt(r?i.reverse():i)}function Bt(t,e){return\"function\"!==typeof t&&(t=C.extend(t)),t.options[e]}function Kt(t){return Wt(t,\"beforeRouteLeave\",Zt,!0)}function Vt(t){return Wt(t,\"beforeRouteUpdate\",Zt)}function Zt(t,e){if(e)return function(){return t.apply(e,arguments)}}function Xt(t,e,n){return Wt(t,\"beforeRouteEnter\",function(t,r,i,o){return Gt(t,i,o,e,n)})}function Gt(t,e,n,r,i){return function(o,a,u){return t(o,a,function(t){u(t),\"function\"===typeof t&&r.push(function(){Jt(t,e.instances,n,i)})})}}function Jt(t,e,n,r){e[n]?t(e[n]):r()&&setTimeout(function(){Jt(t,e,n,r)},16)}Nt.prototype.listen=function(t){this.cb=t},Nt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},Nt.prototype.onError=function(t){this.errorCbs.push(t)},Nt.prototype.transitionTo=function(t,e,n){var r=this,i=this.router.match(t,this.current);this.confirmTransition(i,function(){r.updateRoute(i),e&&e(i),r.ensureURL(),r.ready||(r.ready=!0,r.readyCbs.forEach(function(t){t(i)}))},function(t){n&&n(t),t&&!r.ready&&(r.ready=!0,r.readyErrorCbs.forEach(function(e){e(t)}))})},Nt.prototype.confirmTransition=function(t,e,n){var o=this,a=this.current,u=function(t){i(t)&&(o.errorCbs.length?o.errorCbs.forEach(function(e){e(t)}):(r(!1,\"uncaught error during route navigation:\"),console.error(t))),n&&n(t)};if(x(t,a)&&t.matched.length===a.matched.length)return this.ensureURL(),u();var s=Ht(this.current.matched,t.matched),c=s.updated,l=s.deactivated,f=s.activated,p=[].concat(Kt(l),this.router.beforeHooks,Vt(c),f.map(function(t){return t.beforeEnter}),Pt(f));this.pending=t;var h=function(e,n){if(o.pending!==t)return u();try{e(t,a,function(t){!1===t||i(t)?(o.ensureURL(!0),u(t)):\"string\"===typeof t||\"object\"===typeof t&&(\"string\"===typeof t.path||\"string\"===typeof t.name)?(u(),\"object\"===typeof t&&t.replace?o.replace(t):o.push(t)):n(t)})}catch(t){u(t)}};It(p,h,function(){var n=[],r=function(){return o.current===t},i=Xt(f,n,r),a=i.concat(o.router.resolveHooks);It(a,h,function(){if(o.pending!==t)return u();o.pending=null,e(t),o.router.app&&o.router.app.$nextTick(function(){n.forEach(function(t){t()})})})})},Nt.prototype.updateRoute=function(t){var e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(function(n){n&&n(t,e)})};var Yt=function(t){function e(e,n){var r=this;t.call(this,e,n);var i=e.options.scrollBehavior;i&&yt();var o=Qt(this.base);window.addEventListener(\"popstate\",function(t){var n=r.current,a=Qt(r.base);r.current===m&&a===o||r.transitionTo(a,function(t){i&&gt(e,t,n,!0)})})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.go=function(t){window.history.go(t)},e.prototype.push=function(t,e,n){var r=this,i=this,o=i.current;this.transitionTo(t,function(t){Rt(M(r.base+t.fullPath)),gt(r.router,t,o,!1),e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this,i=this,o=i.current;this.transitionTo(t,function(t){Lt(M(r.base+t.fullPath)),gt(r.router,t,o,!1),e&&e(t)},n)},e.prototype.ensureURL=function(t){if(Qt(this.base)!==this.current.fullPath){var e=M(this.base+this.current.fullPath);t?Rt(e):Lt(e)}},e.prototype.getCurrentLocation=function(){return Qt(this.base)},e}(Nt);function Qt(t){var e=window.location.pathname;return t&&0===e.indexOf(t)&&(e=e.slice(t.length)),(e||\"/\")+window.location.search+window.location.hash}var te=function(t){function e(e,n,r){t.call(this,e,n),r&&ee(this.base)||ne()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setupListeners=function(){var t=this,e=this.router,n=e.options.scrollBehavior,r=Ct&&n;r&&yt(),window.addEventListener(Ct?\"popstate\":\"hashchange\",function(){var e=t.current;ne()&&t.transitionTo(re(),function(n){r&&gt(t.router,n,e,!0),Ct||ae(n.fullPath)})})},e.prototype.push=function(t,e,n){var r=this,i=this,o=i.current;this.transitionTo(t,function(t){oe(t.fullPath),gt(r.router,t,o,!1),e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this,i=this,o=i.current;this.transitionTo(t,function(t){ae(t.fullPath),gt(r.router,t,o,!1),e&&e(t)},n)},e.prototype.go=function(t){window.history.go(t)},e.prototype.ensureURL=function(t){var e=this.current.fullPath;re()!==e&&(t?oe(e):ae(e))},e.prototype.getCurrentLocation=function(){return re()},e}(Nt);function ee(t){var e=Qt(t);if(!/^\\/#/.test(e))return window.location.replace(M(t+\"/#\"+e)),!0}function ne(){var t=re();return\"/\"===t.charAt(0)||(ae(\"/\"+t),!1)}function re(){var t=window.location.href,e=t.indexOf(\"#\");return-1===e?\"\":t.slice(e+1)}function ie(t){var e=window.location.href,n=e.indexOf(\"#\"),r=n>=0?e.slice(0,n):e;return r+\"#\"+t}function oe(t){Ct?Rt(ie(t)):window.location.hash=t}function ae(t){Ct?Lt(ie(t)):window.location.replace(ie(t))}var ue=function(t){function e(e,n){t.call(this,e,n),this.stack=[],this.index=-1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.push=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index+1).concat(t),r.index++,e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index).concat(t),e&&e(t)},n)},e.prototype.go=function(t){var e=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var r=this.stack[n];this.confirmTransition(r,function(){e.index=n,e.updateRoute(r)})}},e.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:\"/\"},e.prototype.ensureURL=function(){},e}(Nt),se=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=pt(t.routes||[],this);var e=t.mode||\"hash\";switch(this.fallback=\"history\"===e&&!Ct&&!1!==t.fallback,this.fallback&&(e=\"hash\"),L||(e=\"abstract\"),this.mode=e,e){case\"history\":this.history=new Yt(this,t.base);break;case\"hash\":this.history=new te(this,t.base,this.fallback);break;case\"abstract\":this.history=new ue(this,t.base);break;default:0}},ce={currentRoute:{configurable:!0}};function le(t,e){return t.push(e),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function fe(t,e,n){var r=\"hash\"===n?\"#\"+e:e;return t?M(t+\"/\"+r):r}se.prototype.match=function(t,e,n){return this.matcher.match(t,e,n)},ce.currentRoute.get=function(){return this.history&&this.history.current},se.prototype.init=function(t){var e=this;if(this.apps.push(t),!this.app){this.app=t;var n=this.history;if(n instanceof Yt)n.transitionTo(n.getCurrentLocation());else if(n instanceof te){var r=function(){n.setupListeners()};n.transitionTo(n.getCurrentLocation(),r,r)}n.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},se.prototype.beforeEach=function(t){return le(this.beforeHooks,t)},se.prototype.beforeResolve=function(t){return le(this.resolveHooks,t)},se.prototype.afterEach=function(t){return le(this.afterHooks,t)},se.prototype.onReady=function(t,e){this.history.onReady(t,e)},se.prototype.onError=function(t){this.history.onError(t)},se.prototype.push=function(t,e,n){this.history.push(t,e,n)},se.prototype.replace=function(t,e,n){this.history.replace(t,e,n)},se.prototype.go=function(t){this.history.go(t)},se.prototype.back=function(){this.go(-1)},se.prototype.forward=function(){this.go(1)},se.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},se.prototype.resolve=function(t,e,n){var r=lt(t,e||this.history.current,n,this),i=this.match(r,e),o=i.redirectedFrom||i.fullPath,a=this.history.base,u=fe(a,o,this.mode);return{location:r,route:i,href:u,normalizedTo:r,resolved:i}},se.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==m&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(se.prototype,ce),se.install=R,se.version=\"3.0.1\",L&&window.Vue&&window.Vue.use(se),e[\"a\"]=se},\"k5N+\":function(t,e,n){\"use strict\";function r(t){if(Array.isArray(t))return t}function i(t,e){var n=[],r=!0,i=!1,o=void 0;try{for(var a,u=t[Symbol.iterator]();!(r=(a=u.next()).done);r=!0)if(n.push(a.value),e&&n.length===e)break}catch(t){i=!0,o=t}finally{try{r||null==u[\"return\"]||u[\"return\"]()}finally{if(i)throw o}}return n}function o(){throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")}function a(t,e){return r(t)||i(t,e)||o()}n.d(e,\"a\",function(){return a})},kMlx:function(t,e,n){\"use strict\";var r=n(\"8zgK\");function i(t){if(t)return o(t)}function o(t){for(var e in i.prototype)t[e]=i.prototype[e];return t}t.exports=i,i.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,this},i.prototype.parse=function(t){return this._parser=t,this},i.prototype.responseType=function(t){return this._responseType=t,this},i.prototype.serialize=function(t){return this._serializer=t,this},i.prototype.timeout=function(t){if(!t||\"object\"!==typeof t)return this._timeout=t,this._responseTimeout=0,this;for(var e in t)switch(e){case\"deadline\":this._timeout=t.deadline;break;case\"response\":this._responseTimeout=t.response;break;default:console.warn(\"Unknown timeout option\",e)}return this},i.prototype.retry=function(t,e){return 0!==arguments.length&&!0!==t||(t=1),t<=0&&(t=0),this._maxRetries=t,this._retries=0,this._retryCallback=e,this};var a=[\"ECONNRESET\",\"ETIMEDOUT\",\"EADDRINFO\",\"ESOCKETTIMEDOUT\"];i.prototype._shouldRetry=function(t,e){if(!this._maxRetries||this._retries++>=this._maxRetries)return!1;if(this._retryCallback)try{var n=this._retryCallback(t,e);if(!0===n)return!0;if(!1===n)return!1}catch(t){console.error(t)}if(e&&e.status&&e.status>=500&&501!=e.status)return!0;if(t){if(t.code&&~a.indexOf(t.code))return!0;if(t.timeout&&\"ECONNABORTED\"==t.code)return!0;if(t.crossDomain)return!0}return!1},i.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this._end()},i.prototype.then=function(t,e){if(!this._fullfilledPromise){var n=this;this._endCalled&&console.warn(\"Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises\"),this._fullfilledPromise=new Promise(function(t,e){n.end(function(n,r){n?e(n):t(r)})})}return this._fullfilledPromise.then(t,e)},i.prototype[\"catch\"]=function(t){return this.then(void 0,t)},i.prototype.use=function(t){return t(this),this},i.prototype.ok=function(t){if(\"function\"!==typeof t)throw Error(\"Callback required\");return this._okCallback=t,this},i.prototype._isResponseOK=function(t){return!!t&&(this._okCallback?this._okCallback(t):t.status>=200&&t.status<300)},i.prototype.get=function(t){return this._header[t.toLowerCase()]},i.prototype.getHeader=i.prototype.get,i.prototype.set=function(t,e){if(r(t)){for(var n in t)this.set(n,t[n]);return this}return this._header[t.toLowerCase()]=e,this.header[t]=e,this},i.prototype.unset=function(t){return delete this._header[t.toLowerCase()],delete this.header[t],this},i.prototype.field=function(t,e){if(null===t||void 0===t)throw new Error(\".field(name, val) name can not be empty\");if(this._data&&console.error(\".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()\"),r(t)){for(var n in t)this.field(n,t[n]);return this}if(Array.isArray(e)){for(var i in e)this.field(t,e[i]);return this}if(null===e||void 0===e)throw new Error(\".field(name, val) val can not be empty\");return\"boolean\"===typeof e&&(e=\"\"+e),this._getFormData().append(t,e),this},i.prototype.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit(\"abort\"),this)},i.prototype._auth=function(t,e,n,r){switch(n.type){case\"basic\":this.set(\"Authorization\",\"Basic \"+r(t+\":\"+e));break;case\"auto\":this.username=t,this.password=e;break;case\"bearer\":this.set(\"Authorization\",\"Bearer \"+t);break}return this},i.prototype.withCredentials=function(t){return void 0==t&&(t=!0),this._withCredentials=t,this},i.prototype.redirects=function(t){return this._maxRedirects=t,this},i.prototype.maxResponseSize=function(t){if(\"number\"!==typeof t)throw TypeError(\"Invalid argument\");return this._maxResponseSize=t,this},i.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},i.prototype.send=function(t){var e=r(t),n=this._header[\"content-type\"];if(this._formData&&console.error(\".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()\"),e&&!this._data)Array.isArray(t)?this._data=[]:this._isHost(t)||(this._data={});else if(t&&this._data&&this._isHost(this._data))throw Error(\"Can't merge these send calls\");if(e&&r(this._data))for(var i in t)this._data[i]=t[i];else\"string\"==typeof t?(n||this.type(\"form\"),n=this._header[\"content-type\"],this._data=\"application/x-www-form-urlencoded\"==n?this._data?this._data+\"&\"+t:t:(this._data||\"\")+t):this._data=t;return!e||this._isHost(t)?this:(n||this.type(\"json\"),this)},i.prototype.sortQuery=function(t){return this._sort=\"undefined\"===typeof t||t,this},i.prototype._finalizeQueryString=function(){var t=this._query.join(\"&\");if(t&&(this.url+=(this.url.indexOf(\"?\")>=0?\"&\":\"?\")+t),this._query.length=0,this._sort){var e=this.url.indexOf(\"?\");if(e>=0){var n=this.url.substring(e+1).split(\"&\");\"function\"===typeof this._sort?n.sort(this._sort):n.sort(),this.url=this.url.substring(0,e)+\"?\"+n.join(\"&\")}}},i.prototype._appendQueryString=function(){console.trace(\"Unsupported\")},i.prototype._timeoutError=function(t,e,n){if(!this._aborted){var r=new Error(t+e+\"ms exceeded\");r.timeout=e,r.code=\"ECONNABORTED\",r.errno=n,this.timedout=!0,this.abort(),this.callback(r)}},i.prototype._setTimeouts=function(){var t=this;this._timeout&&!this._timer&&(this._timer=setTimeout(function(){t._timeoutError(\"Timeout of \",t._timeout,\"ETIME\")},this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout(function(){t._timeoutError(\"Response timeout of \",t._responseTimeout,\"ETIMEDOUT\")},this._responseTimeout))}},m0Pp:function(t,e,n){var r=n(\"2OiF\");t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,i){return t.call(e,n,r,i)}}return function(){return t.apply(e,arguments)}}},nGyu:function(t,e,n){var r=n(\"K0xU\")(\"unscopables\"),i=Array.prototype;void 0==i[r]&&n(\"Mukb\")(i,r,{}),t.exports=function(t){i[r][t]=!0}},nICZ:function(t,e){t.exports=function(t){try{return{e:!1,v:t()}}catch(t){return{e:!0,v:t}}}},nZbv:function(t,e){function n(){this._defaults=[]}[\"use\",\"on\",\"once\",\"set\",\"query\",\"type\",\"accept\",\"auth\",\"withCredentials\",\"sortQuery\",\"retry\",\"ok\",\"redirects\",\"timeout\",\"buffer\",\"serialize\",\"parse\",\"ca\",\"key\",\"pfx\",\"cert\"].forEach(function(t){n.prototype[t]=function(){return this._defaults.push({fn:t,arguments:arguments}),this}}),n.prototype._setDefaults=function(t){this._defaults.forEach(function(e){t[e.fn].apply(t,e.arguments)})},t.exports=n},ne8i:function(t,e,n){var r=n(\"RYi7\"),i=Math.min;t.exports=function(t){return t>0?i(r(t),9007199254740991):0}},nh4g:function(t,e,n){t.exports=!n(\"eeVq\")(function(){return 7!=Object.defineProperty({},\"a\",{get:function(){return 7}}).a})},oHnp:function(t,e,n){\"use strict\";e.type=function(t){return t.split(/ *; */).shift()},e.params=function(t){return t.split(/ *; */).reduce(function(t,e){var n=e.split(/ *= */),r=n.shift(),i=n.shift();return r&&i&&(t[r]=i),t},{})},e.parseLinks=function(t){return t.split(/ *, */).reduce(function(t,e){var n=e.split(/ *; */),r=n[0].slice(1,-1),i=n[1].split(/ *= */)[1].slice(1,-1);return t[i]=r,t},{})},e.cleanHeader=function(t,e){return delete t[\"content-type\"],delete t[\"content-length\"],delete t[\"transfer-encoding\"],delete t[\"host\"],e&&(delete t[\"authorization\"],delete t[\"cookie\"]),t}},ol8x:function(t,e,n){var r=n(\"dyZX\"),i=r.navigator;t.exports=i&&i.userAgent||\"\"},oyJW:function(t,e,n){\"use strict\";function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}n.d(e,\"a\",function(){return r})},pbhE:function(t,e,n){\"use strict\";var r=n(\"2OiF\");function i(t){var e,n;this.promise=new t(function(t,r){if(void 0!==e||void 0!==n)throw TypeError(\"Bad Promise constructor\");e=t,n=r}),this.resolve=r(e),this.reject=r(n)}t.exports.f=function(t){return new i(t)}},quPj:function(t,e,n){var r=n(\"0/R4\"),i=n(\"LZWt\"),o=n(\"K0xU\")(\"match\");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[o])?!!e:\"RegExp\"==i(t))}},rGqo:function(t,e,n){for(var r=n(\"yt8O\"),i=n(\"DVgA\"),o=n(\"KroJ\"),a=n(\"dyZX\"),u=n(\"Mukb\"),s=n(\"hPIQ\"),c=n(\"K0xU\"),l=c(\"iterator\"),f=c(\"toStringTag\"),p=s.Array,h={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},d=i(h),v=0;v<d.length;v++){var y,g=d[v],_=h[g],m=a[g],b=m&&m.prototype;if(b&&(b[l]||u(b,l,p),b[f]||u(b,f,g),s[g]=p,_))for(y in r)b[y]||o(b,y,r[y],!0)}},vKrd:function(t,e,n){var r=n(\"y3w9\"),i=n(\"0/R4\"),o=n(\"pbhE\");t.exports=function(t,e){if(r(t),i(e)&&e.constructor===t)return e;var n=o.f(t),a=n.resolve;return a(e),n.promise}},vhPU:function(t,e){t.exports=function(t){if(void 0==t)throw TypeError(\"Can't call method on  \"+t);return t}},w2a5:function(t,e,n){var r=n(\"aCFj\"),i=n(\"ne8i\"),o=n(\"d/Gc\");t.exports=function(t){return function(e,n,a){var u,s=r(e),c=i(s.length),l=o(a,c);if(t&&n!=n){while(c>l)if(u=s[l++],u!=u)return!0}else for(;c>l;l++)if((t||l in s)&&s[l]===n)return t||l||0;return!t&&-1}}},xpql:function(t,e,n){t.exports=!n(\"nh4g\")&&!n(\"eeVq\")(function(){return 7!=Object.defineProperty(n(\"Iw71\")(\"div\"),\"a\",{get:function(){return 7}}).a})},y3w9:function(t,e,n){var r=n(\"0/R4\");t.exports=function(t){if(!r(t))throw TypeError(t+\" is not an object!\");return t}},yLpj:function(t,e){var n;n=function(){return this}();try{n=n||Function(\"return this\")()||(0,eval)(\"this\")}catch(t){\"object\"===typeof window&&(n=window)}t.exports=n},yT7P:function(t,e,n){\"use strict\";n.d(e,\"a\",function(){return i});var r=n(\"oyJW\");function i(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);\"function\"===typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){Object(r[\"a\"])(t,e,n[e])})}return t}},ylqs:function(t,e){var n=0,r=Math.random();t.exports=function(t){return\"Symbol(\".concat(void 0===t?\"\":t,\")_\",(++n+r).toString(36))}},yt8O:function(t,e,n){\"use strict\";var r=n(\"nGyu\"),i=n(\"1TsA\"),o=n(\"hPIQ\"),a=n(\"aCFj\");t.exports=n(\"Afnz\")(Array,\"Array\",function(t,e){this._t=a(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,i(1)):i(0,\"keys\"==e?n:\"values\"==e?t[n]:[n,t[n]])},\"values\"),o.Arguments=o.Array,r(\"keys\"),r(\"values\"),r(\"entries\")},zRwo:function(t,e,n){var r=n(\"6FMO\");t.exports=function(t,e){return new(r(t))(e)}},zhAb:function(t,e,n){var r=n(\"aagx\"),i=n(\"aCFj\"),o=n(\"w2a5\")(!1),a=n(\"YTvA\")(\"IE_PROTO\");t.exports=function(t,e){var n,u=i(t),s=0,c=[];for(n in u)n!=a&&r(u,n)&&c.push(n);while(e.length>s)r(u,n=e[s++])&&(~o(c,n)||c.push(n));return c}}}]);\n//# sourceMappingURL=chunk-vendors.b9a11975.js.map"
  },
  {
    "path": "web/vue/dist/index.html",
    "content": "<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content=\"IE=edge\"><meta name=viewport content=\"width=device-width,initial-scale=1\"><link rel=icon href=favicon.ico><link rel=stylesheet href=vendor/furtive.min.css><title>Gekko</title><link as=script href=app.5e99ecf7.js rel=preload><link as=style href=app.730569ff.css rel=preload><link as=script href=chunk-vendors.b9a11975.js rel=preload><link href=app.730569ff.css rel=stylesheet></head><body><noscript><strong>We're sorry but gekko-vue-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=UIconfig.js></script><script src=vendor/reconnecting-websocket.min.js></script><script src=vendor/moment.js></script><script src=vendor/d3.js></script><script src=vendor/toml.js></script><script src=vendor/humanize-duration.js></script><script src=chunk-vendors.b9a11975.js></script><script src=app.5e99ecf7.js></script></body></html>"
  },
  {
    "path": "web/vue/dist/vendor/d3.js",
    "content": "// https://d3js.org Version 4.3.0. Copyright 2016 Mike Bostock.\n(function(t,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?n(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],n):n(t.d3=t.d3||{})})(this,function(t){\"use strict\";function n(t){return function(n,e){return Ms(t(n),e)}}function e(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Fs?i*=10:o>=Is?i*=5:o>=Ys&&(i*=2),n<t?-i:i}function r(t){return t.length}function i(){}function o(t,n){var e=new i;if(t instanceof i)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,o=-1,u=t.length;if(null==n)for(;++o<u;)e.set(o,t[o]);else for(;++o<u;)e.set(n(r=t[o],o,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function u(){return{}}function a(t,n,e){t[n]=e}function c(){return o()}function s(t,n,e){t.set(n,e)}function f(){}function l(t,n){var e=new f;if(t instanceof f)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function h(t){return+t}function p(t){return t*t}function d(t){return t*(2-t)}function v(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function _(t){return t*t*t}function y(t){return--t*t*t+1}function g(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function m(t){return 1-Math.cos(t*Tf)}function x(t){return Math.sin(t*Tf)}function b(t){return(1-Math.cos(Mf*t))/2}function w(t){return Math.pow(2,10*t-10)}function M(t){return 1-Math.pow(2,-10*t)}function T(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function N(t){return 1-Math.sqrt(1-t*t)}function k(t){return Math.sqrt(1- --t*t)}function S(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function A(t){return 1-E(1-t)}function E(t){return(t=+t)<Nf?Lf*t*t:t<Sf?Lf*(t-=kf)*t+Af:t<Cf?Lf*(t-=Ef)*t+zf:Lf*(t-=Pf)*t+qf}function C(t){return((t*=2)<=1?1-E(1-t):E(t-1)+1)/2}function z(t,n){return t[0]-n[0]||t[1]-n[1]}function P(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&Wf(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function q(){this._x0=this._y0=this._x1=this._y1=null,this._=[]}function L(){return new q}function R(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u;while((l=f<<1|s)===(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function U(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-(1/0),l=-(1/0);for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)R(this,u[e],a[e],t[e]);return this}function D(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this}function O(t){return t[0]}function F(t){return t[1]}function I(t,n,e){var r=new Y(null==n?O:n,null==e?F:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Y(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function B(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function j(t){if(!(t>=1))throw new Error;this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function H(t){if(!t._start)try{X(t)}catch(n){if(t._tasks[t._ended+t._active-1])W(t,n);else if(!t._data)throw n}}function X(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=V(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||_l)}}function V(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?W(t,e):(t._data[n]=r,t._waiting?H(t):$(t))))}}function W(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(t){}t._active=NaN,$(t)}function $(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Z(t){return new j(arguments.length?+t:1/0)}function G(t){return t.innerRadius}function J(t){return t.outerRadius}function Q(t){return t.startAngle}function K(t){return t.endAngle}function tt(t){return t&&t.padAngle}function nt(t){return t>=1?xl:t<=-1?-xl:Math.asin(t)}function et(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function rt(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/Math.sqrt(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*Math.sqrt(Math.max(0,b*b*x-w*w)),T=(w*m-g*M)/x,N=(-w*g-m*M)/x,k=(w*m+g*M)/x,S=(-w*g+m*M)/x,A=T-_,E=N-y,C=k-_,z=S-y;return A*A+E*E>C*C+z*z&&(T=k,N=S),{cx:T,cy:N,x01:-f,y01:-l,x11:T*(i/b-1),y11:N*(i/b-1)}}function it(t){this._context=t}function ot(t){return t[0]}function ut(t){return t[1]}function at(t){this._curve=t}function ct(t){function n(n){return new at(t(n))}return n._curve=t,n}function st(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(ct(t)):n()._curve},t}function ft(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function lt(t){this._context=t}function ht(t){this._context=t}function pt(t){this._context=t}function dt(t,n){this._basis=new lt(t),this._beta=n}function vt(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function _t(t,n){this._context=t,this._k=(1-n)/6}function yt(t,n){this._context=t,this._k=(1-n)/6}function gt(t,n){this._context=t,this._k=(1-n)/6}function mt(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>gl){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>gl){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function xt(t,n){this._context=t,this._alpha=n}function bt(t,n){this._context=t,this._alpha=n}function wt(t,n){this._context=t,this._alpha=n}function Mt(t){this._context=t}function Tt(t){return t<0?-1:1}function Nt(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(Tt(o)+Tt(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function kt(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function St(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function At(t){this._context=t}function Et(t){this._context=new Ct(t)}function Ct(t){this._context=t}function zt(t){return new At(t)}function Pt(t){return new Et(t)}function qt(t){this._context=t}function Lt(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function Rt(t,n){this._context=t,this._t=n}function Ut(t){return new Rt(t,0)}function Dt(t){return new Rt(t,1)}function Ot(t,n){return t[n]}function Ft(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function It(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Yt(){}function Bt(t){var n;return t=(t+\"\").trim().toLowerCase(),(n=kh.exec(t))?(n=parseInt(n[1],16),new Wt(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=Sh.exec(t))?jt(parseInt(n[1],16)):(n=Ah.exec(t))?new Wt(n[1],n[2],n[3],1):(n=Eh.exec(t))?new Wt(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ch.exec(t))?Ht(n[1],n[2],n[3],n[4]):(n=zh.exec(t))?Ht(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ph.exec(t))?$t(n[1],n[2]/100,n[3]/100,1):(n=qh.exec(t))?$t(n[1],n[2]/100,n[3]/100,n[4]):Lh.hasOwnProperty(t)?jt(Lh[t]):\"transparent\"===t?new Wt(NaN,NaN,NaN,0):null}function jt(t){return new Wt(t>>16&255,t>>8&255,255&t,1)}function Ht(t,n,e,r){return r<=0&&(t=n=e=NaN),new Wt(t,n,e,r)}function Xt(t){return t instanceof Yt||(t=Bt(t)),t?(t=t.rgb(),new Wt(t.r,t.g,t.b,t.opacity)):new Wt}function Vt(t,n,e,r){return 1===arguments.length?Xt(t):new Wt(t,n,e,null==r?1:r)}function Wt(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function $t(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Jt(t,n,e,r)}function Zt(t){if(t instanceof Jt)return new Jt(t.h,t.s,t.l,t.opacity);if(t instanceof Yt||(t=Bt(t)),!t)return new Jt;if(t instanceof Jt)return t;t=t.rgb();var n=t.r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Jt(u,a,c,t.opacity)}function Gt(t,n,e,r){return 1===arguments.length?Zt(t):new Jt(t,n,e,null==r?1:r)}function Jt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Qt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function Kt(t){if(t instanceof nn)return new nn(t.l,t.a,t.b,t.opacity);if(t instanceof sn){var n=t.h*Rh;return new nn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Wt||(t=Xt(t));var e=un(t.r),r=un(t.g),i=un(t.b),o=en((.4124564*e+.3575761*r+.1804375*i)/Oh),u=en((.2126729*e+.7151522*r+.072175*i)/Fh),a=en((.0193339*e+.119192*r+.9503041*i)/Ih);return new nn(116*u-16,500*(o-u),200*(u-a),t.opacity)}function tn(t,n,e,r){return 1===arguments.length?Kt(t):new nn(t,n,e,null==r?1:r)}function nn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function en(t){return t>Hh?Math.pow(t,1/3):t/jh+Yh}function rn(t){return t>Bh?t*t*t:jh*(t-Yh)}function on(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function un(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function an(t){if(t instanceof sn)return new sn(t.h,t.c,t.l,t.opacity);t instanceof nn||(t=Kt(t));var n=Math.atan2(t.b,t.a)*Uh;return new sn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function cn(t,n,e,r){return 1===arguments.length?an(t):new sn(t,n,e,null==r?1:r)}function sn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function fn(t){if(t instanceof hn)return new hn(t.h,t.s,t.l,t.opacity);t instanceof Wt||(t=Xt(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Qh*r+Gh*n-Jh*e)/(Qh+Gh-Jh),o=r-i,u=(Zh*(e-i)-Wh*o)/$h,a=Math.sqrt(u*u+o*o)/(Zh*i*(1-i)),c=a?Math.atan2(u,o)*Uh-120:NaN;return new hn(c<0?c+360:c,a,i,t.opacity)}function ln(t,n,e,r){return 1===arguments.length?fn(t):new hn(t,n,e,null==r?1:r)}function hn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pn(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function dn(t,n){return function(e){return t+e*n}}function vn(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function _n(t,n){var e=n-t;return e?dn(t,e>180||e<-180?e-360*Math.round(e/360):e):op(isNaN(t)?n:t)}function yn(t){return 1===(t=+t)?gn:function(n,e){return e-n?vn(n,e,t):op(isNaN(n)?e:n)}}function gn(t,n){var e=n-t;return e?dn(t,e):op(isNaN(t)?n:t)}function mn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Vt(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+\"\"}}}function xn(t){return function(){return t}}function bn(t){return function(n){return t(n)+\"\"}}function wn(t){return\"none\"===t?mp:(Kh||(Kh=document.createElement(\"DIV\"),tp=document.documentElement,np=document.defaultView),Kh.style.transform=t,t=np.getComputedStyle(tp.appendChild(Kh),null).getPropertyValue(\"transform\"),tp.removeChild(Kh),t=t.slice(7,-1).split(\",\"),xp(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))}function Mn(t){return null==t?mp:(ep||(ep=document.createElementNS(\"http://www.w3.org/2000/svg\",\"g\")),ep.setAttribute(\"transform\",t),(t=ep.transform.baseVal.consolidate())?(t=t.matrix,xp(t.a,t.b,t.c,t.d,t.e,t.f)):mp)}function Tn(t,n,e,r){function i(t){return t.length?t.pop()+\" \":\"\"}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push(\"translate(\",null,n,null,e);a.push({i:c-4,x:lp(t,i)},{i:c-2,x:lp(r,o)})}else(i||o)&&u.push(\"translate(\"+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+\"rotate(\",null,r)-2,x:lp(t,n)})):n&&e.push(i(e)+\"rotate(\"+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+\"skewX(\",null,r)-2,x:lp(t,n)}):n&&e.push(i(e)+\"skewX(\"+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+\"scale(\",null,\",\",null,\")\");u.push({i:a-4,x:lp(t,e)},{i:a-2,x:lp(n,r)})}else 1===e&&1===r||o.push(i(o)+\"scale(\"+e+\",\"+r+\")\")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join(\"\")}}}function Nn(t){return((t=Math.exp(t))+1/t)/2}function kn(t){return((t=Math.exp(t))-1/t)/2}function Sn(t){return((t=Math.exp(2*t))-1)/(t+1)}function An(t){return function(n,e){var r=t((n=Gt(n)).h,(e=Gt(e)).h),i=gn(n.s,e.s),o=gn(n.l,e.l),u=gn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+\"\"}}}function En(t,n){var e=gn((t=tn(t)).l,(n=tn(n)).l),r=gn(t.a,n.a),i=gn(t.b,n.b),o=gn(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+\"\"}}function Cn(t){return function(n,e){var r=t((n=cn(n)).h,(e=cn(e)).h),i=gn(n.c,e.c),o=gn(n.l,e.l),u=gn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+\"\"}}}function zn(t){return function n(e){function r(n,r){var i=t((n=ln(n)).h,(r=ln(r)).h),o=gn(n.s,r.s),u=gn(n.l,r.l),a=gn(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+\"\"}}return e=+e,r.gamma=n,r}(1)}function Pn(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+\"\")||t in r)throw new Error(\"illegal type: \"+t);r[t]=[]}return new qn(r)}function qn(t){this._=t}function Ln(t,n){return t.trim().split(/^|\\s+/).map(function(t){var e=\"\",r=t.indexOf(\".\");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);return{type:t,name:e}})}function Rn(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function Un(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Rp,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function Dn(t){return new Function(\"d\",\"return {\"+t.map(function(t,n){return JSON.stringify(t)+\": d[\"+n+\"]\"}).join(\",\")+\"}\")}function On(t,n){var e=Dn(t);return function(r,i){return n(e(r),i,t)}}function Fn(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function In(t){return function(n,e){t(null==n?e:null)}}function Yn(t){var n=t.responseType;return n&&\"text\"!==n?t.response:t.responseText}function Bn(t,n){return function(e){return t(e.responseText,n)}}function jn(){return sd||(hd(Hn),sd=ld.now()+fd)}function Hn(){sd=0}function Xn(){this._call=this._time=this._next=null}function Vn(t,n,e){var r=new Xn;return r.restart(t,n,e),r}function Wn(){jn(),++id;for(var t,n=Up;n;)(t=sd-n._time)>=0&&n._call.call(null,t),n=n._next;--id}function $n(){sd=(cd=ld.now())+fd,id=od=0;try{Wn()}finally{id=0,Gn(),sd=0}}function Zn(){var t=ld.now(),n=t-cd;n>ad&&(fd-=n,cd=t)}function Gn(){for(var t,n,e=Up,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Up=n);Dp=t,Jn(r)}function Jn(t){if(!id){od&&(od=clearTimeout(od));var n=t-sd;n>24?(t<1/0&&(od=setTimeout($n,n)),ud&&(ud=clearInterval(ud))):(ud||(ud=setInterval(Zn,ad)),id=1,hd($n))}}function Qn(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do u.push(new Date(+e));while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Qn(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return vd.setTime(+n),_d.setTime(+r),t(vd),t(_d),Math.floor(e(vd,_d))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t===0}:function(n){return i.count(0,n)%t===0}):i:null}),i}function Kn(t){return Qn(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*xd)/Md})}function te(t){return Qn(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/Md})}function ne(t){if(!(n=Av.exec(t)))throw new Error(\"invalid format: \"+t);var n,e=n[1]||\" \",r=n[2]||\">\",i=n[3]||\"-\",o=n[4]||\"\",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||\"\";\"n\"===f?(c=!0,f=\"g\"):Sv[f]||(f=\"\"),(u||\"0\"===e&&\"=\"===r)&&(u=!0,e=\"0\",r=\"=\"),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function ee(t){return t}function re(n){return Cv=Pv(n),t.format=Cv.format,t.formatPrefix=Cv.formatPrefix,Cv}function ie(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function oe(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function ue(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function ae(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Dv[r=t.charAt(++a)])?r=t.charAt(++a):i=\"e\"===r?\" \":\"0\",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join(\"\")}}function e(t,n){return function(e){var i=ue(1900),o=r(i,t,e+=\"\",0);if(o!=e.length)return null;if(\"p\"in i&&(i.H=i.H%12+12*i.p),\"W\"in i||\"U\"in i){\"w\"in i||(i.w=\"W\"in i?1:0);var u=\"Z\"in i?oe(ue(i.y)).getUTCDay():n(ue(i.y)).getDay();i.m=0,i.d=\"W\"in i?(i.w+6)%7+7*i.W-(u+5)%7:i.w+7*i.U-(u+6)%7}return\"Z\"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,oe(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(i=n.charCodeAt(u++),37===i){if(i=n.charAt(u++),o=B[i in Dv?n.charAt(u++):i],!o||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function i(t,n,e){var r=C.exec(n.slice(e));return r?(t.p=z[r[0].toLowerCase()],e+r[0].length):-1}function o(t,n,e){var r=L.exec(n.slice(e));return r?(t.w=R[r[0].toLowerCase()],e+r[0].length):-1}function u(t,n,e){var r=P.exec(n.slice(e));return r?(t.w=q[r[0].toLowerCase()],e+r[0].length):-1}function a(t,n,e){var r=O.exec(n.slice(e));return r?(t.m=F[r[0].toLowerCase()],e+r[0].length):-1}function c(t,n,e){var r=U.exec(n.slice(e));return r?(t.m=D[r[0].toLowerCase()],e+r[0].length):-1}function s(t,n,e){return r(t,w,n,e)}function f(t,n,e){return r(t,M,n,e)}function l(t,n,e){return r(t,T,n,e)}function h(t){return S[t.getDay()]}function p(t){return k[t.getDay()]}function d(t){return E[t.getMonth()]}function v(t){return A[t.getMonth()]}function _(t){return N[+(t.getHours()>=12)]}function y(t){return S[t.getUTCDay()]}function g(t){return k[t.getUTCDay()]}function m(t){return E[t.getUTCMonth()]}function x(t){return A[t.getUTCMonth()]}function b(t){return N[+(t.getUTCHours()>=12)]}var w=t.dateTime,M=t.date,T=t.time,N=t.periods,k=t.days,S=t.shortDays,A=t.months,E=t.shortMonths,C=fe(N),z=le(N),P=fe(k),q=le(k),L=fe(S),R=le(S),U=fe(A),D=le(A),O=fe(E),F=le(E),I={a:h,A:p,b:d,B:v,c:null,d:ke,e:ke,H:Se,I:Ae,j:Ee,L:Ce,m:ze,M:Pe,p:_,S:qe,U:Le,w:Re,W:Ue,x:null,X:null,y:De,Y:Oe,Z:Fe,\"%\":tr},Y={a:y,A:g,b:m,B:x,c:null,d:Ie,e:Ie,H:Ye,I:Be,j:je,L:He,m:Xe,M:Ve,p:b,S:We,U:$e,w:Ze,W:Ge,x:null,X:null,y:Je,Y:Qe,Z:Ke,\"%\":tr},B={a:o,A:u,b:a,B:c,c:s,d:me,e:me,H:be,I:be,j:xe,L:Te,m:ge,M:we,p:i,S:Me,U:pe,w:he,W:de,x:f,X:l,y:_e,Y:ve,Z:ye,\"%\":Ne};return I.x=n(M,I),I.X=n(T,I),I.c=n(w,I),Y.x=n(M,Y),Y.X=n(T,Y),Y.c=n(w,Y),{format:function(t){var e=n(t+=\"\",I);return e.toString=function(){return t},e},parse:function(t){var n=e(t+=\"\",ie);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+=\"\",Y);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,oe);return n.toString=function(){return t},n}}}function ce(t,n,e){var r=t<0?\"-\":\"\",i=(r?-t:t)+\"\",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function se(t){return t.replace(Iv,\"\\\\$&\")}function fe(t){return new RegExp(\"^(?:\"+t.map(se).join(\"|\")+\")\",\"i\")}function le(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function he(t,n,e){var r=Ov.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function pe(t,n,e){var r=Ov.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function de(t,n,e){var r=Ov.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function ve(t,n,e){var r=Ov.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function _e(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ye(t,n,e){var r=/^(Z)|([+-]\\d\\d)(?:\\:?(\\d\\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||\"00\")),e+r[0].length):-1}function ge(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function me(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function xe(t,n,e){var r=Ov.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function be(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function we(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Me(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function Te(t,n,e){var r=Ov.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Ne(t,n,e){var r=Fv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function ke(t,n){return ce(t.getDate(),n,2)}function Se(t,n){return ce(t.getHours(),n,2)}function Ae(t,n){return ce(t.getHours()%12||12,n,2)}function Ee(t,n){return ce(1+Cd.count($d(t),t),n,3)}function Ce(t,n){return ce(t.getMilliseconds(),n,3)}function ze(t,n){return ce(t.getMonth()+1,n,2)}function Pe(t,n){return ce(t.getMinutes(),n,2)}function qe(t,n){return ce(t.getSeconds(),n,2)}function Le(t,n){return ce(Pd.count($d(t),t),n,2)}function Re(t){return t.getDay()}function Ue(t,n){return ce(qd.count($d(t),t),n,2)}function De(t,n){return ce(t.getFullYear()%100,n,2)}function Oe(t,n){return ce(t.getFullYear()%1e4,n,4)}function Fe(t){var n=t.getTimezoneOffset();return(n>0?\"-\":(n*=-1,\"+\"))+ce(n/60|0,\"0\",2)+ce(n%60,\"0\",2)}function Ie(t,n){return ce(t.getUTCDate(),n,2)}function Ye(t,n){return ce(t.getUTCHours(),n,2)}function Be(t,n){return ce(t.getUTCHours()%12||12,n,2)}function je(t,n){return ce(1+tv.count(gv(t),t),n,3)}function He(t,n){return ce(t.getUTCMilliseconds(),n,3)}function Xe(t,n){return ce(t.getUTCMonth()+1,n,2)}function Ve(t,n){return ce(t.getUTCMinutes(),n,2)}function We(t,n){return ce(t.getUTCSeconds(),n,2)}function $e(t,n){return ce(ev.count(gv(t),t),n,2)}function Ze(t){return t.getUTCDay()}function Ge(t,n){return ce(rv.count(gv(t),t),n,2)}function Je(t,n){return ce(t.getUTCFullYear()%100,n,2)}function Qe(t,n){return ce(t.getUTCFullYear()%1e4,n,4)}function Ke(){return\"+0000\"}function tr(){return\"%\"}function nr(n){return qv=ae(n),t.timeFormat=qv.format,t.timeParse=qv.parse,t.utcFormat=qv.utcFormat,t.utcParse=qv.utcParse,qv}function er(t){return t.toISOString()}function rr(t){var n=new Date(t);return isNaN(n)?null:n}function ir(t){function n(n){var o=n+\"\",u=e.get(o);if(!u){if(i!==Wv)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=o(),r=[],i=Wv;return t=null==t?[]:Vv.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=o();for(var i,u,a=-1,c=t.length;++a<c;)e.has(u=(i=t[a])+\"\")||e.set(u,r.push(i));return n},n.range=function(e){return arguments.length?(t=Vv.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return ir().domain(r).range(t).unknown(i)},n}function or(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Os(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=ir().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return or().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function ur(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return ur(n())},t}function ar(){return ur(or().paddingInner(1))}function cr(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:$v(n)}function sr(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function fr(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function lr(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function hr(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=ks(t,n,1,i)-1;return u[e](o[e](n))}}function pr(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function dr(t,n){function e(){return i=Math.min(a.length,c.length)>2?hr:lr,o=u=null,r}function r(n){return(o||(o=i(a,c,f?sr(t):t,s)))(+n)}var i,o,u,a=Gv,c=Gv,s=_p,f=!1;return r.invert=function(t){return(u||(u=i(c,a,cr,f?fr(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=Xv.call(t,Zv),e()):a.slice()},r.range=function(t){return arguments.length?(c=Vv.call(t),e()):c.slice()},r.rangeRound=function(t){return c=Vv.call(t),s=yp,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function vr(t){var n=t.domain;return t.ticks=function(t){var e=n();return Bs(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return Jv(n(),t,e)},t.nice=function(r){var i=n(),o=i.length-1,u=null==r?10:r,a=i[0],c=i[o],s=e(a,c,u);return s&&(s=e(Math.floor(a/s)*s,Math.ceil(c/s)*s,u),i[0]=Math.floor(a/s)*s,i[o]=Math.ceil(c/s)*s,n(i)),t},t}function _r(){var t=dr(cr,lp);return t.copy=function(){return pr(t,_r())},vr(t)}function yr(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=Xv.call(e,Zv),t):n.slice()},t.copy=function(){return yr().domain(n)},vr(t)}function gr(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:$v(n)}function mr(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function xr(t){return isFinite(t)?+(\"1e\"+t):t<0?0:t}function br(t){return 10===t?xr:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function wr(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function Mr(t){return function(n){return-t(-n)}}function Tr(){function n(){return o=wr(i),u=br(i),r()[0]<0&&(o=Mr(o),u=Mr(u)),e}var e=dr(gr,mr).domain([1,10]),r=e.domain,i=10,o=wr(10),u=br(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(l=s*f,!(l<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(l=s*f,!(l<a)){if(l>c)break;v.push(l)}}else v=Bs(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?\".0e\":\",\"),\"function\"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):\"\"}},e.nice=function(){return r(Qv(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return pr(e,Tr().base(i))},e}function Nr(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function kr(){function t(t,n){return(n=Nr(n,e)-(t=Nr(t,e)))?function(r){return(Nr(r,e)-t)/n}:$v(n)}function n(t,n){return n=Nr(n,e)-(t=Nr(t,e)),function(r){return Nr(t+n*r,1/e)}}var e=1,r=dr(t,n),i=r.domain;return r.exponent=function(t){return arguments.length?(e=+t,i(i())):e},r.copy=function(){return pr(r,kr().exponent(e))},vr(r)}function Sr(){return kr().exponent(.5)}function Ar(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=Xs(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[ks(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)r=n[i],null==r||isNaN(r=+r)||e.push(r);return e.sort(Ms),t()},n.range=function(n){return arguments.length?(r=Vv.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return Ar().domain(e).range(r)},n}function Er(){function t(t){if(t<=t)return u[ks(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=Vv.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return Er().domain([e,r]).range(u)},vr(t)}function Cr(){function t(t){if(t<=t)return e[ks(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=Vv.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=Vv.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return Cr().domain(n).range(e)},t}function zr(t){return new Date(t);\n}function Pr(t){return t instanceof Date?+t:+new Date(+t)}function qr(t,n,r,i,o,u,a,c,s){function f(e){return(a(e)<e?v:u(e)<e?_:o(e)<e?y:i(e)<e?g:n(e)<e?r(e)<e?m:x:t(e)<e?b:w)(e)}function l(n,r,i,o){if(null==n&&(n=10),\"number\"==typeof n){var u=Math.abs(i-r)/n,a=Ts(function(t){return t[2]}).right(M,u);a===M.length?(o=e(r/o_,i/o_,n),n=t):a?(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a],o=a[1],n=a[0]):(o=e(r,i,n),n=c)}return null==o?n:n.every(o)}var h=dr(cr,lp),p=h.invert,d=h.domain,v=s(\".%L\"),_=s(\":%S\"),y=s(\"%I:%M\"),g=s(\"%I %p\"),m=s(\"%a %d\"),x=s(\"%b %d\"),b=s(\"%B\"),w=s(\"%Y\"),M=[[a,1,Kv],[a,5,5*Kv],[a,15,15*Kv],[a,30,30*Kv],[u,1,t_],[u,5,5*t_],[u,15,15*t_],[u,30,30*t_],[o,1,n_],[o,3,3*n_],[o,6,6*n_],[o,12,12*n_],[i,1,e_],[i,2,2*e_],[r,1,r_],[n,1,i_],[n,3,3*i_],[t,1,o_]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(Xv.call(t,Pr)):d().map(zr)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(Qv(e,t)):h},h.copy=function(){return pr(h,qr(t,n,r,i,o,u,a,c,s))},h}function Lr(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Rr(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Rr(t).domain([e,r]).clamp(i)},vr(n)}function Ur(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===w_&&n.documentElement.namespaceURI===w_?n.createElement(t):n.createElementNS(e,t)}}function Dr(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Or(){return new Fr}function Fr(){this._=\"@\"+(++k_).toString(36)}function Ir(t,n,e){return t=Yr(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Yr(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function Br(t){return t.trim().split(/^|\\s+/).map(function(t){var n=\"\",e=t.indexOf(\".\");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function jr(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function Hr(t,n,e){var r=z_.hasOwnProperty(t.type)?Ir:Yr;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function Xr(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Vr(){}function Wr(){return[]}function $r(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function Zr(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new $r(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function Gr(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=X_+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)s=X_+u.call(t,o[a],a,o),(c=f[s])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new $r(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function Jr(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function Qr(t){return function(){this.removeAttribute(t)}}function Kr(t){return function(){this.removeAttributeNS(t.space,t.local)}}function ti(t,n){return function(){this.setAttribute(t,n)}}function ni(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function ei(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function ri(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function ii(t){return function(){this.style.removeProperty(t)}}function oi(t,n,e){return function(){this.style.setProperty(t,n,e)}}function ui(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function ai(t){return function(){delete this[t]}}function ci(t,n){return function(){this[t]=n}}function si(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function fi(t){return t.trim().split(/^|\\s+/)}function li(t){return t.classList||new hi(t)}function hi(t){this._node=t,this._names=fi(t.getAttribute(\"class\")||\"\")}function pi(t,n){for(var e=li(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function di(t,n){for(var e=li(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function vi(t){return function(){pi(this,t)}}function _i(t){return function(){di(this,t)}}function yi(t,n){return function(){(n.apply(this,arguments)?pi:di)(this,t)}}function gi(){this.textContent=\"\"}function mi(t){return function(){this.textContent=t}}function xi(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?\"\":n}}function bi(){this.innerHTML=\"\"}function wi(t){return function(){this.innerHTML=t}}function Mi(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?\"\":n}}function Ti(){this.nextSibling&&this.parentNode.appendChild(this)}function Ni(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ki(){return null}function Si(){var t=this.parentNode;t&&t.removeChild(this)}function Ai(t,n,e){var r=iy(t),i=r.CustomEvent;i?i=new i(n,e):(i=r.document.createEvent(\"Event\"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function Ei(t,n){return function(){return Ai(this,t,n)}}function Ci(t,n){return function(){return Ai(this,t,n.apply(this,arguments))}}function zi(t,n){this._groups=t,this._parents=n}function Pi(){return new zi([[document.documentElement]],yy)}function qi(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Ty)throw new Error(\"too late\");return e}function Li(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ky)throw new Error(\"too late\");return e}function Ri(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error(\"too late\");return e}function Ui(t,n,e){function r(t){e.state=Ny,e.timer.restart(i,e.delay,e.time),e.delay<=t&&i(t-e.delay)}function i(r){var s,f,l,h;if(e.state!==Ny)return u();for(s in c)if(h=c[s],h.name===e.name){if(h.state===Sy)return pd(i);h.state===Ay?(h.state=Cy,h.timer.stop(),h.on.call(\"interrupt\",t,t.__data__,h.index,h.group),delete c[s]):+s<n&&(h.state=Cy,h.timer.stop(),delete c[s])}if(pd(function(){e.state===Sy&&(e.state=Ay,e.timer.restart(o,e.delay,e.time),o(r))}),e.state=ky,e.on.call(\"start\",t,t.__data__,e.index,e.group),e.state===ky){for(e.state=Sy,a=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(a[++f]=h);a.length=f+1}}function o(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=Ey,1),i=-1,o=a.length;++i<o;)a[i].call(null,r);e.state===Ey&&(e.on.call(\"end\",t,t.__data__,e.index,e.group),u())}function u(){e.state=Cy,e.timer.stop(),delete c[n];for(var r in c)return;delete t.__transition}var a,c=t.__transition;c[n]=e,e.timer=Vn(r,0,e.time)}function Di(t,n){var e,r;return function(){var i=Li(this,t),o=i.tween;if(o!==e){r=e=o;for(var u=0,a=r.length;u<a;++u)if(r[u].name===n){r=r.slice(),r.splice(u,1);break}}i.tween=r}}function Oi(t,n,e){var r,i;if(\"function\"!=typeof e)throw new Error;return function(){var o=Li(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Fi(t,n,e){var r=t._id;return t.each(function(){var t=Li(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Ri(t,r).value[n]}}function Ii(t){return function(){this.removeAttribute(t)}}function Yi(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Bi(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function ji(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function Hi(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttribute(t):(u=this.getAttribute(t),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Xi(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttributeNS(t.space,t.local):(u=this.getAttributeNS(t.space,t.local),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Vi(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Wi(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function $i(t,n){return function(){qi(this,t).delay=+n.apply(this,arguments)}}function Zi(t,n){return n=+n,function(){qi(this,t).delay=n}}function Gi(t,n){return function(){Li(this,t).duration=+n.apply(this,arguments)}}function Ji(t,n){return n=+n,function(){Li(this,t).duration=n}}function Qi(t,n){if(\"function\"!=typeof n)throw new Error;return function(){Li(this,t).ease=n}}function Ki(t){return(t+\"\").trim().split(/^|\\s+/).every(function(t){var n=t.indexOf(\".\");return n>=0&&(t=t.slice(0,n)),!t||\"start\"===t})}function to(t,n,e){var r,i,o=Ki(n)?qi:Li;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function no(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function eo(t,n){var e,r,i;return function(){var o=iy(this).getComputedStyle(this,null),u=o.getPropertyValue(t),a=(this.style.removeProperty(t),o.getPropertyValue(t));return u===a?null:u===e&&a===r?i:i=n(e=u,r=a)}}function ro(t){return function(){this.style.removeProperty(t)}}function io(t,n,e){var r,i;return function(){var o=iy(this).getComputedStyle(this,null).getPropertyValue(t);return o===e?null:o===r?i:i=n(r=o,e)}}function oo(t,n,e){var r,i,o;return function(){var u=iy(this).getComputedStyle(this,null),a=u.getPropertyValue(t),c=e(this);return null==c&&(this.style.removeProperty(t),c=u.getPropertyValue(t)),a===c?null:a===r&&c===i?o:o=n(r=a,i=c)}}function uo(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function ao(t){return function(){this.textContent=t}}function co(t){return function(){var n=t(this);this.textContent=null==n?\"\":n}}function so(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function fo(t){return Pi().transition(t)}function lo(){return++Ky}function ho(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return ng.time=jn(),ng;return e}function po(t,n,e){var r=t(e);return\"translate(\"+(isFinite(r)?r:n(e))+\",0)\"}function vo(t,n,e){var r=t(e);return\"translate(0,\"+(isFinite(r)?r:n(e))+\")\"}function _o(t){var n=t.bandwidth()/2;return t.round()&&(n=Math.round(n)),function(e){return t(e)+n}}function yo(){return!this.__axis}function go(t,n){function e(e){var s,f=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,l=null==o?n.tickFormat?n.tickFormat.apply(n,r):ug:o,h=Math.max(u,0)+c,p=t===ag||t===sg?po:vo,d=n.range(),v=d[0]+.5,_=d[d.length-1]+.5,y=(n.bandwidth?_o:ug)(n.copy()),g=e.selection?e.selection():e,m=g.selectAll(\".domain\").data([null]),x=g.selectAll(\".tick\").data(f,n).order(),b=x.exit(),w=x.enter().append(\"g\").attr(\"class\",\"tick\"),M=x.select(\"line\"),T=x.select(\"text\"),N=t===ag||t===fg?-1:1,k=t===fg||t===cg?(s=\"x\",\"y\"):(s=\"y\",\"x\");m=m.merge(m.enter().insert(\"path\",\".tick\").attr(\"class\",\"domain\").attr(\"stroke\",\"#000\")),x=x.merge(w),M=M.merge(w.append(\"line\").attr(\"stroke\",\"#000\").attr(s+\"2\",N*u).attr(k+\"1\",.5).attr(k+\"2\",.5)),T=T.merge(w.append(\"text\").attr(\"fill\",\"#000\").attr(s,N*h).attr(k,.5).attr(\"dy\",t===ag?\"0em\":t===sg?\"0.71em\":\"0.32em\")),e!==g&&(m=m.transition(e),x=x.transition(e),M=M.transition(e),T=T.transition(e),b=b.transition(e).attr(\"opacity\",lg).attr(\"transform\",function(t){return p(y,this.parentNode.__axis||y,t)}),w.attr(\"opacity\",lg).attr(\"transform\",function(t){return p(this.parentNode.__axis||y,y,t)})),b.remove(),m.attr(\"d\",t===fg||t==cg?\"M\"+N*a+\",\"+v+\"H0.5V\"+_+\"H\"+N*a:\"M\"+v+\",\"+N*a+\"V0.5H\"+_+\"V\"+N*a),x.attr(\"opacity\",1).attr(\"transform\",function(t){return p(y,y,t)}),M.attr(s+\"2\",N*u),T.attr(s,N*h).text(l),g.filter(yo).attr(\"fill\",\"none\").attr(\"font-size\",10).attr(\"font-family\",\"sans-serif\").attr(\"text-anchor\",t===cg?\"start\":t===fg?\"end\":\"middle\"),g.each(function(){this.__axis=y})}var r=[],i=null,o=null,u=6,a=6,c=3;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=og.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:og.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:og.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(u=a=+t,e):u},e.tickSizeInner=function(t){return arguments.length?(u=+t,e):u},e.tickSizeOuter=function(t){return arguments.length?(a=+t,e):a},e.tickPadding=function(t){return arguments.length?(c=+t,e):c},e}function mo(t){return go(ag,t)}function xo(t){return go(cg,t)}function bo(t){return go(sg,t)}function wo(t){return go(fg,t)}function Mo(t,n){return t.parent===n.parent?1:2}function To(t){return t.reduce(No,0)/t.length}function No(t,n){return t+n.x}function ko(t){return 1+t.reduce(So,0)}function So(t,n){return Math.max(t,n.y)}function Ao(t){for(var n;n=t.children;)t=n[0];return t}function Eo(t){for(var n;n=t.children;)t=n[n.length-1];return t}function Co(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function zo(t,n){var e,r,i,o,u,a=new Uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=qo);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new Uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Ro)}function Po(){return zo(this).eachBefore(Lo)}function qo(t){return t.children}function Lo(t){t.data=t.data.data}function Ro(t){var n=0;do t.height=n;while((t=t.parent)&&t.height<++n)}function Uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function Do(t){this._=t,this.next=null}function Oo(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r-n.r;return i*i+1e-6>e*e+r*r}function Fo(t,n){var e,r,i,o=null,u=t.head;switch(n.length){case 1:e=Io(n[0]);break;case 2:e=Yo(n[0],n[1]);break;case 3:e=Bo(n[0],n[1],n[2])}for(;u;)i=u._,r=u.next,e&&Oo(e,i)?o=u:(o?(t.tail=o,o.next=null):t.head=t.tail=null,n.push(i),e=Fo(t,n),n.pop(),t.head?(u.next=t.head,t.head=u):(u.next=null,t.head=t.tail=u),o=t.tail,o.next=r),u=r;return t.tail=o,e}function Io(t){return{x:t.x,y:t.y,r:t.r}}function Yo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function Bo(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=2*(r-u),p=2*(i-a),d=2*(c-o),v=r*r+i*i-o*o-u*u-a*a+c*c,_=2*(r-s),y=2*(i-f),g=2*(l-o),m=r*r+i*i-o*o-s*s-f*f+l*l,x=_*p-h*y,b=(p*m-y*v)/x-r,w=(y*d-p*g)/x,M=(_*v-h*m)/x-i,T=(h*g-_*d)/x,N=w*w+T*T-1,k=2*(b*w+M*T+o),S=b*b+M*M-o*o,A=(-k-Math.sqrt(k*k-4*N*S))/(2*N);return{x:b+w*A+r,y:M+T*A+i,r:A}}function jo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function Ho(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i>e*e+r*r}function Xo(t,n,e){var r=t.x-n,i=t.y-e;return r*r+i*i}function Vo(t){this._=t,this.next=null,this.previous=null}function Wo(t){if(!(i=t.length))return 0;var n,e,r,i;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;jo(e,n,r=t[2]);var o,u,a,c,s,f,l,h=n.r*n.r,p=e.r*e.r,d=r.r*r.r,v=h+p+d,_=h*n.x+p*e.x+d*r.x,y=h*n.y+p*e.y+d*r.y;n=new Vo(n),e=new Vo(e),r=new Vo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){if(jo(n._,e._,r=t[a]),r=new Vo(r),(s=n.previous)===(c=e.next)){if(Ho(c._,r._)){n=e,e=c,--a;continue t}}else{f=c._.r,l=s._.r;do if(f<=l){if(Ho(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}c=c.next,f+=c._.r}else{if(Ho(s._,r._)){n=s,n.next=e,e.previous=n,--a;continue t}s=s.previous,l+=s._.r}while(c!==s.next)}for(r.previous=n,r.next=e,n.next=e.previous=e=r,v+=d=r._.r*r._.r,_+=d*r._.x,y+=d*r._.y,h=Xo(n._,o=_/v,u=y/v);(r=r.next)!==e;)(d=Xo(r._,o,u))<h&&(n=r,h=d);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Tg(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function $o(t){return null==t?null:Zo(t)}function Zo(t){if(\"function\"!=typeof t)throw new Error;return t}function Go(){return 0}function Jo(t){return Math.sqrt(t.value)}function Qo(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Ko(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=Wo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function tu(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function nu(t){return t.id}function eu(t){return t.parentId}function ru(t,n){return t.parent===n.parent?1:2}function iu(t){var n=t.children;return n?n[0]:t.t}function ou(t){var n=t.children;return n?n[n.length-1]:t.t}function uu(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function au(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)n=i[o],n.z+=e,n.m+=e,e+=n.s+(r+=n.c)}function cu(t,n,e){return t.a.parent===n.parent?t.a:e}function su(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function fu(t){for(var n,e,r,i,o,u=new su(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new su(r[i],i)),e.parent=n;return(u.parent=new su(null,0)).children=[u],u}function lu(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y,g=[],m=n.children,x=0,b=m.length,w=n.value;x<b;){for(s=i-e,f=o-r,h=p=l=m[x].value,_=Math.max(f/s,s/f)/(w*t),y=l*l*_,v=Math.max(p/y,y/h),c=x+1;c<b;++c){if(l+=a=m[c].value,a<h&&(h=a),a>p&&(p=a),y=l*l*_,d=Math.max(p/y,y/h),d>v){l-=a;break}v=d}g.push(u={value:l,dice:s<f,children:m.slice(x,c)}),u.dice?Eg(u,e,r,i,w?r+=f*l/w:o):Ug(u,e,r,w?e+=s*l/w:i,o),w-=l,x=c}return g}function hu(t){return t.x+t.vx}function pu(t){return t.y+t.vy}function du(t,n){return n}function vu(t,n){var e=t.get(n);if(!e)throw new Error(\"missing: \"+n);return e}function _u(t){return t.x}function yu(t){return t.y}function gu(){t.event.stopImmediatePropagation()}function mu(t,n){var e=t.document.documentElement,r=gy(t).on(\"dragstart.drag\",null);n&&(r.on(\"click.drag\",tm,!0),setTimeout(function(){r.on(\"click.drag\",null)},0)),\"onselectstart\"in e?r.on(\"selectstart.drag\",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function xu(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function bu(){return!t.event.button}function wu(){return this.parentNode}function Mu(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Tu(t){return t[0]}function Nu(t){return t[1]}function ku(){this._=null}function Su(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Au(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Eu(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Cu(t){for(;t.L;)t=t.L;return t}function zu(t,n,e,r){var i=[null,null],o=sm.push(i)-1;return i.left=t,i.right=n,e&&qu(i,t,n,e),r&&qu(i,n,t,r),am[t.index].halfedges.push(o),am[n.index].halfedges.push(o),i}function Pu(t,n,e){var r=[n,e];return r.left=t,r}function qu(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Lu(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=a[0],l=a[1],h=0,p=1,d=f-c,v=l-s;if(o=n-c,d||!(o>0)){if(o/=d,d<0){if(o<h)return;o<p&&(p=o)}else if(d>0){if(o>p)return;o>h&&(h=o)}if(o=r-c,d||!(o<0)){if(o/=d,d<0){if(o>p)return;o>h&&(h=o)}else if(d>0){if(o<h)return;o<p&&(p=o)}if(o=e-s,v||!(o>0)){if(o/=v,v<0){if(o<h)return;o<p&&(p=o)}else if(v>0){if(o>p)return;o>h&&(h=o)}if(o=i-s,v||!(o<0)){if(o/=v,v<0){if(o>p)return;o>h&&(h=o)}else if(v>0){if(o<h)return;o<p&&(p=o)}return!(h>0||p<1)||(h>0&&(t[0]=[c+h*d,s+h*v]),p<1&&(t[1]=[c+p*d,s+p*v]),!0)}}}}}function Ru(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Uu(t,n,e,r){for(var i,o=sm.length;o--;)Ru(i=sm[o],t,n,e,r)&&Lu(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>hm||Math.abs(i[0][1]-i[1][1])>hm)||delete sm[o]}function Du(t){return am[t.index]={site:t,halfedges:[]}}function Ou(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Fu(t,n){return n[+(n.left!==t.site)]}function Iu(t,n){return n[+(n.left===t.site)]}function Yu(){for(var t,n,e,r,i=0,o=am.length;i<o;++i)if((t=am[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Ou(t,sm[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Bu(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=am.length,y=!0;for(i=0;i<_;++i)if(o=am[i]){for(u=o.site,c=o.halfedges,a=c.length;a--;)sm[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)p=Iu(o,sm[c[a]]),d=p[0],v=p[1],f=Fu(o,sm[c[++a%s]]),l=f[0],h=f[1],(Math.abs(d-l)>hm||Math.abs(v-h)>hm)&&(c.splice(a,0,sm.push(Pu(u,p,Math.abs(d-t)<hm&&r-v>hm?[t,Math.abs(l-t)<hm?h:r]:Math.abs(v-r)<hm&&e-d>hm?[Math.abs(h-r)<hm?l:e,r]:Math.abs(d-e)<hm&&v-n>hm?[e,Math.abs(l-e)<hm?h:n]:Math.abs(v-n)<hm&&d-t>hm?[Math.abs(h-n)<hm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=am[i])&&(u=o.site,g=u[0]-t,m=u[1]-n,x=g*g+m*m,x<b&&(b=x,y=o));if(y){var w=[t,n],M=[t,r],T=[e,r],N=[e,n];y.halfedges.push(sm.push(Pu(u=y.site,w,M))-1,sm.push(Pu(u,M,T))-1,sm.push(Pu(u,T,N))-1,sm.push(Pu(u,N,w))-1)}}for(i=0;i<_;++i)(o=am[i])&&(o.halfedges.length||delete am[i])}function ju(){Su(this),this.x=this.y=this.arc=this.site=this.cy=null}function Hu(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-pm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=fm.pop()||new ju;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=cm._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}cm.insert(g,y),g||(om=y)}}}}function Xu(t){var n=t.circle;n&&(n.P||(om=n.N),cm.remove(n),fm.push(n),Su(n),t.circle=null)}function Vu(){Su(this),this.edge=this.site=this.circle=null}function Wu(t){var n=lm.pop()||new Vu;return n.site=t,n}function $u(t){Xu(t),um.remove(t),lm.push(t),Su(t)}function Zu(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$u(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<hm&&Math.abs(r-c.circle.cy)<hm;)o=c.P,a.unshift(c),$u(c),c=o;a.unshift(c),Xu(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<hm&&Math.abs(r-s.circle.cy)<hm;)u=s.N,a.push(s),$u(s),s=u;a.push(s),Xu(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],qu(s.edge,c.site,s.site,i);c=a[0],s=a[l-1],s.edge=zu(c.site,s.site,null,i),Hu(c),Hu(s)}function Gu(t){for(var n,e,r,i,o=t[0],u=t[1],a=um._;a;)if(r=Ju(a,u)-o,r>hm)a=a.L;else{if(i=o-Qu(a,u),!(i>hm)){r>-hm?(n=a.P,e=a):i>-hm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}Du(t);var c=Wu(t);if(um.insert(n,c),n||e){if(n===e)return Xu(n),e=Wu(n.site),um.insert(c,e),c.edge=e.edge=zu(n.site,c.site),Hu(n),void Hu(e);if(!e)return void(c.edge=zu(n.site,c.site));Xu(n),Xu(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];qu(e.edge,s,d,x),c.edge=zu(s,t,null,x),e.edge=zu(t,d,null,x),Hu(n),Hu(e)}}function Ju(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-(1/0);e=u.site;var a=e[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Qu(t,n){var e=t.N;if(e)return Ju(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Ku(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function ta(t,n){return n[1]-t[1]||n[0]-t[0]}function na(t,n){var e,r,i,o=t.sort(ta).pop();for(sm=[],am=new Array(t.length),um=new ku,cm=new ku;;)if(i=om,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Gu(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Zu(i.arc)}if(Yu(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Uu(u,a,c,s),Bu(u,a,c,s)}this.edges=sm,this.cells=am,um=cm=sm=am=null}function ea(t,n,e){this.target=t,this.type=n,this.transform=e}function ra(t,n,e){this.k=t,this.x=n,this.y=e}function ia(t){return t.__zoom||_m}function oa(){t.event.stopImmediatePropagation()}function ua(){return!t.event.button}function aa(){var t,n,e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,t=e.width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function ca(){return this.__zoom||_m}function sa(){t.event.stopImmediatePropagation()}function fa(t){return{type:t}}function la(){return!t.event.button}function ha(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function pa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function da(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function va(t){var n=t.__brush;return n?n.dim.output(n.selection):null}function _a(){return ga(km)}function ya(){return ga(Sm)}function ga(n){function e(t){var e=t.property(\"__brush\",a).selectAll(\".overlay\").data([fa(\"overlay\")]);e.enter().append(\"rect\").attr(\"class\",\"overlay\").attr(\"pointer-events\",\"all\").attr(\"cursor\",Em.overlay).merge(e).each(function(){var t=pa(this).extent;gy(this).attr(\"x\",t[0][0]).attr(\"y\",t[0][1]).attr(\"width\",t[1][0]-t[0][0]).attr(\"height\",t[1][1]-t[0][1])}),t.selectAll(\".selection\").data([fa(\"selection\")]).enter().append(\"rect\").attr(\"class\",\"selection\").attr(\"cursor\",Em.selection).attr(\"fill\",\"#777\").attr(\"fill-opacity\",.3).attr(\"stroke\",\"#fff\").attr(\"shape-rendering\",\"crispEdges\");var i=t.selectAll(\".handle\").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append(\"rect\").attr(\"class\",function(t){return\"handle handle--\"+t.type}).attr(\"cursor\",function(t){return Em[t.type]}),t.each(r).attr(\"fill\",\"none\").attr(\"pointer-events\",\"all\").style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\").on(\"mousedown.brush touchstart.brush\",u)}function r(){var t=gy(this),n=pa(this).selection;n?(t.selectAll(\".selection\").style(\"display\",null).attr(\"x\",n[0][0]).attr(\"y\",n[0][1]).attr(\"width\",n[1][0]-n[0][0]).attr(\"height\",n[1][1]-n[0][1]),t.selectAll(\".handle\").style(\"display\",null).attr(\"x\",function(t){return\"e\"===t.type[t.type.length-1]?n[1][0]-h/2:n[0][0]-h/2}).attr(\"y\",function(t){return\"s\"===t.type[0]?n[1][1]-h/2:n[0][1]-h/2}).attr(\"width\",function(t){return\"n\"===t.type||\"s\"===t.type?n[1][0]-n[0][0]+h:h}).attr(\"height\",function(t){return\"e\"===t.type||\"w\"===t.type?n[1][1]-n[0][1]+h:h})):t.selectAll(\".selection,.handle\").style(\"display\",\"none\").attr(\"x\",null).attr(\"y\",null).attr(\"width\",null).attr(\"height\",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=U_(T);!U||w||M||(Math.abs(t[0]-O[0])>Math.abs(t[1]-O[1])?M=!0:w=!0),O=t,b=!0,bm(),o()}function o(){var t;switch(m=O[0]-D[0],x=O[1]-D[1],k){case Mm:case wm:S&&(m=Math.max(P-l,Math.min(L-v,m)),h=l+m,_=v+m),A&&(x=Math.max(q-p,Math.min(R-y,x)),d=p+x,g=y+x);break;case Tm:S<0?(m=Math.max(P-l,Math.min(L-l,m)),h=l+m,_=v):S>0&&(m=Math.max(P-v,Math.min(L-v,m)),h=l,_=v+m),A<0?(x=Math.max(q-p,Math.min(R-p,x)),d=p+x,g=y):A>0&&(x=Math.max(q-y,Math.min(R-y,x)),d=p,g=y+x);break;case Nm:S&&(h=Math.max(P,Math.min(L,l-m*S)),_=Math.max(P,Math.min(L,v+m*S))),A&&(d=Math.max(q,Math.min(R,p-x*A)),g=Math.max(q,Math.min(R,y+x*A)))}_<h&&(S*=-1,t=l,l=v,v=t,t=h,h=_,_=t,N in Cm&&Y.attr(\"cursor\",Em[N=Cm[N]])),g<d&&(A*=-1,t=p,p=y,y=t,t=d,d=g,g=t,N in zm&&Y.attr(\"cursor\",Em[N=zm[N]])),E.selection&&(z=E.selection),w&&(h=z[0][0],_=z[1][0]),M&&(d=z[0][1],g=z[1][1]),z[0][0]===h&&z[0][1]===d&&z[1][0]===_&&z[1][1]===g||(E.selection=[[h,d],[_,g]],r.call(T),F.brush())}function u(){if(sa(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),I.on(\"touchmove.brush touchend.brush touchcancel.brush\",null)}else mu(t.event.view,b),B.on(\"keydown.brush keyup.brush mousemove.brush mouseup.brush\",null);I.attr(\"pointer-events\",\"all\"),Y.attr(\"cursor\",Em.overlay),E.selection&&(z=E.selection),da(z)&&(E.selection=null,r.call(T)),F.end()}function a(){switch(t.event.keyCode){case 16:U=S&&A;break;case 18:k===Tm&&(S&&(v=_-m*S,l=h+m*S),A&&(y=g-x*A,p=d+x*A),k=Nm,o());break;case 32:k!==Tm&&k!==Nm||(S<0?v=_-m:S>0&&(l=h-m),A<0?y=g-x:A>0&&(p=d-x),k=Mm,Y.attr(\"cursor\",Em.selection),o());break;default:return}bm()}function s(){switch(t.event.keyCode){case 16:U&&(w=M=U=!1,o());break;case 18:k===Nm&&(S<0?v=_:S>0&&(l=h),A<0?y=g:A>0&&(p=d),k=Tm,o());break;case 32:k===Mm&&(t.event.altKey?(S&&(v=_-m*S,l=h+m*S),A&&(y=g-x*A,p=d+x*A),k=Nm):(S<0?v=_:S>0&&(l=h),A<0?y=g:A>0&&(p=d),k=Tm),Y.attr(\"cursor\",Em[N]),o());break;default:return}bm()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return bm()}else if(c)return;if(f.apply(this,arguments)){var l,h,p,d,v,_,y,g,m,x,b,w,M,T=this,N=t.event.target.__data__.type,k=\"selection\"===(t.event.metaKey?N=\"overlay\":N)?wm:t.event.altKey?Nm:Tm,S=n===Sm?null:Pm[N],A=n===km?null:qm[N],E=pa(T),C=E.extent,z=E.selection,P=C[0][0],q=C[0][1],L=C[1][0],R=C[1][1],U=S&&A&&t.event.shiftKey,D=U_(T),O=D,F=i(T,arguments).beforestart();\"overlay\"===N?E.selection=z=[[l=n===Sm?P:D[0],p=n===km?q:D[1]],[v=n===Sm?L:l,y=n===km?R:p]]:(l=z[0][0],p=z[0][1],v=z[1][0],y=z[1][1]),h=l,d=p,_=v,g=y;var I=gy(T).attr(\"pointer-events\",\"none\"),Y=I.selectAll(\".overlay\").attr(\"cursor\",Em[N]);if(t.event.touches)I.on(\"touchmove.brush\",e,!0).on(\"touchend.brush touchcancel.brush\",u,!0);else{var B=gy(t.event.view).on(\"keydown.brush\",a,!0).on(\"keyup.brush\",s,!0).on(\"mousemove.brush\",e,!0).on(\"mouseup.brush\",u,!0);nm(t.event.view)}sa(),Py(T),r.call(T),F.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=ha,f=la,l=Pn(e,\"start\",\"brush\",\"end\"),h=6;return e.move=function(t,e){t.selection?t.on(\"start.brush\",function(){i(this,arguments).beforestart().start()}).on(\"interrupt.brush end.brush\",function(){i(this,arguments).end()}).tween(\"brush\",function(){function t(t){u.selection=1===t&&da(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input(\"function\"==typeof e?e.apply(this,arguments):e,u.extent),f=_p(c,s);\nreturn c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input(\"function\"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();Py(t),u.selection=null==a||da(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1===++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit(\"start\")),this},brush:function(){return this.emit(\"brush\"),this},end:function(){return 0===--this.active&&(delete this.state.emitter,this.emit(\"end\")),this},emit:function(t){Xr(new xm(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s=\"function\"==typeof t?t:mm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f=\"function\"==typeof t?t:mm(!!t),e):f},e.handleSize=function(t){return arguments.length?(h=+t,e):h},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function ma(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function xa(t){return t.source}function ba(t){return t.target}function wa(t){return t.radius}function Ma(t){return t.startAngle}function Ta(t){return t.endAngle}function Na(){this.reset()}function ka(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Sa(t){return t>1?0:t<-1?kx:Math.acos(t)}function Aa(t){return t>1?Sx:t<-1?-Sx:Math.asin(t)}function Ea(t){return(t=Ix(t/2))*t}function Ca(){}function za(t,n){t&&Xx.hasOwnProperty(t.type)&&Xx[t.type](t,n)}function Pa(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function qa(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)Pa(t[e],n,1);n.polygonEnd()}function La(){Zx.point=Ua}function Ra(){Da(Vm,Wm)}function Ua(t,n){Zx.point=Da,Vm=t,Wm=n,t*=zx,n*=zx,$m=t,Zm=Rx(n=n/2+Ax),Gm=Ix(n)}function Da(t,n){t*=zx,n*=zx,n=n/2+Ax;var e=t-$m,r=e>=0?1:-1,i=r*e,o=Rx(n),u=Ix(n),a=Gm*u,c=Zm*o+a*Rx(i),s=a*r*Ix(i);Wx.add(Lx(s,c)),$m=t,Zm=o,Gm=u}function Oa(t){return[Lx(t[1],t[0]),Aa(t[2])]}function Fa(t){var n=t[0],e=t[1],r=Rx(e);return[r*Rx(n),r*Ix(n),Ix(e)]}function Ia(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Ya(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Ba(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function ja(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Ha(t){var n=Bx(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function Xa(t,n){ox.push(ux=[Jm=t,Km=t]),n<Qm&&(Qm=n),n>tx&&(tx=n)}function Va(t,n){var e=Fa([t*zx,n*zx]);if(ix){var r=Ya(ix,e),i=[r[1],-r[0],0],o=Ya(i,r);Ha(o),o=Oa(o);var u,a=t-nx,c=a>0?1:-1,s=o[0]*Cx*c,f=Px(a)>180;f^(c*nx<s&&s<c*t)?(u=o[1]*Cx,u>tx&&(tx=u)):(s=(s+360)%360-180,f^(c*nx<s&&s<c*t)?(u=-o[1]*Cx,u<Qm&&(Qm=u)):(n<Qm&&(Qm=n),n>tx&&(tx=n))),f?t<nx?Qa(Jm,t)>Qa(Jm,Km)&&(Km=t):Qa(t,Km)>Qa(Jm,Km)&&(Jm=t):Km>=Jm?(t<Jm&&(Jm=t),t>Km&&(Km=t)):t>nx?Qa(Jm,t)>Qa(Jm,Km)&&(Km=t):Qa(t,Km)>Qa(Jm,Km)&&(Jm=t)}else Xa(t,n);ix=e,nx=t}function Wa(){Qx.point=Va}function $a(){ux[0]=Jm,ux[1]=Km,Qx.point=Xa,ix=null}function Za(t,n){if(ix){var e=t-nx;Jx.add(Px(e)>180?e+(e>0?360:-360):e)}else ex=t,rx=n;Zx.point(t,n),Va(t,n)}function Ga(){Zx.lineStart()}function Ja(){Za(ex,rx),Zx.lineEnd(),Px(Jx)>Tx&&(Jm=-(Km=180)),ux[0]=Jm,ux[1]=Km,ix=null}function Qa(t,n){return(n-=t)<0?n+360:n}function Ka(t,n){return t[0]-n[0]}function tc(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function nc(t,n){t*=zx,n*=zx;var e=Rx(n);ec(e*Rx(t),e*Ix(t),Ix(n))}function ec(t,n,e){++ax,sx+=(t-sx)/ax,fx+=(n-fx)/ax,lx+=(e-lx)/ax}function rc(){tb.point=ic}function ic(t,n){t*=zx,n*=zx;var e=Rx(n);xx=e*Rx(t),bx=e*Ix(t),wx=Ix(n),tb.point=oc,ec(xx,bx,wx)}function oc(t,n){t*=zx,n*=zx;var e=Rx(n),r=e*Rx(t),i=e*Ix(t),o=Ix(n),u=Lx(Bx((u=bx*o-wx*i)*u+(u=wx*r-xx*o)*u+(u=xx*i-bx*r)*u),xx*r+bx*i+wx*o);cx+=u,hx+=u*(xx+(xx=r)),px+=u*(bx+(bx=i)),dx+=u*(wx+(wx=o)),ec(xx,bx,wx)}function uc(){tb.point=nc}function ac(){tb.point=sc}function cc(){fc(gx,mx),tb.point=nc}function sc(t,n){gx=t,mx=n,t*=zx,n*=zx,tb.point=fc;var e=Rx(n);xx=e*Rx(t),bx=e*Ix(t),wx=Ix(n),ec(xx,bx,wx)}function fc(t,n){t*=zx,n*=zx;var e=Rx(n),r=e*Rx(t),i=e*Ix(t),o=Ix(n),u=bx*o-wx*i,a=wx*r-xx*o,c=xx*i-bx*r,s=Bx(u*u+a*a+c*c),f=xx*r+bx*i+wx*o,l=s&&-Sa(f)/s,h=Lx(s,f);vx+=l*u,_x+=l*a,yx+=l*c,cx+=h,hx+=h*(xx+(xx=r)),px+=h*(bx+(bx=i)),dx+=h*(wx+(wx=o)),ec(xx,bx,wx)}function lc(t,n){return[t>kx?t-Ex:t<-kx?t+Ex:t,n]}function hc(t,n,e){return(t%=Ex)?n||e?rb(dc(t),vc(n,e)):dc(t):n||e?vc(n,e):lc}function pc(t){return function(n,e){return n+=t,[n>kx?n-Ex:n<-kx?n+Ex:n,e]}}function dc(t){var n=pc(t);return n.invert=pc(-t),n}function vc(t,n){function e(t,n){var e=Rx(n),a=Rx(t)*e,c=Ix(t)*e,s=Ix(n),f=s*r+a*i;return[Lx(c*o-f*u,a*r-s*i),Aa(f*o+c*u)]}var r=Rx(t),i=Ix(t),o=Rx(n),u=Ix(n);return e.invert=function(t,n){var e=Rx(n),a=Rx(t)*e,c=Ix(t)*e,s=Ix(n),f=s*o-c*u;return[Lx(c*o+s*u,a*r+f*i),Aa(f*r-a*i)]},e}function _c(t,n,e,r,i,o){if(e){var u=Rx(n),a=Ix(n),c=r*e;null==i?(i=n+r*Ex,o=n-c/2):(i=yc(u,i),o=yc(u,o),(r>0?i<o:i>o)&&(i+=r*Ex));for(var s,f=i;r>0?f>o:f<o;f-=c)s=Oa([u,-a*Rx(f),-a*Ix(f)]),t.point(s[0],s[1])}}function yc(t,n){n=Fa(n),n[0]-=t,Ha(n);var e=Sa(-n[1]);return((-n[2]<0?-e:e)+Ex-Tx)%Ex}function gc(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function mc(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function xc(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0){do s.point(0===f||3===f?t:e,f>1?r:n);while((f=(f+a+4)%4)!==l)}else s.point(o[0],o[1])}function u(r,i){return Px(r[0]-t)<Tx?i>0?0:3:Px(r[0]-e)<Tx?i>0?2:1:Px(r[1]-n)<Tx?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&k.point(t,n)}function s(){for(var n=0,e=0,i=_.length;e<i;++e)for(var o,u,a=_[e],c=1,s=a.length,f=a[0],l=f[0],h=f[1];c<s;++c)o=l,u=h,f=a[c],l=f[0],h=f[1],u<=r?h>r&&(l-o)*(r-u)>(h-u)*(t-o)&&++n:h<=r&&(l-o)*(r-u)<(h-u)*(t-o)&&--n;return n}function f(){k=S,v=[],_=[],N=!0}function l(){var t=s(),n=N&&t,e=(v=Js(v)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&xb(v,a,t,o,u),u.polygonEnd()),k=u,v=_=y=null}function h(){A.point=d,_&&_.push(y=[]),T=!0,M=!1,b=w=NaN}function p(){v&&(d(g,m),x&&M&&S.rejoin(),v.push(S.result())),A.point=c,M&&k.lineEnd()}function d(o,u){var a=i(o,u);if(_&&y.push([o,u]),T)g=o,m=u,x=a,T=!1,a&&(k.lineStart(),k.point(o,u));else if(a&&M)k.point(o,u);else{var c=[b=Math.max(wb,Math.min(bb,b)),w=Math.max(wb,Math.min(bb,w))],s=[o=Math.max(wb,Math.min(bb,o)),u=Math.max(wb,Math.min(bb,u))];gb(c,s,t,n,e,r)?(M||(k.lineStart(),k.point(c[0],c[1])),k.point(s[0],s[1]),a||k.lineEnd(),N=!1):a&&(k.lineStart(),k.point(o,u),N=!1)}b=o,w=u,M=a}var v,_,y,g,m,x,b,w,M,T,N,k=u,S=yb(),A={point:c,lineStart:h,lineEnd:p,polygonStart:f,polygonEnd:l};return A}}function bc(){Nb.point=Mc,Nb.lineEnd=wc}function wc(){Nb.point=Nb.lineEnd=Ca}function Mc(t,n){t*=zx,n*=zx,ib=t,ob=Ix(n),ub=Rx(n),Nb.point=Tc}function Tc(t,n){t*=zx,n*=zx;var e=Ix(n),r=Rx(n),i=Px(t-ib),o=Rx(i),u=Ix(i),a=r*u,c=ub*e-ob*r*o,s=ob*e+ub*r*o;Tb.add(Lx(Bx(a*a+c*c),s)),ib=t,ob=e,ub=r}function Nc(t,n,e){var r=Os(t,n-Tx,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function kc(t,n,e){var r=Os(t,n-Tx,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Sc(){function t(){return{type:\"MultiLineString\",coordinates:n()}}function n(){return Os(Ux(o/_)*_,i,_).map(h).concat(Os(Ux(s/y)*y,c,y).map(p)).concat(Os(Ux(r/d)*d,e,d).filter(function(t){return Px(t%_)>Tx}).map(f)).concat(Os(Ux(a/v)*v,u,v).filter(function(t){return Px(t%y)>Tx}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:\"LineString\",coordinates:t}})},t.outline=function(){return{type:\"Polygon\",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Nc(a,u,90),l=kc(r,e,g),h=Nc(s,c,90),p=kc(o,i,g),t):g},t.extentMajor([[-180,-90+Tx],[180,90-Tx]]).extentMinor([[-180,-80-Tx],[180,80+Tx]])}function Ac(){return Sc()()}function Ec(){Lb.point=Cc}function Cc(t,n){Lb.point=zc,ab=sb=t,cb=fb=n}function zc(t,n){qb.add(fb*t-sb*n),sb=t,fb=n}function Pc(){zc(ab,cb)}function qc(t,n){t<Rb&&(Rb=t),t>Db&&(Db=t),n<Ub&&(Ub=n),n>Ob&&(Ob=n)}function Lc(t,n){Ib+=t,Yb+=n,++Bb}function Rc(){Zb.point=Uc}function Uc(t,n){Zb.point=Dc,Lc(pb=t,db=n)}function Dc(t,n){var e=t-pb,r=n-db,i=Bx(e*e+r*r);jb+=i*(pb+t)/2,Hb+=i*(db+n)/2,Xb+=i,Lc(pb=t,db=n)}function Oc(){Zb.point=Lc}function Fc(){Zb.point=Yc}function Ic(){Bc(lb,hb)}function Yc(t,n){Zb.point=Bc,Lc(lb=pb=t,hb=db=n)}function Bc(t,n){var e=t-pb,r=n-db,i=Bx(e*e+r*r);jb+=i*(pb+t)/2,Hb+=i*(db+n)/2,Xb+=i,i=db*t-pb*n,Vb+=i*(pb+t),Wb+=i*(db+n),$b+=3*i,Lc(pb=t,db=n)}function jc(t){this._context=t}function Hc(){this._string=[]}function Xc(t){return\"m0,\"+t+\"a\"+t+\",\"+t+\" 0 1,1 0,\"+-2*t+\"a\"+t+\",\"+t+\" 0 1,1 0,\"+2*t+\"z\"}function Vc(t){return t.length>1}function Wc(t,n){return((t=t.x)[0]<0?t[1]-Sx-Tx:Sx-t[1])-((n=n.x)[0]<0?n[1]-Sx-Tx:Sx-n[1])}function $c(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?kx:-kx,c=Px(o-e);Px(c-kx)<Tx?(t.point(e,r=(r+u)/2>0?Sx:-Sx),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=kx&&(Px(e-i)<Tx&&(e-=i*Tx),Px(o-a)<Tx&&(o-=a*Tx),r=Zc(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}function Zc(t,n,e,r){var i,o,u=Ix(t-e);return Px(u)>Tx?qx((Ix(n)*(o=Rx(r))*Ix(e)-Ix(r)*(i=Rx(n))*Ix(t))/(i*o*u)):(n+r)/2}function Gc(t,n,e,r){var i;if(null==t)i=e*Sx,r.point(-kx,i),r.point(0,i),r.point(kx,i),r.point(kx,0),r.point(kx,-i),r.point(0,-i),r.point(-kx,-i),r.point(-kx,0),r.point(-kx,i);else if(Px(t[0]-n[0])>Tx){var o=t[0]<n[0]?kx:-kx;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}function Jc(t){return function(n){var e=new Qc;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Qc(){}function Kc(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Vx(e,t.stream(Fb));var u=Fb.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ts(t,n,e){return Kc(t,[[0,0],n],e)}function ns(t){return Jc({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function es(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=Bx(x*x+b*b+w*w),T=Aa(w/=M),N=Px(Px(w)-1)<Tx||Px(o-l)<Tx?(o+l)/2:Lx(b,x),k=t(N,T),S=k[0],A=k[1],E=S-r,C=A-i,z=g*E-y*C;(z*z/m>n||Px((y*E+g*C)/m-.5)>.3||u*h+a*p+c*d<iw)&&(e(r,i,o,u,a,c,S,A,N,x/=M,b/=M,w,v,_),_.point(S,A),e(S,A,N,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=Fa([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],rw,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,rw,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function rs(t){return is(function(){return t})()}function is(t){function n(t){return t=f(t[0]*zx,t[1]*zx),[t[0]*_+a,c-t[1]*_]}function e(t){return t=f.invert((t[0]-a)/_,(c-t[1])/_),t&&[t[0]*Cx,t[1]*Cx]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=rb(s=hc(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,N=tw,k=null,S=zb,A=.5,E=ow(r,A);return n.stream=function(t){return d&&v===t?d:d=uw(N(s,E(S(v=t))))},n.clipAngle=function(t){return arguments.length?(N=+t?nw(T=t*zx,6*zx):(T=null,tw),o()):T*Cx},n.clipExtent=function(t){return arguments.length?(S=null==t?(k=l=h=p=null,zb):xc(k=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==k?null:[[k,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*zx,x=t[1]%360*zx,i()):[m*Cx,x*Cx]},n.rotate=function(t){return arguments.length?(b=t[0]%360*zx,w=t[1]%360*zx,M=t.length>2?t[2]%360*zx:0,i()):[b*Cx,w*Cx,M*Cx]},n.precision=function(t){return arguments.length?(E=ow(r,A=t*t),o()):Bx(A)},n.fitExtent=function(t,e){return Kc(n,t,e)},n.fitSize=function(t,e){return ts(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function os(t){var n=0,e=kx/3,r=is(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*zx,e=t[1]*zx):[n*Cx,e*Cx]},i}function us(t){function n(t,n){return[t*e,Ix(n)/e]}var e=Rx(t);return n.invert=function(t,n){return[t/e,Aa(n*e)]},n}function as(t,n){function e(t,n){var e=Bx(o-2*i*Ix(n))/i;return[e*Ix(t*=i),u-e*Rx(t)]}var r=Ix(t),i=(r+Ix(n))/2;if(Px(i)<Tx)return us(t);var o=1+r*(2*i-r),u=Bx(o)/i;return e.invert=function(t,n){var e=u-n;return[Lx(t,Px(e))/i*Yx(e),Aa((o-(t*t+e*e)*i*i)/(2*i))]},e}function cs(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function ss(t){return function(n,e){var r=Rx(n),i=Rx(e),o=t(r*i);return[o*i*Ix(n),o*Ix(e)]}}function fs(t){return function(n,e){var r=Bx(n*n+e*e),i=t(r),o=Ix(i),u=Rx(i);return[Lx(n*o,r*u),Aa(r&&e*o/r)]}}function ls(t,n){return[t,Ox(jx((Sx+n)/2))]}function hs(t){var n,e=rs(t),r=e.scale,i=e.translate,o=e.clipExtent;return e.scale=function(t){return arguments.length?(r(t),n&&e.clipExtent(null),e):r()},e.translate=function(t){return arguments.length?(i(t),n&&e.clipExtent(null),e):i()},e.clipExtent=function(t){if(!arguments.length)return n?null:o();if(n=null==t){var u=kx*r(),a=i();t=[[a[0]-u,a[1]-u],[a[0]+u,a[1]+u]]}return o(t),e},e.clipExtent(null)}function ps(t){return jx((Sx+t)/2)}function ds(t,n){function e(t,n){o>0?n<-Sx+Tx&&(n=-Sx+Tx):n>Sx-Tx&&(n=Sx-Tx);var e=o/Fx(ps(n),i);return[e*Ix(i*t),o-e*Rx(i*t)]}var r=Rx(t),i=t===n?Ix(t):Ox(r/Rx(n))/Ox(ps(n)/ps(t)),o=r*Fx(ps(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=Yx(i)*Bx(t*t+e*e);return[Lx(t,Px(e))/i*Yx(e),2*qx(Fx(o/r,1/i))-Sx]},e):ls}function vs(t,n){return[t,n]}function _s(t,n){function e(t,n){var e=o-n,r=i*t;return[e*Ix(r),o-e*Rx(r)]}var r=Rx(t),i=t===n?Ix(t):(r-Rx(n))/(n-t),o=r/i+t;return Px(i)<Tx?vs:(e.invert=function(t,n){var e=o-n;return[Lx(t,Px(e))/i*Yx(e),o-Yx(i)*Bx(t*t+e*e)]},e)}function ys(t,n){var e=Rx(n),r=Rx(t)*e;return[e*Ix(t)/r,Ix(n)/r]}function gs(t,n,e){return 1===t&&0===n&&0===e?zb:Jc({point:function(r,i){this.stream.point(r*t+n,i*t+e)}})}function ms(t,n){return[Rx(n)*Ix(t),Ix(n)]}function xs(t,n){var e=Rx(n),r=1+Rx(t)*e;return[e*Ix(t)/r,Ix(n)/r]}function bs(t,n){return[Ox(jx((Sx+n)/2)),-t]}var ws=\"4.3.0\",Ms=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},Ts=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},Ns=Ts(Ms),ks=Ns.right,Ss=Ns.left,As=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Es=function(t){return null===t?NaN:+t},Cs=function(t,n){var e,r,i=t.length,o=0,u=0,a=-1,c=0;if(null==n)for(;++a<i;)isNaN(e=Es(t[a]))||(r=e-o,o+=r/++c,u+=r*(e-o));else for(;++a<i;)isNaN(e=Es(n(t[a],a,t)))||(r=e-o,o+=r/++c,u+=r*(e-o));if(c>1)return u/(c-1)},zs=function(t,n){var e=Cs(t,n);return e?Math.sqrt(e):e},Ps=function(t,n){var e,r,i,o=-1,u=t.length;if(null==n){for(;++o<u;)if(null!=(r=t[o])&&r>=r){e=i=r;break}for(;++o<u;)null!=(r=t[o])&&(e>r&&(e=r),i<r&&(i=r))}else{for(;++o<u;)if(null!=(r=n(t[o],o,t))&&r>=r){e=i=r;break}for(;++o<u;)null!=(r=n(t[o],o,t))&&(e>r&&(e=r),i<r&&(i=r))}return[e,i]},qs=Array.prototype,Ls=qs.slice,Rs=qs.map,Us=function(t){return function(){return t}},Ds=function(t){return t},Os=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Fs=Math.sqrt(50),Is=Math.sqrt(10),Ys=Math.sqrt(2),Bs=function(t,n,r){var i=e(t,n,r);return Os(Math.ceil(t/i)*i,Math.floor(n/i)*i+i/2,i)},js=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},Hs=function(){function t(t){var i,o,u=t.length,a=new Array(u);for(i=0;i<u;++i)a[i]=n(t[i],i,t);var c=e(a),s=c[0],f=c[1],l=r(a,s,f);Array.isArray(l)||(l=Bs(s,f,l));for(var h=l.length;l[0]<=s;)l.shift(),--h;for(;l[h-1]>=f;)l.pop(),--h;var p,d=new Array(h+1);for(i=0;i<=h;++i)p=d[i]=[],p.x0=i>0?l[i-1]:s,p.x1=i<h?l[i]:f;for(i=0;i<u;++i)o=a[i],s<=o&&o<=f&&d[ks(l,o,0,h)].push(t[i]);return d}var n=Ds,e=Ps,r=js;return t.value=function(e){return arguments.length?(n=\"function\"==typeof e?e:Us(e),t):n},t.domain=function(n){return arguments.length?(e=\"function\"==typeof n?n:Us([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r=\"function\"==typeof n?n:Us(Array.isArray(n)?Ls.call(n):n),t):r},t},Xs=function(t,n,e){if(null==e&&(e=Es),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t),a=+e(t[o+1],o+1,t);return u+(a-u)*(i-o)}},Vs=function(t,n,e){return t=Rs.call(t,Es).sort(Ms),Math.ceil((e-n)/(2*(Xs(t,.75)-Xs(t,.25))*Math.pow(t.length,-1/3)))},Ws=function(t,n,e){return Math.ceil((e-n)/(3.5*zs(t)*Math.pow(t.length,-1/3)))},$s=function(t,n){var e,r,i=-1,o=t.length;if(null==n){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&r>e&&(e=r)}else{for(;++i<o;)if(null!=(r=n(t[i],i,t))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n(t[i],i,t))&&r>e&&(e=r)}return e},Zs=function(t,n){var e,r=0,i=t.length,o=-1,u=i;if(null==n)for(;++o<i;)isNaN(e=Es(t[o]))?--u:r+=e;else for(;++o<i;)isNaN(e=Es(n(t[o],o,t)))?--u:r+=e;if(u)return r/u},Gs=function(t,n){var e,r=[],i=t.length,o=-1;if(null==n)for(;++o<i;)isNaN(e=Es(t[o]))||r.push(e);else for(;++o<i;)isNaN(e=Es(n(t[o],o,t)))||r.push(e);return Xs(r.sort(Ms),.5)},Js=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(r=t[i],n=r.length;--n>=0;)e[--u]=r[n];return e},Qs=function(t,n){var e,r,i=-1,o=t.length;if(null==n){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&e>r&&(e=r)}else{for(;++i<o;)if(null!=(r=n(t[i],i,t))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n(t[i],i,t))&&e>r&&(e=r)}return e},Ks=function(t){for(var n=0,e=t.length-1,r=t[0],i=new Array(e<0?0:e);n<e;)i[n]=[r,r=t[++n]];return i},tf=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},nf=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(n||(n=Ms);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},ef=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},rf=function(t,n){var e,r=0,i=t.length,o=-1;if(null==n)for(;++o<i;)(e=+t[o])&&(r+=e);else for(;++o<i;)(e=+n(t[o],o,t))&&(r+=e);return r},of=function(t){if(!(o=t.length))return[];for(var n=-1,e=Qs(t,r),i=new Array(e);++n<e;)for(var o,u=-1,a=i[n]=new Array(o);++u<o;)a[u]=t[u][n];return i},uf=function(){return of(arguments)},af=\"$\";i.prototype=o.prototype={constructor:i,has:function(t){return af+t in this},get:function(t){return this[af+t]},set:function(t,n){return this[af+t]=n,this},remove:function(t){var n=af+t;return n in this&&delete this[n]},clear:function(){for(var t in this)t[0]===af&&delete this[t]},keys:function(){var t=[];for(var n in this)n[0]===af&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)n[0]===af&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)n[0]===af&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)n[0]===af&&++t;return t},empty:function(){for(var t in this)if(t[0]===af)return!1;return!0},each:function(t){for(var n in this)n[0]===af&&t(this[n],n.slice(1),this)}};var cf=function(){function t(n,i,u,a){if(i>=f.length)return null!=r?r(n):null!=e?n.sort(e):n;for(var c,s,l,h=-1,p=n.length,d=f[i++],v=o(),_=u();++h<p;)(l=v.get(c=d(s=n[h])+\"\"))?l.push(s):v.set(c,[s]);return v.each(function(n,e){a(_,e,t(n,i,u,a))}),_}function n(t,e){if(++e>f.length)return t;var i,o=l[e-1];return null!=r&&e>=f.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=o?i.sort(function(t,n){return o(t.key,n.key)}):i}var e,r,i,f=[],l=[];return i={object:function(n){return t(n,0,u,a)},map:function(n){return t(n,0,c,s)},entries:function(e){return n(t(e,0,c,s),0)},key:function(t){return f.push(t),i},sortKeys:function(t){return l[f.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},sf=o.prototype;f.prototype=l.prototype={constructor:f,has:sf.has,add:function(t){return t+=\"\",this[af+t]=t,this},remove:sf.remove,clear:sf.clear,values:sf.keys,size:sf.size,empty:sf.empty,each:sf.each};var ff=function(t){var n=[];for(var e in t)n.push(e);return n},lf=function(t){var n=[];for(var e in t)n.push(t[e]);return n},hf=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},pf=function(t,n){return t=null==t?0:+t,n=null==n?1:+n,1===arguments.length?(n=t,t=0):n-=t,function(){return Math.random()*n+t}},df=function(t,n){var e,r;return t=null==t?0:+t,n=null==n?1:+n,function(){var i;if(null!=e)i=e,e=null;else do e=2*Math.random()-1,i=2*Math.random()-1,r=e*e+i*i;while(!r||r>1);return t+n*i*Math.sqrt(-2*Math.log(r)/r)}},vf=function(){var t=df.apply(this,arguments);return function(){return Math.exp(t())}},_f=function(t){return function(){for(var n=0,e=0;e<t;++e)n+=Math.random();return n}},yf=function(t){var n=_f(t);return function(){return n()/t}},gf=function(t){return function(){return-Math.log(1-Math.random())/t}},mf=3,xf=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(mf),bf=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(mf),wf=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(mf),Mf=Math.PI,Tf=Mf/2,Nf=4/11,kf=6/11,Sf=8/11,Af=.75,Ef=9/11,Cf=10/11,zf=.9375,Pf=21/22,qf=63/64,Lf=1/Nf/Nf,Rf=1.70158,Uf=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(Rf),Df=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(Rf),Of=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Rf),Ff=2*Math.PI,If=1,Yf=.3,Bf=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),jf=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),Hf=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),Xf=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},Vf=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},Wf=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},$f=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(z),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=P(r),u=P(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},Zf=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)o=t[l],e=o[0],r=o[1],r>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},Gf=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,o=t[r],u=o[0],a=o[1],n-=u,e-=a,c+=Math.sqrt(n*n+e*e);return c},Jf=Math.PI,Qf=2*Jf,Kf=1e-6,tl=Qf-Kf;q.prototype=L.prototype={constructor:q,moveTo:function(t,n){this._.push(\"M\",this._x0=this._x1=+t,\",\",this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._.push(\"Z\"))},lineTo:function(t,n){this._.push(\"L\",this._x1=+t,\",\",this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._.push(\"Q\",+t,\",\",+n,\",\",this._x1=+e,\",\",this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._.push(\"C\",+t,\",\",+n,\",\",+e,\",\",+r,\",\",this._x1=+i,\",\",this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error(\"negative radius: \"+i);if(null===this._x1)this._.push(\"M\",this._x1=t,\",\",this._y1=n);else if(l>Kf)if(Math.abs(f*a-c*s)>Kf&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Jf-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>Kf&&this._.push(\"L\",t+m*s,\",\",n+m*f),this._.push(\"A\",i,\",\",i,\",0,0,\",+(f*h>s*p),\",\",this._x1=t+x*a,\",\",this._y1=n+x*c)}else this._.push(\"L\",this._x1=t,\",\",this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,e=+e;var u=e*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error(\"negative radius: \"+e);null===this._x1?this._.push(\"M\",c,\",\",s):(Math.abs(this._x1-c)>Kf||Math.abs(this._y1-s)>Kf)&&this._.push(\"L\",c,\",\",s),e&&(l>tl?this._.push(\"A\",e,\",\",e,\",0,1,\",f,\",\",t-u,\",\",n-a,\"A\",e,\",\",e,\",0,1,\",f,\",\",this._x1=c,\",\",this._y1=s):(l<0&&(l=l%Qf+Qf),this._.push(\"A\",e,\",\",e,\",0,\",+(l>=Jf),\",\",f,\",\",this._x1=t+e*Math.cos(i),\",\",this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._.push(\"M\",this._x0=this._x1=+t,\",\",this._y0=this._y1=+n,\"h\",+e,\"v\",+r,\"h\",-e,\"Z\")},toString:function(){return this._.join(\"\")}};var nl=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return R(this.cover(n,e),n,e,t)},el=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do u=new Array(4),u[a]=s,s=u;while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do u=new Array(4),u[a]=s,s=u;while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do u=new Array(4),u[a]=s,s=u;while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do u=new Array(4),u[a]=s,s=u;while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},rl=function(){var t=[];return this.visit(function(n){if(!n.length)do t.push(n.data);while(n=n.next)}),t},il=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},ol=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},ul=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ol(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ol(v[3],_,y,u,a),new ol(v[2],i,y,_,a),new ol(v[1],_,o,u,y),new ol(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},al=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},cl=function(){return this._root},sl=function(){var t=0;return this.visit(function(n){if(!n.length)do++t;while(n=n.next)}),t},fl=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ol(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ol(e,s,f,o,u)),(e=c[2])&&a.push(new ol(e,r,f,s,u)),(e=c[1])&&a.push(new ol(e,s,i,o,f)),(e=c[0])&&a.push(new ol(e,r,i,s,f))}return this},ll=function(t){var n,e=[],r=[];for(this._root&&e.push(new ol(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ol(o,u,a,f,l)),(o=i[1])&&e.push(new ol(o,f,a,c,l)),(o=i[2])&&e.push(new ol(o,u,l,f,s)),(o=i[3])&&e.push(new ol(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},hl=function(t){return arguments.length?(this._x=t,this):this._x},pl=function(t){return arguments.length?(this._y=t,this):this._y},dl=I.prototype=Y.prototype;dl.copy=function(){var t,n,e=new Y(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=B(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=B(n));return e},dl.add=nl,dl.addAll=U,dl.cover=el,dl.data=rl,dl.extent=il,dl.find=ul,dl.remove=al,dl.removeAll=D,dl.root=cl,dl.size=sl,dl.visit=fl,dl.visitAfter=ll,dl.x=hl,dl.y=pl;var vl=[].slice,_l={};j.prototype=Z.prototype={constructor:j,defer:function(t){if(\"function\"!=typeof t||this._call)throw new Error;if(null!=this._error)return this;var n=vl.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),H(this),this},abort:function(){return null==this._error&&W(this,new Error(\"abort\")),this},await:function(t){if(\"function\"!=typeof t||this._call)throw new Error;return this._call=function(n,e){t.apply(null,[n].concat(e))},$(this),this},awaitAll:function(t){if(\"function\"!=typeof t||this._call)throw new Error;return this._call=t,$(this),this}};var yl=function(t){\nreturn function(){return t}},gl=1e-12,ml=Math.PI,xl=ml/2,bl=2*ml,wl=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-xl,p=u.apply(this,arguments)-xl,d=Math.abs(p-h),v=p>h;if(c||(c=t=L()),l<f&&(s=l,l=f,f=s),l>gl)if(d>bl-gl)c.moveTo(l*Math.cos(h),l*Math.sin(h)),c.arc(0,0,l,h,p,!v),f>gl&&(c.moveTo(f*Math.cos(p),f*Math.sin(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,N=T>gl&&(i?+i.apply(this,arguments):Math.sqrt(f*f+l*l)),k=Math.min(Math.abs(l-f)/2,+r.apply(this,arguments)),S=k,A=k;if(N>gl){var E=nt(N/f*Math.sin(T)),C=nt(N/l*Math.sin(T));(w-=2*E)>gl?(E*=v?1:-1,x+=E,b-=E):(w=0,x=b=(h+p)/2),(M-=2*C)>gl?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*Math.cos(g),P=l*Math.sin(g),q=f*Math.cos(b),R=f*Math.sin(b);if(k>gl){var U=l*Math.cos(m),D=l*Math.sin(m),O=f*Math.cos(x),F=f*Math.sin(x);if(d<ml){var I=w>gl?et(z,P,O,F,U,D,q,R):[q,R],Y=z-I[0],B=P-I[1],j=U-I[0],H=D-I[1],X=1/Math.sin(Math.acos((Y*j+B*H)/(Math.sqrt(Y*Y+B*B)*Math.sqrt(j*j+H*H)))/2),V=Math.sqrt(I[0]*I[0]+I[1]*I[1]);S=Math.min(k,(f-V)/(X-1)),A=Math.min(k,(l-V)/(X+1))}}M>gl?A>gl?(_=rt(O,F,z,P,l,A,v),y=rt(U,D,q,R,l,A,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),A<k?c.arc(_.cx,_.cy,A,Math.atan2(_.y01,_.x01),Math.atan2(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,A,Math.atan2(_.y01,_.x01),Math.atan2(_.y11,_.x11),!v),c.arc(0,0,l,Math.atan2(_.cy+_.y11,_.cx+_.x11),Math.atan2(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,A,Math.atan2(y.y11,y.x11),Math.atan2(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>gl&&w>gl?S>gl?(_=rt(q,R,U,D,f,-S,v),y=rt(z,P,O,F,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<k?c.arc(_.cx,_.cy,S,Math.atan2(_.y01,_.x01),Math.atan2(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,Math.atan2(_.y01,_.x01),Math.atan2(_.y11,_.x11),!v),c.arc(0,0,f,Math.atan2(_.cy+_.y11,_.cx+_.x11),Math.atan2(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,Math.atan2(y.y11,y.x11),Math.atan2(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(q,R)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+\"\"||null}var n=G,e=J,r=yl(0),i=null,o=Q,u=K,a=tt,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-ml/2;return[Math.cos(r)*t,Math.sin(r)*t]},t.innerRadius=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.outerRadius=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r=\"function\"==typeof n?n:yl(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:\"function\"==typeof n?n:yl(+n),t):i},t.startAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:yl(+n),t):o},t.endAngle=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(+n),t):u},t.padAngle=function(n){return arguments.length?(a=\"function\"==typeof n?n:yl(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t};it.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Ml=function(t){return new it(t)},Tl=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=L())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+\"\"||null}var n=ot,e=ut,r=yl(!0),i=null,o=Ml,u=null;return t.x=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.y=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.defined=function(n){return arguments.length?(r=\"function\"==typeof n?n:yl(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},Nl=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=L())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+\"\"||null}function n(){return Tl().defined(u).curve(c).context(a)}var e=ot,r=null,i=yl(0),o=ut,u=yl(!0),a=null,c=Ml,s=null;return t.x=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:\"function\"==typeof n?n:yl(+n),t):r},t.y=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:\"function\"==typeof n?n:yl(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},kl=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Sl=function(t){return t},Al=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(bl,Math.max(-bl,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],l=v[c],f=_+(l>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=Sl,e=kl,r=null,i=yl(0),o=yl(bl),u=yl(0);return t.value=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.endAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:yl(+n),t):o},t.padAngle=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(+n),t):u},t},El=ct(Ml);at.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var Cl=function(){return st(Tl().curve(El))},zl=function(){var t=Nl().curve(El),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return st(e())},delete t.lineX0,t.lineEndAngle=function(){return st(r())},delete t.lineX1,t.lineInnerRadius=function(){return st(i())},delete t.lineY0,t.lineOuterRadius=function(){return st(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(ct(t)):n()._curve},t},Pl={draw:function(t,n){var e=Math.sqrt(n/ml);t.moveTo(e,0),t.arc(0,0,e,0,bl)}},ql={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Ll=Math.sqrt(1/3),Rl=2*Ll,Ul={draw:function(t,n){var e=Math.sqrt(n/Rl),r=e*Ll;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Dl=.8908130915292852,Ol=Math.sin(ml/10)/Math.sin(7*ml/10),Fl=Math.sin(bl/10)*Ol,Il=-Math.cos(bl/10)*Ol,Yl={draw:function(t,n){var e=Math.sqrt(n*Dl),r=Fl*e,i=Il*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=bl*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},Bl={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},jl=Math.sqrt(3),Hl={draw:function(t,n){var e=-Math.sqrt(n/(3*jl));t.moveTo(0,2*e),t.lineTo(-jl*e,-e),t.lineTo(jl*e,-e),t.closePath()}},Xl=-.5,Vl=Math.sqrt(3)/2,Wl=1/Math.sqrt(12),$l=3*(Wl/2+1),Zl={draw:function(t,n){var e=Math.sqrt(n/$l),r=e/2,i=e*Wl,o=r,u=e*Wl+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Xl*r-Vl*i,Vl*r+Xl*i),t.lineTo(Xl*o-Vl*u,Vl*o+Xl*u),t.lineTo(Xl*a-Vl*c,Vl*a+Xl*c),t.lineTo(Xl*r+Vl*i,Xl*i-Vl*r),t.lineTo(Xl*o+Vl*u,Xl*u-Vl*o),t.lineTo(Xl*a+Vl*c,Xl*c-Vl*a),t.closePath()}},Gl=[Pl,ql,Ul,Bl,Yl,Hl,Zl],Jl=function(){function t(){var t;if(r||(r=t=L()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+\"\"||null}var n=yl(Pl),e=yl(64),r=null;return t.type=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(e),t):n},t.size=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},Ql=function(){};lt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:ft(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var Kl=function(t){return new lt(t)};ht.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var th=function(t){return new ht(t)};pt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var nh=function(t){return new pt(t)};dt.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var eh=function t(n){function e(t){return 1===n?new lt(t):new dt(t,n)}return e.beta=function(n){return t(+n)},e}(.85);_t.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:vt(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var rh=function t(n){function e(t){return new _t(t,n)}return e.tension=function(n){return t(+n)},e}(0);yt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ih=function t(n){function e(t){return new yt(t,n)}return e.tension=function(n){return t(+n)},e}(0);gt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var oh=function t(n){function e(t){return new gt(t,n)}return e.tension=function(n){return t(+n)},e}(0);xt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var uh=function t(n){function e(t){return n?new xt(t,n):new _t(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);bt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ah=function t(n){function e(t){return n?new bt(t,n):new yt(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);wt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ch=function t(n){function e(t){return n?new wt(t,n):new gt(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);Mt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};var sh=function(t){return new Mt(t)};At.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:St(this,this._t0,kt(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,St(this,kt(this,e=Nt(this,t,n)),e);break;default:St(this,this._t0,e=Nt(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Et.prototype=Object.create(At.prototype)).point=function(t,n){At.prototype.point.call(this,n,t)},Ct.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},qt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=Lt(t),i=Lt(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var fh=function(t){return new qt(t)};Rt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var lh=function(t){return new Rt(t,.5)},hh=Array.prototype.slice,ph=function(t,n){if((r=t.length)>1)for(var e,r,i=1,o=t[n[0]],u=o.length;i<r;++i){e=o,o=t[n[i]];for(var a=0;a<u;++a)o[a][1]+=o[a][0]=isNaN(e[a][1])?e[a][0]:e[a][1]}},dh=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},vh=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=yl([]),e=dh,r=ph,i=Ot;return t.keys=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(hh.call(e)),t):n},t.value=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?dh:\"function\"==typeof n?n:yl(hh.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?ph:n,t):r},t},_h=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}ph(t,n)}},yh=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}ph(t,n)}},gh=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=f[u-1][1]||0,p=(l-h)/2,d=0;d<a;++d){var v=t[n[d]],_=v[u][1]||0,y=v[u-1][1]||0;p+=_-y}c+=l,s+=p*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,ph(t,n)}},mh=function(t){var n=t.map(Ft);return dh(t).sort(function(t,e){return n[t]-n[e]})},xh=function(t){return mh(t).reverse()},bh=function(t){var n,e,r=t.length,i=t.map(Ft),o=dh(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},wh=function(t){return dh(t).reverse()},Mh=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},Th=.7,Nh=1/Th,kh=/^#([0-9a-f]{3})$/,Sh=/^#([0-9a-f]{6})$/,Ah=/^rgb\\(\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*\\)$/,Eh=/^rgb\\(\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*\\)$/,Ch=/^rgba\\(\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,zh=/^rgba\\(\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,Ph=/^hsl\\(\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*\\)$/,qh=/^hsla\\(\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,Lh={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Mh(Yt,Bt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+\"\"}}),Mh(Wt,Vt,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new Wt(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new Wt(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return t=isNaN(t)?1:Math.max(0,Math.min(1,t)),(1===t?\"rgb(\":\"rgba(\")+Math.max(0,Math.min(255,Math.round(this.r)||0))+\", \"+Math.max(0,Math.min(255,Math.round(this.g)||0))+\", \"+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?\")\":\", \"+t+\")\")}})),Mh(Jt,Gt,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new Jt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new Jt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Wt(Qt(t>=240?t-240:t+120,i,r),Qt(t,i,r),Qt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Rh=Math.PI/180,Uh=180/Math.PI,Dh=18,Oh=.95047,Fh=1,Ih=1.08883,Yh=4/29,Bh=6/29,jh=3*Bh*Bh,Hh=Bh*Bh*Bh;Mh(nn,tn,It(Yt,{brighter:function(t){return new nn(this.l+Dh*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new nn(this.l-Dh*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Fh*rn(t),n=Oh*rn(n),e=Ih*rn(e),new Wt(on(3.2404542*n-1.5371385*t-.4985314*e),on(-.969266*n+1.8760108*t+.041556*e),on(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),Mh(sn,cn,It(Yt,{brighter:function(t){return new sn(this.h,this.c,this.l+Dh*(null==t?1:t),this.opacity)},darker:function(t){return new sn(this.h,this.c,this.l-Dh*(null==t?1:t),this.opacity)},rgb:function(){return Kt(this).rgb()}}));var Xh=-.14861,Vh=1.78277,Wh=-.29227,$h=-.90649,Zh=1.97294,Gh=Zh*$h,Jh=Zh*Vh,Qh=Vh*Wh-$h*Xh;Mh(hn,ln,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new hn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new hn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Rh,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Wt(255*(n+e*(Xh*r+Vh*i)),255*(n+e*(Wh*r+$h*i)),255*(n+e*(Zh*r)),this.opacity)}}));var Kh,tp,np,ep,rp=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return pn((e-r/n)*n,u,i,o,a)}},ip=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return pn((e-r/n)*n,i,o,u,a)}},op=function(t){return function(){return t}},up=function t(n){function e(t,n){var e=r((t=Vt(t)).r,(n=Vt(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=r(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+\"\"}}var r=yn(n);return e.gamma=t,e}(1),ap=mn(rp),cp=mn(ip),sp=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=_p(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},fp=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},lp=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},hp=function(t,n){var e,r={},i={};null!==t&&\"object\"==typeof t||(t={}),null!==n&&\"object\"==typeof n||(n={});for(e in n)e in t?r[e]=_p(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},pp=/[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,dp=new RegExp(pp.source,\"g\"),vp=function(t,n){var e,r,i,o=pp.lastIndex=dp.lastIndex=0,u=-1,a=[],c=[];for(t+=\"\",n+=\"\";(e=pp.exec(t))&&(r=dp.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:lp(e,r)})),o=dp.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?bn(c[0].x):xn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join(\"\")})},_p=function(t,n){var e,r=typeof n;return null==n||\"boolean\"===r?op(n):(\"number\"===r?lp:\"string\"===r?(e=Bt(n))?(n=e,up):vp:n instanceof Bt?up:n instanceof Date?fp:Array.isArray(n)?sp:isNaN(n)?hp:lp)(t,n)},yp=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},gp=180/Math.PI,mp={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},xp=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*gp,skewX:Math.atan(c)*gp,scaleX:u,scaleY:a}},bp=Tn(wn,\"px, \",\"px)\",\"deg)\"),wp=Tn(Mn,\", \",\")\",\")\"),Mp=Math.SQRT2,Tp=2,Np=4,kp=1e-12,Sp=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<kp)r=Math.log(s/u)/Mp,e=function(t){return[i+t*f,o+t*l,u*Math.exp(Mp*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+Np*h)/(2*u*Tp*p),v=(s*s-u*u-Np*h)/(2*s*Tp*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/Mp,e=function(t){var n=t*r,e=Nn(_),a=u/(Tp*p)*(e*Sn(Mp*n+_)-kn(_));return[i+a*f,o+a*l,u*e/Nn(Mp*n+_)]}}return e.duration=1e3*r,e},Ap=An(_n),Ep=An(gn),Cp=Cn(_n),zp=Cn(gn),Pp=zn(_n),qp=zn(gn),Lp=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));\nreturn e},Rp={value:function(){}};qn.prototype=Pn.prototype={constructor:qn,on:function(t,n){var e,r=this._,i=Ln(t+\"\",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&\"function\"!=typeof n)throw new Error(\"invalid callback: \"+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=Un(r[e],t.name,n);else if(null==n)for(e in r)r[e]=Un(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=Rn(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new qn(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(r=this._[t],o=0,e=r.length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Up,Dp,Op=function(t){function n(t,n){var r,i,o=e(t,function(t,e){return r?r(t,e-1):(i=t,void(r=n?On(t,n):Dn(t)))});return o.columns=i,o}function e(t,n){function e(){if(f>=s)return u;if(i)return i=!1,o;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,n=t.charCodeAt(r+1),13===n?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/\"\"/g,'\"')}for(;f<s;){var a=1;if(n=t.charCodeAt(f++),10===n)i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++a);else if(n!==c)continue;return t.slice(e,f-a)}return t.slice(e)}for(var r,i,o={},u={},a=[],s=t.length,f=0,l=0;(r=e())!==u;){for(var h=[];r!==o&&r!==u;)h.push(r),r=e();n&&null==(h=n(h,l++))||a.push(h)}return a}function r(n,e){return null==e&&(e=Fn(n)),[e.map(u).join(t)].concat(n.map(function(n){return e.map(function(t){return u(n[t])}).join(t)})).join(\"\\n\")}function i(t){return t.map(o).join(\"\\n\")}function o(n){return n.map(u).join(t)}function u(t){return null==t?\"\":a.test(t+=\"\")?'\"'+t.replace(/\\\"/g,'\"\"')+'\"':t}var a=new RegExp('[\"'+t+\"\\n]\"),c=t.charCodeAt(0);return{parse:n,parseRows:e,format:r,formatRows:i}},Fp=Op(\",\"),Ip=Fp.parse,Yp=Fp.parseRows,Bp=Fp.format,jp=Fp.formatRows,Hp=Op(\"\\t\"),Xp=Hp.parse,Vp=Hp.parseRows,Wp=Hp.format,$p=Hp.formatRows,Zp=function(t,n){function e(t){var n,e=f.status;if(!e&&Yn(f)||e>=200&&e<300||304===e){if(u)try{n=u.call(r,f)}catch(t){return void c.call(\"error\",r,t)}else n=f;c.call(\"load\",r,n)}else c.call(\"error\",r,t)}var r,i,u,a,c=Pn(\"beforesend\",\"progress\",\"load\",\"error\"),s=o(),f=new XMLHttpRequest,l=null,h=null,p=0;if(\"undefined\"==typeof XDomainRequest||\"withCredentials\"in f||!/^(http(s)?:)?\\/\\//.test(t)||(f=new XDomainRequest),\"onload\"in f?f.onload=f.onerror=f.ontimeout=e:f.onreadystatechange=function(t){f.readyState>3&&e(t)},f.onprogress=function(t){c.call(\"progress\",r,t)},r={header:function(t,n){return t=(t+\"\").toLowerCase(),arguments.length<2?s.get(t):(null==n?s.remove(t):s.set(t,n+\"\"),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+\"\",r):i},responseType:function(t){return arguments.length?(a=t,r):a},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?l:(l=null==t?null:t+\"\",r)},password:function(t){return arguments.length<1?h:(h=null==t?null:t+\"\",r)},response:function(t){return u=t,r},get:function(t,n){return r.send(\"GET\",t,n)},post:function(t,n){return r.send(\"POST\",t,n)},send:function(n,e,o){return f.open(n,t,!0,l,h),null==i||s.has(\"accept\")||s.set(\"accept\",i+\",*/*\"),f.setRequestHeader&&s.each(function(t,n){f.setRequestHeader(n,t)}),null!=i&&f.overrideMimeType&&f.overrideMimeType(i),null!=a&&(f.responseType=a),p>0&&(f.timeout=p),null==o&&\"function\"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=In(o)),null!=o&&r.on(\"error\",o).on(\"load\",function(t){o(null,t)}),c.call(\"beforesend\",r,f),f.send(null==e?null:e),r},abort:function(){return f.abort(),r},on:function(){var t=c.on.apply(c,arguments);return t===c?r:t}},null!=n){if(\"function\"!=typeof n)throw new Error(\"invalid callback: \"+n);return r.get(n)}return r},Gp=function(t,n){return function(e,r){var i=Zp(e).mimeType(t).response(n);if(null!=r){if(\"function\"!=typeof r)throw new Error(\"invalid callback: \"+r);return i.get(r)}return i}},Jp=Gp(\"text/html\",function(t){return document.createRange().createContextualFragment(t.responseText)}),Qp=Gp(\"application/json\",function(t){return JSON.parse(t.responseText)}),Kp=Gp(\"text/plain\",function(t){return t.responseText}),td=Gp(\"application/xml\",function(t){var n=t.responseXML;if(!n)throw new Error(\"parse error\");return n}),nd=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=Zp(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Bn(n,r=t)):r},o.row(r),i?o.get(i):o}},ed=nd(\"text/csv\",Ip),rd=nd(\"text/tab-separated-values\",Xp),id=0,od=0,ud=0,ad=1e3,cd=0,sd=0,fd=0,ld=\"object\"==typeof performance&&performance.now?performance:Date,hd=\"function\"==typeof requestAnimationFrame?requestAnimationFrame:function(t){setTimeout(t,17)};Xn.prototype=Vn.prototype={constructor:Xn,restart:function(t,n,e){if(\"function\"!=typeof t)throw new TypeError(\"callback is not a function\");e=(null==e?jn():+e)+(null==n?0:+n),this._next||Dp===this||(Dp?Dp._next=this:Up=this,Dp=this),this._call=t,this._time=e,Jn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Jn())}};var pd=function(t,n,e){var r=new Xn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},dd=function(t,n,e){var r=new Xn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?jn():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},vd=new Date,_d=new Date,yd=Qn(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});yd.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Qn(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):yd:null};var gd=yd.range,md=1e3,xd=6e4,bd=36e5,wd=864e5,Md=6048e5,Td=Qn(function(t){t.setTime(Math.floor(t/md)*md)},function(t,n){t.setTime(+t+n*md)},function(t,n){return(n-t)/md},function(t){return t.getUTCSeconds()}),Nd=Td.range,kd=Qn(function(t){t.setTime(Math.floor(t/xd)*xd)},function(t,n){t.setTime(+t+n*xd)},function(t,n){return(n-t)/xd},function(t){return t.getMinutes()}),Sd=kd.range,Ad=Qn(function(t){var n=t.getTimezoneOffset()*xd%bd;n<0&&(n+=bd),t.setTime(Math.floor((+t-n)/bd)*bd+n)},function(t,n){t.setTime(+t+n*bd)},function(t,n){return(n-t)/bd},function(t){return t.getHours()}),Ed=Ad.range,Cd=Qn(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*xd)/wd},function(t){return t.getDate()-1}),zd=Cd.range,Pd=Kn(0),qd=Kn(1),Ld=Kn(2),Rd=Kn(3),Ud=Kn(4),Dd=Kn(5),Od=Kn(6),Fd=Pd.range,Id=qd.range,Yd=Ld.range,Bd=Rd.range,jd=Ud.range,Hd=Dd.range,Xd=Od.range,Vd=Qn(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Wd=Vd.range,$d=Qn(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});$d.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Qn(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var Zd=$d.range,Gd=Qn(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*xd)},function(t,n){return(n-t)/xd},function(t){return t.getUTCMinutes()}),Jd=Gd.range,Qd=Qn(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+n*bd)},function(t,n){return(n-t)/bd},function(t){return t.getUTCHours()}),Kd=Qd.range,tv=Qn(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/wd},function(t){return t.getUTCDate()-1}),nv=tv.range,ev=te(0),rv=te(1),iv=te(2),ov=te(3),uv=te(4),av=te(5),cv=te(6),sv=ev.range,fv=rv.range,lv=iv.range,hv=ov.range,pv=uv.range,dv=av.range,vv=cv.range,_v=Qn(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),yv=_v.range,gv=Qn(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});gv.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Qn(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var mv,xv=gv.range,bv=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf(\"e\"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},wv=function(t){return t=bv(Math.abs(t)),t?t[1]:NaN},Mv=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},Tv=function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,i=1,o=-1;i<r;++i)switch(t[i]){case\".\":o=e=i;break;case\"0\":0===o&&(o=i),e=i;break;case\"e\":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},Nv=function(t,n){var e=bv(t,n);if(!e)return t+\"\";var r=e[0],i=e[1],o=i-(mv=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join(\"0\"):o>0?r.slice(0,o)+\".\"+r.slice(o):\"0.\"+new Array(1-o).join(\"0\")+bv(t,Math.max(0,n+o-1))[0]},kv=function(t,n){var e=bv(t,n);if(!e)return t+\"\";var r=e[0],i=e[1];return i<0?\"0.\"+new Array(-i).join(\"0\")+r:r.length>i+1?r.slice(0,i+1)+\".\"+r.slice(i+1):r+new Array(i-r.length+2).join(\"0\")},Sv={\"\":Tv,\"%\":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+\"\"},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return kv(100*t,n)},r:kv,s:Nv,X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Av=/^(?:(.)?([<>=^]))?([+\\-\\( ])?([$#])?(0)?(\\d+)?(,)?(\\.\\d+)?([a-z%])?$/i,Ev=function(t){return new ne(t)};ne.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?\"0\":\"\")+(null==this.width?\"\":Math.max(1,0|this.width))+(this.comma?\",\":\"\")+(null==this.precision?\"\":\".\"+Math.max(0,0|this.precision))+this.type};var Cv,zv=[\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"µ\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"],Pv=function(t){function n(t){function n(t){var n,i,c,g=d,m=v;if(\"c\"===p)m=_(t)+m,t=\"\";else{t=+t;var x=(t<0||1/t<0)&&(t*=-1,!0);if(t=_(t,h),x)for(n=-1,i=t.length,x=!1;++n<i;)if(c=t.charCodeAt(n),48<c&&c<58||\"x\"===p&&96<c&&c<103||\"X\"===p&&64<c&&c<71){x=!0;break}if(g=(x?\"(\"===a?a:\"-\":\"-\"===a||\"(\"===a?\"\":a)+g,m=m+(\"s\"===p?zv[8+mv/3]:\"\")+(x&&\"(\"===a?\")\":\"\"),y)for(n=-1,i=t.length;++n<i;)if(c=t.charCodeAt(n),48>c||c>57){m=(46===c?o+t.slice(n+1):t.slice(n))+m,t=t.slice(0,n);break}}l&&!s&&(t=r(t,1/0));var b=g.length+t.length+m.length,w=b<f?new Array(f-b+1).join(e):\"\";switch(l&&s&&(t=r(w+t,w.length?f-m.length:1/0),w=\"\"),u){case\"<\":return g+t+m+w;case\"=\":return g+w+t+m;case\"^\":return w.slice(0,b=w.length>>1)+g+t+m+w.slice(b)}return w+g+t+m}t=Ev(t);var e=t.fill,u=t.align,a=t.sign,c=t.symbol,s=t.zero,f=t.width,l=t.comma,h=t.precision,p=t.type,d=\"$\"===c?i[0]:\"#\"===c&&/[boxX]/.test(p)?\"0\"+p.toLowerCase():\"\",v=\"$\"===c?i[1]:/[%p]/.test(p)?\"%\":\"\",_=Sv[p],y=!p||/[defgprs%]/.test(p);return h=null==h?p?6:12:/[gprs]/.test(p)?Math.max(1,Math.min(21,h)):Math.max(0,Math.min(20,h)),n.toString=function(){return t+\"\"},n}function e(t,e){var r=n((t=Ev(t),t.type=\"f\",t)),i=3*Math.max(-8,Math.min(8,Math.floor(wv(e)/3))),o=Math.pow(10,-i),u=zv[8+i/3];return function(t){return r(o*t)+u}}var r=t.grouping&&t.thousands?Mv(t.grouping,t.thousands):ee,i=t.currency,o=t.decimal;return{format:n,formatPrefix:e}};re({decimal:\".\",thousands:\",\",grouping:[3],currency:[\"$\",\"\"]});var qv,Lv=function(t){return Math.max(0,-wv(Math.abs(t)))},Rv=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(wv(n)/3)))-wv(Math.abs(t)))},Uv=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,wv(n)-wv(t))+1},Dv={\"-\":\"\",_:\" \",0:\"0\"},Ov=/^\\s*\\d+/,Fv=/^%/,Iv=/[\\\\\\^\\$\\*\\+\\?\\|\\[\\]\\(\\)\\.\\{\\}]/g;nr({dateTime:\"%x, %X\",date:\"%-m/%-d/%Y\",time:\"%-I:%M:%S %p\",periods:[\"AM\",\"PM\"],days:[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],shortDays:[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"],months:[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],shortMonths:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"]});var Yv=\"%Y-%m-%dT%H:%M:%S.%LZ\",Bv=Date.prototype.toISOString?er:t.utcFormat(Yv),jv=+new Date(\"2000-01-01T00:00:00.000Z\")?rr:t.utcParse(Yv),Hv=Array.prototype,Xv=Hv.map,Vv=Hv.slice,Wv={name:\"implicit\"},$v=function(t){return function(){return t}},Zv=function(t){return+t},Gv=[0,1],Jv=function(n,r,i){var o,u=n[0],a=n[n.length-1],c=e(u,a,null==r?10:r);switch(i=Ev(null==i?\",f\":i),i.type){case\"s\":var s=Math.max(Math.abs(u),Math.abs(a));return null!=i.precision||isNaN(o=Rv(c,s))||(i.precision=o),t.formatPrefix(i,s);case\"\":case\"e\":case\"g\":case\"p\":case\"r\":null!=i.precision||isNaN(o=Uv(c,Math.max(Math.abs(u),Math.abs(a))))||(i.precision=o-(\"e\"===i.type));break;case\"f\":case\"%\":null!=i.precision||isNaN(o=Lv(c))||(i.precision=o-2*(\"%\"===i.type))}return t.format(i)},Qv=function(t,n){t=t.slice();var e,r=0,i=t.length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},Kv=1e3,t_=60*Kv,n_=60*t_,e_=24*n_,r_=7*e_,i_=30*e_,o_=365*e_,u_=function(){return qr($d,Vd,Pd,Cd,Ad,kd,Td,yd,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},a_=function(){return qr(gv,_v,ev,tv,Qd,Gd,Td,yd,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},c_=function(t){return t.match(/.{6}/g).map(function(t){return\"#\"+t})},s_=c_(\"1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf\"),f_=c_(\"393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6\"),l_=c_(\"3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9\"),h_=c_(\"1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5\"),p_=qp(ln(300,.5,0),ln(-240,.5,1)),d_=qp(ln(-100,.75,.35),ln(80,1.5,.8)),v_=qp(ln(260,.75,.35),ln(80,1.5,.8)),__=ln(),y_=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return __.h=360*t-100,__.s=1.5-1.5*n,__.l=.8-.9*n,__+\"\"},g_=Lr(c_(\"44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725\")),m_=Lr(c_(\"00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf\")),x_=Lr(c_(\"00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4\")),b_=Lr(c_(\"0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921\")),w_=\"http://www.w3.org/1999/xhtml\",M_={svg:\"http://www.w3.org/2000/svg\",xhtml:w_,xlink:\"http://www.w3.org/1999/xlink\",xml:\"http://www.w3.org/XML/1998/namespace\",xmlns:\"http://www.w3.org/2000/xmlns/\"},T_=function(t){var n=t+=\"\",e=n.indexOf(\":\");return e>=0&&\"xmlns\"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),M_.hasOwnProperty(n)?{space:M_[n],local:t}:t},N_=function(t){var n=T_(t);return(n.local?Dr:Ur)(n)},k_=0;Fr.prototype=Or.prototype={constructor:Fr,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var S_=function(t){return function(){return this.matches(t)}};if(\"undefined\"!=typeof document){var A_=document.documentElement;if(!A_.matches){var E_=A_.webkitMatchesSelector||A_.msMatchesSelector||A_.mozMatchesSelector||A_.oMatchesSelector;S_=function(t){return function(){return E_.call(this,t)}}}}var C_=S_,z_={};if(t.event=null,\"undefined\"!=typeof document){var P_=document.documentElement;\"onmouseenter\"in P_||(z_={mouseenter:\"mouseover\",mouseleave:\"mouseout\"})}var q_=function(t,n,e){var r,i,o=Br(t+\"\"),u=o.length;{if(!(arguments.length<2)){for(a=n?Hr:jr,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},L_=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},R_=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},U_=function(t){var n=L_();return n.changedTouches&&(n=n.changedTouches[0]),R_(t,n)},D_=function(t){return null==t?Vr:function(){return this.querySelector(t)}},O_=function(t){\"function\"!=typeof t&&(t=D_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&(\"__data__\"in o&&(u.__data__=o.__data__),s[f]=u);return new zi(r,this._parents)},F_=function(t){return null==t?Wr:function(){return this.querySelectorAll(t)}},I_=function(t){\"function\"!=typeof t&&(t=F_(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new zi(r,i)},Y_=function(t){\"function\"!=typeof t&&(t=C_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new zi(r,this._parents)},B_=function(t){return new Array(t.length)},j_=function(){return new zi(this._enter||this._groups.map(B_),this._parents)};$r.prototype={constructor:$r,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var H_=function(t){return function(){return t}},X_=\"$\",V_=function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?Gr:Zr,r=this._parents,i=this._groups;\"function\"!=typeof t&&(t=H_(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d),y=c[s]=new Array(h);e(f,l,v,_,y,p,n);for(var g,m,x=0,b=0;x<d;++x)if(g=v[x]){for(x>=b&&(b=x+1);!(m=_[b])&&++b<d;);g._next=m||null}}return u=new zi(u,r),u._enter=a,u._exit=c,u},W_=function(){return new zi(this._exit||this._groups.map(B_),this._parents)},$_=function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new zi(u,this._parents)},Z_=function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},G_=function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=Jr);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var u,a=e[o],c=a.length,s=i[o]=new Array(c),f=0;f<c;++f)(u=a[f])&&(s[f]=u);s.sort(n)}return new zi(i,this._parents).order()},J_=function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},Q_=function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},K_=function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},ty=function(){var t=0;return this.each(function(){++t}),t},ny=function(){return!this.node()},ey=function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},ry=function(t,n){var e=T_(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?Kr:Qr:\"function\"==typeof n?e.local?ri:ei:e.local?ni:ti)(e,n))},iy=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView},oy=function(t,n,e){var r;return arguments.length>1?this.each((null==n?ii:\"function\"==typeof n?ui:oi)(t,n,null==e?\"\":e)):iy(r=this.node()).getComputedStyle(r,null).getPropertyValue(t)},uy=function(t,n){return arguments.length>1?this.each((null==n?ai:\"function\"==typeof n?si:ci)(t,n)):this.node()[t]};hi.prototype={add:function(t){var n=this._names.indexOf(t);n<0&&(this._names.push(t),this._node.setAttribute(\"class\",this._names.join(\" \")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute(\"class\",this._names.join(\" \")))},contains:function(t){return this._names.indexOf(t)>=0}};var ay=function(t,n){var e=fi(t+\"\");if(arguments.length<2){for(var r=li(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each((\"function\"==typeof n?yi:n?vi:_i)(e,n))},cy=function(t){return arguments.length?this.each(null==t?gi:(\"function\"==typeof t?xi:mi)(t)):this.node().textContent},sy=function(t){return arguments.length?this.each(null==t?bi:(\"function\"==typeof t?Mi:wi)(t)):this.node().innerHTML},fy=function(){return this.each(Ti)},ly=function(){return this.each(Ni)},hy=function(t){var n=\"function\"==typeof t?t:N_(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},py=function(t,n){var e=\"function\"==typeof t?t:N_(t),r=null==n?ki:\"function\"==typeof n?n:D_(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},dy=function(){return this.each(Si)},vy=function(t){return arguments.length?this.property(\"__data__\",t):this.node().__data__},_y=function(t,n){return this.each((\"function\"==typeof n?Ci:Ei)(t,n))},yy=[null];zi.prototype=Pi.prototype={constructor:zi,select:O_,selectAll:I_,filter:Y_,data:V_,enter:j_,exit:W_,merge:$_,order:Z_,sort:G_,call:J_,nodes:Q_,node:K_,size:ty,empty:ny,each:ey,attr:ry,style:oy,property:uy,classed:ay,text:cy,html:sy,raise:fy,lower:ly,append:hy,insert:py,remove:dy,datum:vy,on:q_,dispatch:_y};var gy=function(t){return\"string\"==typeof t?new zi([[document.querySelector(t)]],[document.documentElement]):new zi([[t]],yy)},my=function(t){return\"string\"==typeof t?new zi([document.querySelectorAll(t)],[document.documentElement]):new zi([null==t?[]:t],yy)},xy=function(t,n,e){arguments.length<3&&(e=n,n=L_().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return R_(t,r);return null},by=function(t,n){null==n&&(n=L_().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=R_(t,n[e]);return i},wy=Pn(\"start\",\"end\",\"interrupt\"),My=[],Ty=0,Ny=1,ky=2,Sy=3,Ay=4,Ey=5,Cy=6,zy=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Ui(t,e,{name:n,index:r,group:i,on:wy,tween:My,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:Ty})},Py=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+\"\";for(i in o)(e=o[i]).name===n?(r=e.state>ky&&e.state<Ey,e.state=Cy,e.timer.stop(),r&&e.on.call(\"interrupt\",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},qy=function(t){return this.each(function(){Py(this,t)})},Ly=function(t,n){var e=this._id;if(t+=\"\",arguments.length<2){for(var r,i=Ri(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Di:Oi)(e,t,n))},Ry=function(t,n){var e;return(\"number\"==typeof n?lp:n instanceof Bt?up:(e=Bt(n))?(n=e,up):vp)(t,n)},Uy=function(t,n){var e=T_(t),r=\"transform\"===e?wp:Ry;return this.attrTween(t,\"function\"==typeof n?(e.local?Xi:Hi)(e,r,Fi(this,\"attr.\"+t,n)):null==n?(e.local?Yi:Ii)(e):(e.local?ji:Bi)(e,r,n))},Dy=function(t,n){var e=\"attr.\"+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if(\"function\"!=typeof n)throw new Error;var r=T_(t);return this.tween(e,(r.local?Vi:Wi)(r,n))},Oy=function(t){var n=this._id;return arguments.length?this.each((\"function\"==typeof t?$i:Zi)(n,t)):Ri(this.node(),n).delay},Fy=function(t){var n=this._id;return arguments.length?this.each((\"function\"==typeof t?Gi:Ji)(n,t)):Ri(this.node(),n).duration},Iy=function(t){var n=this._id;return arguments.length?this.each(Qi(n,t)):Ri(this.node(),n).ease},Yy=function(t){\"function\"!=typeof t&&(t=C_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new so(r,this._parents,this._name,this._id)},By=function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new so(u,this._parents,this._name,this._id)},jy=function(t,n){var e=this._id;return arguments.length<2?Ri(this.node(),e).on.on(t):this.each(to(e,t,n))},Hy=function(){return this.on(\"end.remove\",no(this._id))},Xy=function(t){var n=this._name,e=this._id;\"function\"!=typeof t&&(t=D_(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&(\"__data__\"in a&&(c.__data__=a.__data__),l[h]=c,zy(l[h],n,e,h,l,Ri(a,e)));return new so(o,this._parents,n,e)},Vy=function(t){var n=this._name,e=this._id;\"function\"!=typeof t&&(t=F_(t));\nfor(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=Ri(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&zy(h,n,e,v,p,d);o.push(p),u.push(c)}return new so(o,u,n,e)},Wy=Pi.prototype.constructor,$y=function(){return new Wy(this._groups,this._parents)},Zy=function(t,n,e){var r=\"transform\"==(t+=\"\")?bp:Ry;return null==n?this.styleTween(t,eo(t,r)).on(\"end.style.\"+t,ro(t)):this.styleTween(t,\"function\"==typeof n?oo(t,r,Fi(this,\"style.\"+t,n)):io(t,r,n),e)},Gy=function(t,n,e){var r=\"style.\"+(t+=\"\");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if(\"function\"!=typeof n)throw new Error;return this.tween(r,uo(t,n,null==e?\"\":e))},Jy=function(t){return this.tween(\"text\",\"function\"==typeof t?co(Fi(this,\"text\",t)):ao(null==t?\"\":t+\"\"))},Qy=function(){for(var t=this._name,n=this._id,e=lo(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=Ri(u,n);zy(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new so(r,this._parents,t,e)},Ky=0,tg=Pi.prototype;so.prototype=fo.prototype={constructor:so,select:Xy,selectAll:Vy,filter:Yy,merge:By,selection:$y,transition:Qy,call:tg.call,nodes:tg.nodes,node:tg.node,size:tg.size,empty:tg.empty,each:tg.each,on:jy,attr:Uy,attrTween:Dy,style:Zy,styleTween:Gy,text:Jy,remove:Hy,tween:Ly,delay:Oy,duration:Fy,ease:Iy};var ng={time:null,delay:0,duration:250,ease:g},eg=function(t){var n,e;t instanceof so?(n=t._id,t=t._name):(n=lo(),(e=ng).time=jn(),t=null==t?null:t+\"\");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&zy(u,t,n,s,a,e||ho(u,n));return new so(r,this._parents,t,n)};Pi.prototype.interrupt=qy,Pi.prototype.transition=eg;var rg=[null],ig=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+\"\";for(r in i)if((e=i[r]).state>Ny&&e.name===n)return new so([[t]],rg,n,+r)}return null},og=Array.prototype.slice,ug=function(t){return t},ag=1,cg=2,sg=3,fg=4,lg=1e-6,hg=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=To(e),t.y=ko(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Ao(t),c=Eo(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Mo,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},pg=function(t){var n,e,r,i,o=this,u=[o];do for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r]);while(u.length);return this},dg=function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},vg=function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},_g=function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},yg=function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},gg=function(t){for(var n=this,e=Co(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},mg=function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},xg=function(){var t=[];return this.each(function(n){t.push(n)}),t},bg=function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},wg=function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n};Uo.prototype=zo.prototype={constructor:Uo,each:pg,eachAfter:vg,eachBefore:dg,sum:_g,sort:yg,path:gg,ancestors:mg,descendants:xg,leaves:bg,links:wg,copy:Po};var Mg=function(t){for(var n,e=(t=t.slice()).length,r=null,i=r;e;){var o=new Do(t[e-1]);i=i?i.next=o:r=o,t[n]=t[--e]}return{head:r,tail:i}},Tg=function(t){return Fo(Mg(t),[])},Ng=function(t){return Wo(t),t},kg=function(t){return function(){return t}},Sg=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(Qo(n)).eachAfter(Ko(i,.5)).eachBefore(tu(1)):t.eachBefore(Qo(Jo)).eachAfter(Ko(Go,1)).eachAfter(Ko(i,t.r/Math.min(e,r))).eachBefore(tu(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=Go;return t.radius=function(e){return arguments.length?(n=$o(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=\"function\"==typeof n?n:kg(+n),t):i},t},Ag=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Eg=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)o=u[a],o.y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Cg=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore(Ag),t}function n(t,n){return function(e){e.children&&Eg(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},zg=\"$\",Pg={depth:-1},qg={},Lg=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new Uo(r),null!=(c=n(r,i,t))&&(c+=\"\")&&(s=zg+(a.id=c),h[s]=s in h?qg:a);for(i=0;i<f;++i)if(a=l[i],c=e(t[i],i,t),null!=c&&(c+=\"\")){if(u=h[zg+c],!u)throw new Error(\"missing: \"+c);if(u===qg)throw new Error(\"ambiguous: \"+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error(\"multiple roots\");o=a}if(!o)throw new Error(\"no root\");if(o.parent=Pg,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(Ro),o.parent=null,f>0)throw new Error(\"cycle\");return o}var n=nu,e=eu;return t.id=function(e){return arguments.length?(n=Zo(e),t):n},t.parentId=function(n){return arguments.length?(e=Zo(n),t):e},t};su.prototype=Object.create(Uo.prototype);var Rg=function(){function t(t){var r=fu(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){au(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=ou(a),i=iu(i),a&&i;)c=iu(c),u=ou(u),u.a=t,r=a.z+l-i.z-s+o(a._,i._),r>0&&(uu(cu(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!ou(u)&&(u.t=a,u.m+=l-f),i&&!iu(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=ru,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},Ug=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)o=u[a],o.x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Dg=(1+Math.sqrt(5))/2,Og=function t(n){function e(t,e,r,i,o){lu(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Dg),Fg=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore(Ag),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Og,r=!1,i=1,o=1,u=[0],a=Go,c=Go,s=Go,f=Go,l=Go;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Zo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a=\"function\"==typeof n?n:kg(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c=\"function\"==typeof n?n:kg(+n),t):c},t.paddingRight=function(n){return arguments.length?(s=\"function\"==typeof n?n:kg(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f=\"function\"==typeof n?n:kg(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l=\"function\"==typeof n?n:kg(+n),t):l},t},Ig=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,s.y1=a,void 0}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}var _=f[p]-l,y=e-_;if(a-i>u-r){var g=(i*y+a*_)/e;o(t,p,_,r,i,u,g),o(p,n,y,r,g,u,a)}else{var m=(r*y+u*_)/e;o(t,p,_,r,i,m,a),o(p,n,y,m,i,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},Yg=function(t,n,e,r,i){(1&t.depth?Ug:Eg)(t,n,e,r,i)},Bg=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(a=u[l],c=a.children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Eg(a,e,r,i,r+=(o-r)*a.value/p):Ug(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=lu(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Dg),jg=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)i=r[e],u+=i.x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)i=r[e],i.x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},Hg=function(t){return function(){return t}},Xg=function(){return 1e-6*(Math.random()-.5)},Vg=function(t){function n(){function t(t,e,r,i,o){var a=t.data,p=t.r,d=l+p;{if(!a)return e>s+d||i<s-d||r>f+d||o<f-d;if(a.index>n){var v=s-a.x-a.vx,_=f-a.y-a.vy,y=v*v+_*_;y<d*d&&(0===v&&(v=Xg(),y+=v*v),0===_&&(_=Xg(),y+=_*_),y=(d-(y=Math.sqrt(y)))/y*u,c.vx+=(v*=y)*(d=(p*=p)/(h+p)),c.vy+=(_*=y)*d,a.vx-=v*(d=1-d),a.vy-=_*d)}}}for(var n,r,c,s,f,l,h,p=i.length,d=0;d<a;++d)for(r=I(i,hu,pu).visitAfter(e),n=0;n<p;++n)c=i[n],l=o[n],h=l*l,s=c.x+c.vx,f=c.y+c.vy,r.visit(t)}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e=i.length;for(o=new Array(e),n=0;n<e;++n)o[n]=+t(i[n],n,i)}}var i,o,u=1,a=1;return\"function\"!=typeof t&&(t=Hg(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t=\"function\"==typeof e?e:Hg(+e),r(),n):t},n},Wg=function(t){function n(t){return 1/Math.min(f[t.source.index],f[t.target.index])}function e(n){for(var e=0,r=t.length;e<v;++e)for(var i,o,u,s,f,h,p,d=0;d<r;++d)i=t[d],o=i.source,u=i.target,s=u.x+u.vx-o.x-o.vx||Xg(),f=u.y+u.vy-o.y-o.vy||Xg(),h=Math.sqrt(s*s+f*f),h=(h-c[d])/h*n*a[d],s*=h,f*=h,u.vx-=s*(p=l[d]),u.vy-=f*p,o.vx+=s*(p=1-p),o.vy+=f*p}function r(){if(s){var n,e,r=s.length,p=t.length,d=o(s,h);for(n=0,f=new Array(r);n<r;++n)f[n]=0;for(n=0;n<p;++n)e=t[n],e.index=n,\"object\"!=typeof e.source&&(e.source=vu(d,e.source)),\"object\"!=typeof e.target&&(e.target=vu(d,e.target)),++f[e.source.index],++f[e.target.index];for(n=0,l=new Array(p);n<p;++n)e=t[n],l[n]=f[e.source.index]/(f[e.source.index]+f[e.target.index]);a=new Array(p),i(),c=new Array(p),u()}}function i(){if(s)for(var n=0,e=t.length;n<e;++n)a[n]=+p(t[n],n,t)}function u(){if(s)for(var n=0,e=t.length;n<e;++n)c[n]=+d(t[n],n,t)}var a,c,s,f,l,h=du,p=n,d=Hg(30),v=1;return null==t&&(t=[]),e.initialize=function(t){s=t,r()},e.links=function(n){return arguments.length?(t=n,r(),e):t},e.id=function(t){return arguments.length?(h=t,e):h},e.iterations=function(t){return arguments.length?(v=+t,e):v},e.strength=function(t){return arguments.length?(p=\"function\"==typeof t?t:Hg(+t),i(),e):p},e.distance=function(t){return arguments.length?(d=\"function\"==typeof t?t:Hg(+t),u(),e):d},e},$g=10,Zg=Math.PI*(3-Math.sqrt(5)),Gg=function(t){function n(){e(),d.call(\"tick\",u),a<c&&(p.stop(),d.call(\"end\",u))}function e(){var n,e,r=t.length;for(a+=(f-a)*s,h.each(function(t){t(a)}),n=0;n<r;++n)e=t[n],null==e.fx?e.x+=e.vx*=l:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=l:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=$g*Math.sqrt(e),o=e*Zg;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var u,a=1,c=.001,s=1-Math.pow(c,1/300),f=0,l=.6,h=o(),p=Vn(n),d=Pn(\"tick\",\"end\");return null==t&&(t=[]),r(),u={tick:e,restart:function(){return p.restart(n),u},stop:function(){return p.stop(),u},nodes:function(n){return arguments.length?(t=n,r(),h.each(i),u):t},alpha:function(t){return arguments.length?(a=+t,u):a},alphaMin:function(t){return arguments.length?(c=+t,u):c},alphaDecay:function(t){return arguments.length?(s=+t,u):+s},alphaTarget:function(t){return arguments.length?(f=+t,u):f},velocityDecay:function(t){return arguments.length?(l=1-t,u):1-l},force:function(t,n){return arguments.length>1?(null==n?h.remove(t):h.set(t,i(n)),u):h.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)a=t[s],i=n-a.x,o=e-a.y,u=i*i+o*o,u<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),u):d.on(t)}}},Jg=function(){function t(t){var n,a=i.length,c=I(i,_u,yu).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n=i.length;for(a=new Array(n),t=0;t<n;++t)a[t]=+c(i[t],t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{n=t,n.x=n.data.x,n.y=n.data.y;do u+=a[n.data.index];while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=Xg(),p+=i*i),0===c&&(c=Xg(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=Xg(),p+=i*i),0===c&&(c=Xg(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h);while(t=t.next)}}var i,o,u,a,c=Hg(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c=\"function\"==typeof e?e:Hg(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},Qg=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Hg(.1);return\"function\"!=typeof t&&(t=Hg(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u=\"function\"==typeof t?t:Hg(+t),e(),n):u},n.x=function(r){return arguments.length?(t=\"function\"==typeof r?r:Hg(+r),e(),n):t},n},Kg=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Hg(.1);return\"function\"!=typeof t&&(t=Hg(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u=\"function\"==typeof t?t:Hg(+t),e(),n):u},n.y=function(r){return arguments.length?(t=\"function\"==typeof r?r:Hg(+r),e(),n):t},n},tm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},nm=function(t){var n=t.document.documentElement,e=gy(t).on(\"dragstart.drag\",tm,!0);\"onselectstart\"in n?e.on(\"selectstart.drag\",tm,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect=\"none\")},em=function(t){return function(){return t}};xu.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var rm=function(){function n(t){t.on(\"mousedown.drag\",e).on(\"touchstart.drag\",o).on(\"touchmove.drag\",u).on(\"touchend.drag touchcancel.drag\",a).style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\")}function e(){if(!f&&l.apply(this,arguments)){var n=c(\"mouse\",h.apply(this,arguments),U_,this,arguments);n&&(gy(t.event.view).on(\"mousemove.drag\",r,!0).on(\"mouseup.drag\",i,!0),nm(t.event.view),gu(),s=!1,n(\"start\"))}}function r(){tm(),s=!0,d.mouse(\"drag\")}function i(){gy(t.event.view).on(\"mousemove.drag mouseup.drag\",null),mu(t.event.view,s),tm(),d.mouse(\"end\")}function o(){if(l.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=h.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,xy,this,arguments))&&(gu(),e(\"start\"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=d[r[n].identifier])&&(tm(),e(\"drag\"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(f&&clearTimeout(f),f=setTimeout(function(){f=null},500),n=0;n<i;++n)(e=d[r[n].identifier])&&(gu(),e(\"end\"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=v.copy();if(Xr(new xu(n,\"beforestart\",a,e,_,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=p.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,v=f;switch(h){case\"start\":d[e]=t,p=_++;break;case\"end\":delete d[e],--_;case\"drag\":f=i(r,e),p=_}Xr(new xu(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-v[0],f[1]-v[1],l),l.apply,l,[h,o,u])}}var s,f,l=bu,h=wu,p=Mu,d={},v=Pn(\"start\",\"drag\",\"end\"),_=0;return n.filter=function(t){return arguments.length?(l=\"function\"==typeof t?t:em(!!t),n):l},n.container=function(t){return arguments.length?(h=\"function\"==typeof t?t:em(t),n):h},n.subject=function(t){return arguments.length?(p=\"function\"==typeof t?t:em(t),n):p},n.on=function(){var t=v.on.apply(v,arguments);return t===v?n:t},n},im=function(t){return function(){return t}};ku.prototype={constructor:ku,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Cu(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Au(this,e),t=e,e=t.U),e.C=!1,r.C=!0,Eu(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Eu(this,e),t=e,e=t.U),e.C=!1,r.C=!0,Au(this,r))),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Cu(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r){if(t&&t.C)return void(t.C=!1);do{if(t===this._)break;if(t===i.L){if(n=i.R,n.C&&(n.C=!1,i.C=!0,Au(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Eu(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Au(this,i),t=this._;break}}else if(n=i.L,n.C&&(n.C=!1,i.C=!0,Eu(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Au(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Eu(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var om,um,am,cm,sm,fm=[],lm=[],hm=1e-6,pm=1e-12;na.prototype={constructor:na,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Fu(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){for(var i,o=e.site,u=e.halfedges,a=-1,c=u.length,s=n[u[c-1]],f=s.left===o?s.right:s.left;++a<c;)i=f,s=n[u[a]],f=s.left===o?s.right:s.left,i&&f&&r<i.index&&r<f.index&&Ku(o,i,f)<0&&t.push([o.data,i.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){var r,i=this,o=i._found||0,u=i.cells[o]||i.cells[o=0],a=t-u.site[0],c=n-u.site[1],s=a*a+c*c;do u=i.cells[r=o],o=null,u.halfedges.forEach(function(e){var r=i.edges[e],a=r.left;if(a!==u.site&&a||(a=r.right)){var c=t-a[0],f=n-a[1],l=c*c+f*f;l<s&&(s=l,o=a.index)}});while(null!==o);return i._found=r,null==e||s<=e*e?u.site:null}};var dm=function(){function t(t){return new na(t.map(function(r,i){var o=[Math.round(n(r,i,t)/hm)*hm,Math.round(e(r,i,t)/hm)*hm];return o.index=i,o.data=r,o}),r)}var n=Tu,e=Nu,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n=\"function\"==typeof e?e:im(+e),t):n},t.y=function(n){return arguments.length?(e=\"function\"==typeof n?n:im(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},vm=function(t){return function(){return t}};ra.prototype={constructor:ra,scale:function(t){return 1===t?this:new ra(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ra(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return\"translate(\"+this.x+\",\"+this.y+\") scale(\"+this.k+\")\"}};var _m=new ra(1,0,0);ia.prototype=ra.prototype;var ym=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},gm=function(){function n(t){t.on(\"wheel.zoom\",s).on(\"mousedown.zoom\",f).on(\"dblclick.zoom\",l).on(\"touchstart.zoom\",h).on(\"touchmove.zoom\",p).on(\"touchend.zoom touchcancel.zoom\",d).style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\").property(\"__zoom\",ca)}function e(t,n){return n=Math.max(m,Math.min(x,n)),n===t.k?t:new ra(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ra(t.k,r,i)}function i(t,n){var e=Math.min(0,t.invertX(n[0][0])-b)||Math.max(0,t.invertX(n[1][0])-w),r=Math.min(0,t.invertY(n[0][1])-M)||Math.max(0,t.invertY(n[1][1])-T);return e||r?t.translate(e,r):t}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on(\"start.zoom\",function(){a(this,arguments).start()}).on(\"interrupt.zoom end.zoom\",function(){a(this,arguments).end()}).tween(\"zoom\",function(){var t=this,r=arguments,i=a(t,r),u=g.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l=\"function\"==typeof n?n.apply(t,r):n,h=Sp(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ra(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=k.length;r<i;++r)if((e=k[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=g.apply(t,n)}function s(){function n(){o.wheel=null,o.end()}if(y.apply(this,arguments)){var o=a(this,arguments),u=this.__zoom,c=Math.max(m,Math.min(x,u.k*Math.pow(2,-t.event.deltaY*(t.event.deltaMode?120:1)/500))),s=U_(this);if(o.wheel)o.mouse[0][0]===s[0]&&o.mouse[0][1]===s[1]||(o.mouse[1]=u.invert(o.mouse[0]=s)),clearTimeout(o.wheel);else{if(u.k===c)return;o.mouse=[s,u.invert(s)],Py(this),o.start()}ym(),o.wheel=setTimeout(n,E),o.zoom(\"mouse\",i(r(e(u,c),o.mouse[0],o.mouse[1]),o.extent))}}function f(){function n(){ym(),o.moved=!0,o.zoom(\"mouse\",i(r(o.that.__zoom,o.mouse[0]=U_(o.that),o.mouse[1]),o.extent))}function e(){u.on(\"mousemove.zoom mouseup.zoom\",null),mu(t.event.view,o.moved),ym(),o.end()}if(!_&&y.apply(this,arguments)){var o=a(this,arguments),u=gy(t.event.view).on(\"mousemove.zoom\",n,!0).on(\"mouseup.zoom\",e,!0),c=U_(this);nm(t.event.view),oa(),o.mouse=[c,this.__zoom.invert(c)],Py(this),o.start()}}function l(){if(y.apply(this,arguments)){var o=this.__zoom,a=U_(this),c=o.invert(a),s=o.k*(t.event.shiftKey?.5:2),f=i(r(e(o,s),a,c),g.apply(this,arguments));ym(),N>0?gy(this).transition().duration(N).call(u,f,a):gy(this).call(n.transform,f)}}function h(){if(y.apply(this,arguments)){var n,e,r,i=a(this,arguments),o=t.event.changedTouches,u=o.length;for(oa(),n=0;n<u;++n)e=o[n],r=xy(this,o,e.identifier),r=[r,this.__zoom.invert(r),e.identifier],i.touch0?i.touch1||(i.touch1=r):i.touch0=r;return v&&(v=clearTimeout(v),!i.touch1)?(i.end(),l.apply(this,arguments)):void(t.event.touches.length===u&&(v=setTimeout(function(){v=null},A),Py(this),i.start()))}}function p(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(ym(),v&&(v=clearTimeout(v)),n=0;n<l;++n)o=f[n],u=xy(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],_=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=_[0]-p[0])*g+(g=_[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+_[0])/2,(p[1]+_[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom(\"touch\",i(r(o,u,c),s.extent))}function d(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(oa(),_&&clearTimeout(_),_=setTimeout(function(){_=null},A),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0||r.end()}var v,_,y=ua,g=aa,m=0,x=1/0,b=-x,w=x,M=b,T=w,N=250,k=[],S=Pn(\"start\",\"zoom\",\"end\"),A=500,E=150;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property(\"__zoom\",ca),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,\"function\"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){var t=this.__zoom.k,n=\"function\"==typeof e?e.apply(this,arguments):e;return t*n})},n.scaleTo=function(t,u){n.transform(t,function(){var t=g.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a),s=\"function\"==typeof u?u.apply(this,arguments):u;return i(r(e(n,s),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate(\"function\"==typeof e?e.apply(this,arguments):e,\"function\"==typeof r?r.apply(this,arguments):r),g.apply(this,arguments))})},c.prototype={start:function(){return 1===++this.active&&(this.index=k.push(this)-1,this.emit(\"start\")),this},zoom:function(t,n){return this.mouse&&\"mouse\"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&\"touch\"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&\"touch\"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit(\"zoom\"),this},end:function(){return 0===--this.active&&(k.splice(this.index,1),this.index=-1,this.emit(\"end\")),this},emit:function(t){Xr(new ea(n,t,this.that.__zoom),S.apply,S,[t,this.that,this.args])}},n.filter=function(t){return arguments.length?(y=\"function\"==typeof t?t:vm(!!t),n):y},n.extent=function(t){return arguments.length?(g=\"function\"==typeof t?t:vm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):g},n.scaleExtent=function(t){return arguments.length?(m=+t[0],x=+t[1],n):[m,x]},n.translateExtent=function(t){return arguments.length?(b=+t[0][0],w=+t[1][0],M=+t[0][1],T=+t[1][1],n):[[b,M],[w,T]]},n.duration=function(t){return arguments.length?(N=+t,n):N},n.on=function(){var t=S.on.apply(S,arguments);return t===S?n:t},n},mm=function(t){return function(){return t}},xm=function(t,n,e){this.target=t,this.type=n,this.selection=e},bm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},wm={name:\"drag\"},Mm={name:\"space\"},Tm={name:\"handle\"},Nm={name:\"center\"},km={name:\"x\",handles:[\"e\",\"w\"].map(fa),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Sm={name:\"y\",handles:[\"n\",\"s\"].map(fa),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Am={name:\"xy\",handles:[\"n\",\"e\",\"s\",\"w\",\"nw\",\"ne\",\"se\",\"sw\"].map(fa),input:function(t){return t},output:function(t){return t}},Em={overlay:\"crosshair\",selection:\"move\",n:\"ns-resize\",e:\"ew-resize\",s:\"ns-resize\",w:\"ew-resize\",nw:\"nwse-resize\",ne:\"nesw-resize\",se:\"nwse-resize\",sw:\"nesw-resize\"},Cm={e:\"w\",w:\"e\",nw:\"ne\",ne:\"nw\",se:\"sw\",sw:\"se\"},zm={n:\"s\",s:\"n\",nw:\"sw\",ne:\"se\",se:\"ne\",sw:\"nw\"},Pm={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},qm={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Lm=function(){return ga(Am)},Rm=Math.cos,Um=Math.sin,Dm=Math.PI,Om=Dm/2,Fm=2*Dm,Im=Math.max,Ym=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Os(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Os(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),o=Im(0,Fm-n*l)/o,c=o?n:Fm/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Im(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=ma(n))._=n,t):i&&i._},t},Bm=Array.prototype.slice,jm=function(t){return function(){return t}},Hm=function(){function t(){var t,a=Bm.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Om,h=o.apply(this,a)-Om,p=f*Rm(l),d=f*Um(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Om,y=o.apply(this,a)-Om;if(u||(u=t=L()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rm(_),v*Um(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+\"\"||null}var n=xa,e=ba,r=wa,i=Ma,o=Ta,u=null;return t.radius=function(n){return arguments.length?(r=\"function\"==typeof n?n:jm(+n),t):r},t.startAngle=function(n){return arguments.length?(i=\"function\"==typeof n?n:jm(+n),t):i},t.endAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:jm(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},Xm=function(){return new Na};Na.prototype={constructor:Na,reset:function(){this.s=this.t=0},add:function(t){ka(Mx,t,this.t),ka(this,Mx.s,this.s),this.s?this.t+=Mx.t:this.s=Mx.t},valueOf:function(){return this.s}};var Vm,Wm,$m,Zm,Gm,Jm,Qm,Km,tx,nx,ex,rx,ix,ox,ux,ax,cx,sx,fx,lx,hx,px,dx,vx,_x,yx,gx,mx,xx,bx,wx,Mx=new Na,Tx=1e-6,Nx=1e-12,kx=Math.PI,Sx=kx/2,Ax=kx/4,Ex=2*kx,Cx=180/kx,zx=kx/180,Px=Math.abs,qx=Math.atan,Lx=Math.atan2,Rx=Math.cos,Ux=Math.ceil,Dx=Math.exp,Ox=Math.log,Fx=Math.pow,Ix=Math.sin,Yx=Math.sign||function(t){return t>0?1:t<0?-1:0;\n},Bx=Math.sqrt,jx=Math.tan,Hx={Feature:function(t,n){za(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)za(e[r].geometry,n)}},Xx={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){Pa(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Pa(e[r],n,0)},Polygon:function(t,n){qa(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)qa(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)za(e[r],n)}},Vx=function(t,n){t&&Hx.hasOwnProperty(t.type)?Hx[t.type](t,n):za(t,n)},Wx=Xm(),$x=Xm(),Zx={point:Ca,lineStart:Ca,lineEnd:Ca,polygonStart:function(){Wx.reset(),Zx.lineStart=La,Zx.lineEnd=Ra},polygonEnd:function(){var t=+Wx;$x.add(t<0?Ex+t:t),this.lineStart=this.lineEnd=this.point=Ca},sphere:function(){$x.add(Ex)}},Gx=function(t){return $x.reset(),Vx(t,Zx),2*$x},Jx=Xm(),Qx={point:Xa,lineStart:Wa,lineEnd:$a,polygonStart:function(){Qx.point=Za,Qx.lineStart=Ga,Qx.lineEnd=Ja,Jx.reset(),Zx.polygonStart()},polygonEnd:function(){Zx.polygonEnd(),Qx.point=Xa,Qx.lineStart=Wa,Qx.lineEnd=$a,Wx<0?(Jm=-(Km=180),Qm=-(tx=90)):Jx>Tx?tx=90:Jx<-Tx&&(Qm=-90),ux[0]=Jm,ux[1]=Km}},Kx=function(t){var n,e,r,i,o,u,a;if(tx=Km=-(Jm=Qm=1/0),ox=[],Vx(t,Qx),e=ox.length){for(ox.sort(Ka),n=1,r=ox[0],o=[r];n<e;++n)i=ox[n],tc(r,i[0])||tc(r,i[1])?(Qa(r[0],i[1])>Qa(r[0],r[1])&&(r[1]=i[1]),Qa(i[0],r[1])>Qa(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-(1/0),e=o.length-1,n=0,r=o[e];n<=e;r=i,++n)i=o[n],(a=Qa(r[1],i[0]))>u&&(u=a,Jm=i[0],Km=r[1])}return ox=ux=null,Jm===1/0||Qm===1/0?[[NaN,NaN],[NaN,NaN]]:[[Jm,Qm],[Km,tx]]},tb={sphere:Ca,point:nc,lineStart:rc,lineEnd:uc,polygonStart:function(){tb.lineStart=ac,tb.lineEnd=cc},polygonEnd:function(){tb.lineStart=rc,tb.lineEnd=uc}},nb=function(t){ax=cx=sx=fx=lx=hx=px=dx=vx=_x=yx=0,Vx(t,tb);var n=vx,e=_x,r=yx,i=n*n+e*e+r*r;return i<Nx&&(n=hx,e=px,r=dx,cx<Tx&&(n=sx,e=fx,r=lx),i=n*n+e*e+r*r,i<Nx)?[NaN,NaN]:[Lx(e,n)*Cx,Aa(r/Bx(i))*Cx]},eb=function(t){return function(){return t}},rb=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return e=n.invert(e,r),e&&t.invert(e[0],e[1])}),e};lc.invert=lc;var ib,ob,ub,ab,cb,sb,fb,lb,hb,pb,db,vb=function(t){function n(n){return n=t(n[0]*zx,n[1]*zx),n[0]*=Cx,n[1]*=Cx,n}return t=hc(t[0]*zx,t[1]*zx,t.length>2?t[2]*zx:0),n.invert=function(n){return n=t.invert(n[0]*zx,n[1]*zx),n[0]*=Cx,n[1]*=Cx,n},n},_b=function(){function t(t,n){e.push(t=r(t,n)),t[0]*=Cx,t[1]*=Cx}function n(){var t=i.apply(this,arguments),n=o.apply(this,arguments)*zx,c=u.apply(this,arguments)*zx;return e=[],r=hc(-t[0]*zx,-t[1]*zx,0).invert,_c(a,n,c,1),t={type:\"Polygon\",coordinates:[e]},e=r=null,t}var e,r,i=eb([0,0]),o=eb(90),u=eb(6),a={point:t};return n.center=function(t){return arguments.length?(i=\"function\"==typeof t?t:eb([+t[0],+t[1]]),n):i},n.radius=function(t){return arguments.length?(o=\"function\"==typeof t?t:eb(+t),n):o},n.precision=function(t){return arguments.length?(u=\"function\"==typeof t?t:eb(+t),n):u},n},yb=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Ca,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},gb=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=n[0],f=n[1],l=0,h=1,p=s-a,d=f-c;if(u=e-a,p||!(u>0)){if(u/=p,p<0){if(u<l)return;u<h&&(h=u)}else if(p>0){if(u>h)return;u>l&&(l=u)}if(u=i-a,p||!(u<0)){if(u/=p,p<0){if(u>h)return;u>l&&(l=u)}else if(p>0){if(u<l)return;u<h&&(h=u)}if(u=r-c,d||!(u>0)){if(u/=d,d<0){if(u<l)return;u<h&&(h=u)}else if(d>0){if(u>h)return;u>l&&(l=u)}if(u=o-c,d||!(u<0)){if(u/=d,d<0){if(u>h)return;u>l&&(l=u)}else if(d>0){if(u<l)return;u<h&&(h=u)}return l>0&&(t[0]=a+l*p,t[1]=c+l*d),h<1&&(n[0]=a+h*p,n[1]=c+h*d),!0}}}}},mb=function(t,n){return Px(t[0]-n[0])<Tx&&Px(t[1]-n[1])<Tx},xb=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if(mb(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a.push(e=new gc(r,t,null,!0)),c.push(e.o=new gc(r,null,e,!1)),a.push(e=new gc(u,t,null,!1)),c.push(e.o=new gc(u,null,e,!0))}}),a.length){for(c.sort(n),mc(a),mc(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}h=h.o,s=h.z,p=!p}while(!h.v);i.lineEnd()}}},bb=1e9,wb=-bb,Mb=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=xc(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},Tb=Xm(),Nb={sphere:Ca,point:Ca,lineStart:bc,lineEnd:Ca,polygonStart:Ca,polygonEnd:Ca},kb=function(t){return Tb.reset(),Vx(t,Nb),+Tb},Sb=[null,null],Ab={type:\"LineString\",coordinates:Sb},Eb=function(t,n){return Sb[0]=t,Sb[1]=n,kb(Ab)},Cb=function(t,n){var e=t[0]*zx,r=t[1]*zx,i=n[0]*zx,o=n[1]*zx,u=Rx(r),a=Ix(r),c=Rx(o),s=Ix(o),f=u*Rx(e),l=u*Ix(e),h=c*Rx(i),p=c*Ix(i),d=2*Aa(Bx(Ea(o-r)+u*c*Ea(i-e))),v=Ix(d),_=d?function(t){var n=Ix(t*=d)/v,e=Ix(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[Lx(i,r)*Cx,Lx(o,Bx(r*r+i*i))*Cx]}:function(){return[e*Cx,r*Cx]};return _.distance=d,_},zb=function(t){return t},Pb=Xm(),qb=Xm(),Lb={point:Ca,lineStart:Ca,lineEnd:Ca,polygonStart:function(){Lb.lineStart=Ec,Lb.lineEnd=Pc},polygonEnd:function(){Lb.lineStart=Lb.lineEnd=Lb.point=Ca,Pb.add(Px(qb)),qb.reset()},result:function(){var t=Pb/2;return Pb.reset(),t}},Rb=1/0,Ub=Rb,Db=-Rb,Ob=Db,Fb={point:qc,lineStart:Ca,lineEnd:Ca,polygonStart:Ca,polygonEnd:Ca,result:function(){var t=[[Rb,Ub],[Db,Ob]];return Db=Ob=-(Ub=Rb=1/0),t}},Ib=0,Yb=0,Bb=0,jb=0,Hb=0,Xb=0,Vb=0,Wb=0,$b=0,Zb={point:Lc,lineStart:Rc,lineEnd:Oc,polygonStart:function(){Zb.lineStart=Fc,Zb.lineEnd=Ic},polygonEnd:function(){Zb.point=Lc,Zb.lineStart=Rc,Zb.lineEnd=Oc},result:function(){var t=$b?[Vb/$b,Wb/$b]:Xb?[jb/Xb,Hb/Xb]:Bb?[Ib/Bb,Yb/Bb]:[NaN,NaN];return Ib=Yb=Bb=jb=Hb=Xb=Vb=Wb=$b=0,t}};jc.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Ex)}},result:Ca},Hc.prototype={_circle:Xc(4.5),pointRadius:function(t){return this._circle=Xc(t),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push(\"Z\"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push(\"M\",t,\",\",n),this._point=1;break;case 1:this._string.push(\"L\",t,\",\",n);break;default:this._string.push(\"M\",t,\",\",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join(\"\");return this._string=[],t}}};var Gb=function(t,n){function e(t){return t&&(\"function\"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Vx(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Vx(t,r(Lb)),Lb.result()},e.bounds=function(t){return Vx(t,r(Fb)),Fb.result()},e.centroid=function(t){return Vx(t,r(Zb)),Zb.result()},e.projection=function(n){return arguments.length?(r=null==(t=n)?zb:n.stream,e):t},e.context=function(t){return arguments.length?(i=null==(n=t)?new Hc:new jc(t),\"function\"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o=\"function\"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},Jb=Xm(),Qb=function(t,n){var e=n[0],r=n[1],i=[Ix(e),-Rx(e),0],o=0,u=0;Jb.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+Ax,d=Ix(p),v=Rx(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+Ax,x=Ix(m),b=Rx(m),w=g-h,M=w>=0?1:-1,T=M*w,N=T>kx,k=d*x;if(Jb.add(Lx(k*M*Ix(T),v*b+k*Rx(T))),o+=N?w+M*Ex:w,N^h>=e^g>=e){var S=Ya(Fa(l),Fa(y));Ha(S);var A=Ya(i,S);Ha(A);var E=(N^w>=0?-1:1)*Aa(A[2]);(r>E||r===E&&(S[0]||S[1]))&&(u+=N^w>=0?1:-1)}}return(o<-Tx||o<Tx&&Jb<-Tx)^1&u},Kb=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(Vc))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=yb(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Js(d);var t=Qb(p,y);d.length?(x||(o.polygonStart(),x=!0),xb(d,Wc,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},tw=Kb(function(){return!0},$c,Gc,[-kx,-Sx]),nw=function(t,n){function e(e,r,i,o){_c(o,t,n,i,e,r)}function r(t,n){return Rx(t)*Rx(n)>a}function i(t){var n,e,i,a,f;return{lineStart:function(){a=i=!1,f=1},point:function(l,h){var p,d=[l,h],v=r(l,h),_=c?v?0:u(l,h):v?u(l+(l<0?kx:-kx),h):0;if(!n&&(a=i=v)&&t.lineStart(),v!==i&&(p=o(n,d),(mb(n,p)||mb(d,p))&&(d[0]+=Tx,d[1]+=Tx,v=r(d[0],d[1]))),v!==i)f=0,v?(t.lineStart(),p=o(d,n),t.point(p[0],p[1])):(p=o(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(s&&n&&c^v){var y;_&e||!(y=o(d,n,!0))||(f=0,c?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&mb(n,d)||t.point(d[0],d[1]),n=d,i=v,e=_},lineEnd:function(){i&&t.lineEnd(),n=null},clean:function(){return f|(a&&i)<<1}}}function o(t,n,e){var r=Fa(t),i=Fa(n),o=[1,0,0],u=Ya(r,i),c=Ia(u,u),s=u[0],f=c-s*s;if(!f)return!e&&t;var l=a*c/f,h=-a*s/f,p=Ya(o,u),d=ja(o,l),v=ja(u,h);Ba(d,v);var _=p,y=Ia(d,_),g=Ia(_,_),m=y*y-g*(Ia(d,d)-1);if(!(m<0)){var x=Bx(m),b=ja(_,(-y-x)/g);if(Ba(b,d),b=Oa(b),!e)return b;var w,M=t[0],T=n[0],N=t[1],k=n[1];T<M&&(w=M,M=T,T=w);var S=T-M,A=Px(S-kx)<Tx,E=A||S<Tx;if(!A&&k<N&&(w=N,N=k,k=w),E?A?N+k>0^b[1]<(Px(b[0]-M)<Tx?N:k):N<=b[1]&&b[1]<=k:S>kx^(M<=b[0]&&b[0]<=T)){var C=ja(_,(-y+x)/g);return Ba(C,d),[b,Oa(C)]}}}function u(n,e){var r=c?t:kx-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var a=Rx(t),c=a>0,s=Px(a)>Tx;return Kb(r,i,e,c?[0,-t]:[-kx,t-kx])},ew=function(t){return{stream:Jc(t)}};Qc.prototype={constructor:Qc,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var rw=16,iw=Rx(30*zx),ow=function(t,n){return+n?es(t,n):ns(t)},uw=Jc({point:function(t,n){this.stream.point(t*zx,n*zx)}}),aw=function(){return os(as).scale(155.424).center([0,33.6442])},cw=function(){return aw().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},sw=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=cw(),s=aw().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=aw().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=cs([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+Tx,a+.12*e+Tx],[r-.214*e-Tx,a+.234*e-Tx]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+Tx,a+.166*e+Tx],[r-.115*e-Tx,a+.234*e-Tx]]).stream(l),n()},t.fitExtent=function(n,e){return Kc(t,n,e)},t.fitSize=function(n,e){return ts(t,n,e)},t.scale(1070)},fw=ss(function(t){return Bx(2/(1+t))});fw.invert=fs(function(t){return 2*Aa(t/2)});var lw=function(){return rs(fw).scale(124.75).clipAngle(179.999)},hw=ss(function(t){return(t=Sa(t))&&t/Ix(t)});hw.invert=fs(function(t){return t});var pw=function(){return rs(hw).scale(79.4188).clipAngle(179.999)};ls.invert=function(t,n){return[t,2*qx(Dx(n))-Sx]};var dw=function(){return hs(ls).scale(961/Ex)},vw=function(){return os(ds).scale(109.5).parallels([30,30])};vs.invert=vs;var _w=function(){return rs(vs).scale(152.63)},yw=function(){return os(_s).scale(131.154).center([0,13.9389])};ys.invert=fs(qx);var gw=function(){return rs(ys).scale(144.049).clipAngle(60)},mw=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=zb,l=null,h=zb;return u={stream:function(t){return i&&o===t?i:i=f(h(o=t))},clipExtent:function(i){return arguments.length?(h=null==i?(l=n=e=r=null,zb):xc(l=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==l?null:[[l,n],[e,r]]},scale:function(n){return arguments.length?(f=gs(a=+n,c,s),t()):a},translate:function(n){return arguments.length?(f=gs(a,c=+n[0],s=+n[1]),t()):[c,s]},fitExtent:function(t,n){return Kc(u,t,n)},fitSize:function(t,n){return ts(u,t,n)}}};ms.invert=fs(Aa);var xw=function(){return rs(ms).scale(249.5).clipAngle(90+Tx)};xs.invert=fs(function(t){return 2*qx(t)});var bw=function(){return rs(xs).scale(250).clipAngle(142)};bs.invert=function(t,n){return[-n,2*qx(Dx(t))-Sx]};var ww=function(){var t=hs(bs),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)};t.version=ws,t.bisect=ks,t.bisectRight=ks,t.bisectLeft=Ss,t.ascending=Ms,t.bisector=Ts,t.descending=As,t.deviation=zs,t.extent=Ps,t.histogram=Hs,t.thresholdFreedmanDiaconis=Vs,t.thresholdScott=Ws,t.thresholdSturges=js,t.max=$s,t.mean=Zs,t.median=Gs,t.merge=Js,t.min=Qs,t.pairs=Ks,t.permute=tf,t.quantile=Xs,t.range=Os,t.scan=nf,t.shuffle=ef,t.sum=rf,t.ticks=Bs,t.tickStep=e,t.transpose=of,t.variance=Cs,t.zip=uf,t.entries=hf,t.keys=ff,t.values=lf,t.map=o,t.set=l,t.nest=cf,t.randomUniform=pf,t.randomNormal=df,t.randomLogNormal=vf,t.randomBates=yf,t.randomIrwinHall=_f,t.randomExponential=gf,t.easeLinear=h,t.easeQuad=v,t.easeQuadIn=p,t.easeQuadOut=d,t.easeQuadInOut=v,t.easeCubic=g,t.easeCubicIn=_,t.easeCubicOut=y,t.easeCubicInOut=g,t.easePoly=wf,t.easePolyIn=xf,t.easePolyOut=bf,t.easePolyInOut=wf,t.easeSin=b,t.easeSinIn=m,t.easeSinOut=x,t.easeSinInOut=b,t.easeExp=T,t.easeExpIn=w,t.easeExpOut=M,t.easeExpInOut=T,t.easeCircle=S,t.easeCircleIn=N,t.easeCircleOut=k,t.easeCircleInOut=S,t.easeBounce=E,t.easeBounceIn=A,t.easeBounceOut=E,t.easeBounceInOut=C,t.easeBack=Of,t.easeBackIn=Uf,t.easeBackOut=Df,t.easeBackInOut=Of,t.easeElastic=jf,t.easeElasticIn=Bf,t.easeElasticOut=jf,t.easeElasticInOut=Hf,t.polygonArea=Xf,t.polygonCentroid=Vf,t.polygonHull=$f,t.polygonContains=Zf,t.polygonLength=Gf,t.path=L,t.quadtree=I,t.queue=Z,t.arc=wl,t.area=Nl,t.line=Tl,t.pie=Al,t.radialArea=zl,t.radialLine=Cl,t.symbol=Jl,t.symbols=Gl,t.symbolCircle=Pl,t.symbolCross=ql,t.symbolDiamond=Ul,t.symbolSquare=Bl,t.symbolStar=Yl,t.symbolTriangle=Hl,t.symbolWye=Zl,t.curveBasisClosed=th,t.curveBasisOpen=nh,t.curveBasis=Kl,t.curveBundle=eh,t.curveCardinalClosed=ih,t.curveCardinalOpen=oh,t.curveCardinal=rh,t.curveCatmullRomClosed=ah,t.curveCatmullRomOpen=ch,t.curveCatmullRom=uh,t.curveLinearClosed=sh,t.curveLinear=Ml,t.curveMonotoneX=zt,t.curveMonotoneY=Pt,t.curveNatural=fh,t.curveStep=lh,t.curveStepAfter=Dt,t.curveStepBefore=Ut,t.stack=vh,t.stackOffsetExpand=_h,t.stackOffsetNone=ph,t.stackOffsetSilhouette=yh,t.stackOffsetWiggle=gh,t.stackOrderAscending=mh,t.stackOrderDescending=xh,t.stackOrderInsideOut=bh,t.stackOrderNone=dh,t.stackOrderReverse=wh,t.color=Bt,t.rgb=Vt,t.hsl=Gt,t.lab=tn,t.hcl=cn,t.cubehelix=ln,t.interpolate=_p,t.interpolateArray=sp,t.interpolateDate=fp,t.interpolateNumber=lp,t.interpolateObject=hp,t.interpolateRound=yp,t.interpolateString=vp,t.interpolateTransformCss=bp,t.interpolateTransformSvg=wp,t.interpolateZoom=Sp,t.interpolateRgb=up,t.interpolateRgbBasis=ap,t.interpolateRgbBasisClosed=cp,t.interpolateHsl=Ap,t.interpolateHslLong=Ep,t.interpolateLab=En,t.interpolateHcl=Cp,t.interpolateHclLong=zp,t.interpolateCubehelix=Pp,t.interpolateCubehelixLong=qp,t.interpolateBasis=rp,t.interpolateBasisClosed=ip,t.quantize=Lp,t.dispatch=Pn,t.dsvFormat=Op,t.csvParse=Ip,t.csvParseRows=Yp,t.csvFormat=Bp,t.csvFormatRows=jp,t.tsvParse=Xp,t.tsvParseRows=Vp,t.tsvFormat=Wp,t.tsvFormatRows=$p,t.request=Zp,t.html=Jp,t.json=Qp,t.text=Kp,t.xml=td,t.csv=ed,t.tsv=rd,t.now=jn,t.timer=Vn,t.timerFlush=Wn,t.timeout=pd,t.interval=dd,t.timeInterval=Qn,t.timeMillisecond=yd,t.timeMilliseconds=gd,t.timeSecond=Td,t.timeSeconds=Nd,t.timeMinute=kd,t.timeMinutes=Sd,t.timeHour=Ad,t.timeHours=Ed,t.timeDay=Cd,t.timeDays=zd,t.timeWeek=Pd,t.timeWeeks=Fd,t.timeSunday=Pd,t.timeSundays=Fd,t.timeMonday=qd,t.timeMondays=Id,t.timeTuesday=Ld,t.timeTuesdays=Yd;t.timeWednesday=Rd;t.timeWednesdays=Bd,t.timeThursday=Ud,t.timeThursdays=jd,t.timeFriday=Dd,t.timeFridays=Hd,t.timeSaturday=Od,t.timeSaturdays=Xd,t.timeMonth=Vd,t.timeMonths=Wd,t.timeYear=$d,t.timeYears=Zd,t.utcMillisecond=yd,t.utcMilliseconds=gd,t.utcSecond=Td,t.utcSeconds=Nd,t.utcMinute=Gd,t.utcMinutes=Jd,t.utcHour=Qd,t.utcHours=Kd,t.utcDay=tv,t.utcDays=nv,t.utcWeek=ev,t.utcWeeks=sv,t.utcSunday=ev,t.utcSundays=sv,t.utcMonday=rv,t.utcMondays=fv,t.utcTuesday=iv,t.utcTuesdays=lv,t.utcWednesday=ov,t.utcWednesdays=hv,t.utcThursday=uv,t.utcThursdays=pv,t.utcFriday=av,t.utcFridays=dv,t.utcSaturday=cv,t.utcSaturdays=vv,t.utcMonth=_v,t.utcMonths=yv,t.utcYear=gv,t.utcYears=xv,t.formatLocale=Pv,t.formatDefaultLocale=re,t.formatSpecifier=Ev,t.precisionFixed=Lv,t.precisionPrefix=Rv,t.precisionRound=Uv,t.isoFormat=Bv,t.isoParse=jv,t.timeFormatLocale=ae,t.timeFormatDefaultLocale=nr,t.scaleBand=or,t.scalePoint=ar,t.scaleIdentity=yr,t.scaleLinear=_r,t.scaleLog=Tr,t.scaleOrdinal=ir,t.scaleImplicit=Wv,t.scalePow=kr,t.scaleSqrt=Sr,t.scaleQuantile=Ar,t.scaleQuantize=Er,t.scaleThreshold=Cr,t.scaleTime=u_,t.scaleUtc=a_,t.schemeCategory10=s_,t.schemeCategory20b=f_,t.schemeCategory20c=l_,t.schemeCategory20=h_,t.scaleSequential=Rr,t.interpolateCubehelixDefault=p_,t.interpolateRainbow=y_,t.interpolateWarm=d_,t.interpolateCool=v_,t.interpolateViridis=g_,t.interpolateMagma=m_,t.interpolateInferno=x_,t.interpolatePlasma=b_,t.creator=N_,t.customEvent=Xr,t.local=Or,t.matcher=C_,t.mouse=U_,t.namespace=T_,t.namespaces=M_,t.select=gy,t.selectAll=my,t.selection=Pi,t.selector=D_,t.selectorAll=F_,t.touch=xy,t.touches=by,t.window=iy,t.active=ig,t.interrupt=Py,t.transition=fo,t.axisTop=mo,t.axisRight=xo,t.axisBottom=bo,t.axisLeft=wo,t.cluster=hg,t.hierarchy=zo,t.pack=Sg,t.packSiblings=Ng,t.packEnclose=Tg,t.partition=Cg,t.stratify=Lg,t.tree=Rg,t.treemap=Fg,t.treemapBinary=Ig,t.treemapDice=Eg,t.treemapSlice=Ug,t.treemapSliceDice=Yg,t.treemapSquarify=Og,t.treemapResquarify=Bg,t.forceCenter=jg,t.forceCollide=Vg,t.forceLink=Wg,t.forceManyBody=Jg,t.forceSimulation=Gg,t.forceX=Qg,t.forceY=Kg,t.drag=rm,t.dragDisable=nm,t.dragEnable=mu,t.voronoi=dm,t.zoom=gm,t.zoomIdentity=_m,t.zoomTransform=ia,t.brush=Lm,t.brushX=_a,t.brushY=ya,t.brushSelection=va,t.chord=Ym,t.ribbon=Hm,t.geoAlbers=cw,t.geoAlbersUsa=sw,t.geoArea=Gx,t.geoAzimuthalEqualArea=lw,t.geoAzimuthalEqualAreaRaw=fw,t.geoAzimuthalEquidistant=pw,t.geoAzimuthalEquidistantRaw=hw,t.geoBounds=Kx,t.geoCentroid=nb,t.geoCircle=_b,t.geoClipExtent=Mb,t.geoConicConformal=vw,t.geoConicConformalRaw=ds,t.geoConicEqualArea=aw,t.geoConicEqualAreaRaw=as,t.geoConicEquidistant=yw,t.geoConicEquidistantRaw=_s,t.geoDistance=Eb,t.geoEquirectangular=_w,t.geoEquirectangularRaw=vs,t.geoGnomonic=gw,t.geoGnomonicRaw=ys,t.geoGraticule=Sc,t.geoGraticule10=Ac,t.geoIdentity=mw,t.geoInterpolate=Cb,t.geoLength=kb,t.geoMercator=dw,t.geoMercatorRaw=ls,t.geoOrthographic=xw,t.geoOrthographicRaw=ms,t.geoPath=Gb,t.geoProjection=rs,t.geoProjectionMutator=is,t.geoRotation=vb,t.geoStereographic=bw,t.geoStereographicRaw=xs,t.geoStream=Vx,t.geoTransform=ew,t.geoTransverseMercator=ww,t.geoTransverseMercatorRaw=bs,Object.defineProperty(t,\"__esModule\",{value:!0})});"
  },
  {
    "path": "web/vue/dist/vendor/humanize-duration.js",
    "content": "// HumanizeDuration.js - http://git.io/j0HgmQ\n\n;(function () {\n  var languages = {\n    en: {\n      y: function (c) { return 'year' + (c !== 1 ? 's' : '') },\n      mo: function (c) { return 'month' + (c !== 1 ? 's' : '') },\n      w: function (c) { return 'week' + (c !== 1 ? 's' : '') },\n      d: function (c) { return 'day' + (c !== 1 ? 's' : '') },\n      h: function (c) { return 'hour' + (c !== 1 ? 's' : '') },\n      m: function (c) { return 'minute' + (c !== 1 ? 's' : '') },\n      s: function (c) { return 'second' + (c !== 1 ? 's' : '') },\n      ms: function (c) { return 'millisecond' + (c !== 1 ? 's' : '') },\n      decimal: '.'\n    }\n  }\n\n  // You can create a humanizer, which returns a function with default\n  // parameters.\n  function humanizer (passedOptions) {\n    var result = function humanizer (ms, humanizerOptions) {\n      var options = extend({}, result, humanizerOptions || {})\n      return doHumanization(ms, options)\n    }\n\n    return extend(result, {\n      language: 'en',\n      delimiter: ', ',\n      spacer: ' ',\n      conjunction: '',\n      serialComma: true,\n      units: ['y', 'mo', 'w', 'd', 'h', 'm', 's'],\n      languages: {},\n      round: false,\n      unitMeasures: {\n        y: 31557600000,\n        mo: 2629800000,\n        w: 604800000,\n        d: 86400000,\n        h: 3600000,\n        m: 60000,\n        s: 1000,\n        ms: 1\n      }\n    }, passedOptions)\n  }\n\n  // The main function is just a wrapper around a default humanizer.\n  var humanizeDuration = humanizer({})\n\n  // doHumanization does the bulk of the work.\n  function doHumanization (ms, options) {\n    var i, len, piece\n\n    // Make sure we have a positive number.\n    // Has the nice sideffect of turning Number objects into primitives.\n    ms = Math.abs(ms)\n\n    var dictionary = options.languages[options.language] || languages[options.language]\n    if (!dictionary) {\n      throw new Error('No language ' + dictionary + '.')\n    }\n\n    var pieces = []\n\n    // Start at the top and keep removing units, bit by bit.\n    var unitName, unitMS, unitCount\n    for (i = 0, len = options.units.length; i < len; i++) {\n      unitName = options.units[i]\n      unitMS = options.unitMeasures[unitName]\n\n      // What's the number of full units we can fit?\n      if (i + 1 === len) {\n        unitCount = ms / unitMS\n      } else {\n        unitCount = Math.floor(ms / unitMS)\n      }\n\n      // Add the string.\n      pieces.push({\n        unitCount: unitCount,\n        unitName: unitName\n      })\n\n      // Remove what we just figured out.\n      ms -= unitCount * unitMS\n    }\n\n    var firstOccupiedUnitIndex = 0\n    for (i = 0; i < pieces.length; i++) {\n      if (pieces[i].unitCount) {\n        firstOccupiedUnitIndex = i\n        break\n      }\n    }\n\n    if (options.round) {\n      var ratioToLargerUnit, previousPiece\n      for (i = pieces.length - 1; i >= 0; i--) {\n        piece = pieces[i]\n        piece.unitCount = Math.round(piece.unitCount)\n\n        if (i === 0) { break }\n\n        previousPiece = pieces[i - 1]\n\n        ratioToLargerUnit = options.unitMeasures[previousPiece.unitName] / options.unitMeasures[piece.unitName]\n        if ((piece.unitCount % ratioToLargerUnit) === 0 || (options.largest && ((options.largest - 1) < (i - firstOccupiedUnitIndex)))) {\n          previousPiece.unitCount += piece.unitCount / ratioToLargerUnit\n          piece.unitCount = 0\n        }\n      }\n    }\n\n    var result = []\n    for (i = 0, pieces.length; i < len; i++) {\n      piece = pieces[i]\n      if (piece.unitCount) {\n        result.push(render(piece.unitCount, piece.unitName, dictionary, options))\n      }\n\n      if (result.length === options.largest) { break }\n    }\n\n    if (result.length) {\n      if (!options.conjunction || result.length === 1) {\n        return result.join(options.delimiter)\n      } else if (result.length === 2) {\n        return result.join(options.conjunction)\n      } else if (result.length > 2) {\n        return result.slice(0, -1).join(options.delimiter) + (options.serialComma ? ',' : '') + options.conjunction + result.slice(-1)\n      }\n    } else {\n      return render(0, options.units[options.units.length - 1], dictionary, options)\n    }\n  }\n\n  function render (count, type, dictionary, options) {\n    var decimal\n    if (options.decimal === void 0) {\n      decimal = dictionary.decimal\n    } else {\n      decimal = options.decimal\n    }\n\n    var countStr = count.toString().replace('.', decimal)\n\n    var dictionaryValue = dictionary[type]\n    var word\n    if (typeof dictionaryValue === 'function') {\n      word = dictionaryValue(count)\n    } else {\n      word = dictionaryValue\n    }\n\n    return countStr + options.spacer + word\n  }\n\n  function extend (destination) {\n    var source\n    for (var i = 1; i < arguments.length; i++) {\n      source = arguments[i]\n      for (var prop in source) {\n        if (source.hasOwnProperty(prop)) {\n          destination[prop] = source[prop]\n        }\n      }\n    }\n    return destination\n  }\n\n  humanizeDuration.getSupportedLanguages = function getSupportedLanguages () {\n    var result = []\n    for (var language in languages) {\n      if (languages.hasOwnProperty(language)) {\n        result.push(language)\n      }\n    }\n    return result\n  }\n\n  humanizeDuration.humanizer = humanizer\n\n  if (typeof define === 'function' && define.amd) {\n    define(function () {\n      return humanizeDuration\n    })\n  } else if (typeof module !== 'undefined' && module.exports) {\n    module.exports = humanizeDuration\n  } else {\n    this.humanizeDuration = humanizeDuration\n  }\n})();  // eslint-disable-line semi"
  },
  {
    "path": "web/vue/dist/vendor/moment.js",
    "content": "//! moment.js\n//! version : 2.15.2\n//! authors : Tim Wood, Iskren Chernev, Moment.js contributors\n//! license : MIT\n//! momentjs.com\n!function(a,b){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=b():\"function\"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){\"use strict\";function a(){return md.apply(null,arguments)}\n// This is done to register the method called with moment()\n// without creating circular dependencies.\nfunction b(a){md=a}function c(a){return a instanceof Array||\"[object Array]\"===Object.prototype.toString.call(a)}function d(a){\n// IE8 will treat undefined and null as object if it wasn't for\n// input != null\nreturn null!=a&&\"[object Object]\"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)\n// even if its not own property I'd still call it non-empty\nreturn!1;return!0}function f(a){return a instanceof Date||\"[object Date]\"===Object.prototype.toString.call(a)}function g(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function h(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function i(a,b){for(var c in b)h(b,c)&&(a[c]=b[c]);return h(b,\"toString\")&&(a.toString=b.toString),h(b,\"valueOf\")&&(a.valueOf=b.valueOf),a}function j(a,b,c,d){return qb(a,b,c,d,!0).utc()}function k(){\n// We need to deep clone this object.\nreturn{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function l(a){return null==a._pf&&(a._pf=k()),a._pf}function m(a){if(null==a._isValid){var b=l(a),c=nd.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function n(a){var b=j(NaN);return null!=a?i(l(b),a):l(b).userInvalidated=!0,b}function o(a){return void 0===a}function p(a,b){var c,d,e;if(o(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),o(b._i)||(a._i=b._i),o(b._f)||(a._f=b._f),o(b._l)||(a._l=b._l),o(b._strict)||(a._strict=b._strict),o(b._tzm)||(a._tzm=b._tzm),o(b._isUTC)||(a._isUTC=b._isUTC),o(b._offset)||(a._offset=b._offset),o(b._pf)||(a._pf=l(b)),o(b._locale)||(a._locale=b._locale),od.length>0)for(c in od)d=od[c],e=b[d],o(e)||(a[d]=e);return a}\n// Moment prototype object\nfunction q(b){p(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),\n// Prevent infinite loop in case updateOffset creates new moment\n// objects.\npd===!1&&(pd=!0,a.updateOffset(this),pd=!1)}function r(a){return a instanceof q||null!=a&&null!=a._isAMomentObject}function s(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function t(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=s(b)),c}\n// compare two arrays, return the number of differences\nfunction u(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&t(a[d])!==t(b[d]))&&g++;return g+f}function v(b){a.suppressDeprecationWarnings===!1&&\"undefined\"!=typeof console&&console.warn&&console.warn(\"Deprecation warning: \"+b)}function w(b,c){var d=!0;return i(function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,b),d){for(var e,f=[],g=0;g<arguments.length;g++){if(e=\"\",\"object\"==typeof arguments[g]){e+=\"\\n[\"+g+\"] \";for(var h in arguments[0])e+=h+\": \"+arguments[0][h]+\", \";e=e.slice(0,-2)}else e=arguments[g];f.push(e)}v(b+\"\\nArguments: \"+Array.prototype.slice.call(f).join(\"\")+\"\\n\"+(new Error).stack),d=!1}return c.apply(this,arguments)},c)}function x(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),qd[b]||(v(c),qd[b]=!0)}function y(a){return a instanceof Function||\"[object Function]\"===Object.prototype.toString.call(a)}function z(a){var b,c;for(c in a)b=a[c],y(b)?this[c]=b:this[\"_\"+c]=b;this._config=a,\n// Lenient ordinal parsing accepts just a number in addition to\n// number + (possibly) stuff coming from _ordinalParseLenient.\nthis._ordinalParseLenient=new RegExp(this._ordinalParse.source+\"|\"+/\\d{1,2}/.source)}function A(a,b){var c,e=i({},a);for(c in b)h(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},i(e[c],a[c]),i(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)h(a,c)&&!h(b,c)&&d(a[c])&&(\n// make sure changes to properties don't modify parent config\ne[c]=i({},e[c]));return e}function B(a){null!=a&&this.set(a)}function C(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return y(d)?d.call(b,c):d}function D(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function E(){return this._invalidDate}function F(a){return this._ordinal.replace(\"%d\",a)}function G(a,b,c,d){var e=this._relativeTime[c];return y(e)?e(a,b,c,d):e.replace(/%d/i,a)}function H(a,b){var c=this._relativeTime[a>0?\"future\":\"past\"];return y(c)?c(b):c.replace(/%s/i,b)}function I(a,b){var c=a.toLowerCase();zd[c]=zd[c+\"s\"]=zd[b]=a}function J(a){return\"string\"==typeof a?zd[a]||zd[a.toLowerCase()]:void 0}function K(a){var b,c,d={};for(c in a)h(a,c)&&(b=J(c),b&&(d[b]=a[c]));return d}function L(a,b){Ad[a]=b}function M(a){var b=[];for(var c in a)b.push({unit:c,priority:Ad[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function N(b,c){return function(d){return null!=d?(P(this,b,d),a.updateOffset(this,c),this):O(this,b)}}function O(a,b){return a.isValid()?a._d[\"get\"+(a._isUTC?\"UTC\":\"\")+b]():NaN}function P(a,b,c){a.isValid()&&a._d[\"set\"+(a._isUTC?\"UTC\":\"\")+b](c)}\n// MOMENTS\nfunction Q(a){return a=J(a),y(this[a])?this[a]():this}function R(a,b){if(\"object\"==typeof a){a=K(a);for(var c=M(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=J(a),y(this[a]))return this[a](b);return this}function S(a,b,c){var d=\"\"+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?\"+\":\"\":\"-\")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}\n// token:    'M'\n// padded:   ['MM', 2]\n// ordinal:  'Mo'\n// callback: function () { this.month() + 1 }\nfunction T(a,b,c,d){var e=d;\"string\"==typeof d&&(e=function(){return this[d]()}),a&&(Ed[a]=e),b&&(Ed[b[0]]=function(){return S(e.apply(this,arguments),b[1],b[2])}),c&&(Ed[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function U(a){return a.match(/\\[[\\s\\S]/)?a.replace(/^\\[|\\]$/g,\"\"):a.replace(/\\\\/g,\"\")}function V(a){var b,c,d=a.match(Bd);for(b=0,c=d.length;b<c;b++)Ed[d[b]]?d[b]=Ed[d[b]]:d[b]=U(d[b]);return function(b){var e,f=\"\";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}\n// format date using native date object\nfunction W(a,b){return a.isValid()?(b=X(b,a.localeData()),Dd[b]=Dd[b]||V(b),Dd[b](a)):a.localeData().invalidDate()}function X(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Cd.lastIndex=0;d>=0&&Cd.test(a);)a=a.replace(Cd,c),Cd.lastIndex=0,d-=1;return a}function Y(a,b,c){Wd[a]=y(b)?b:function(a,d){return a&&c?c:b}}function Z(a,b){return h(Wd,a)?Wd[a](b._strict,b._locale):new RegExp($(a))}\n// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript\nfunction $(a){return _(a.replace(\"\\\\\",\"\").replace(/\\\\(\\[)|\\\\(\\])|\\[([^\\]\\[]*)\\]|\\\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function _(a){return a.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g,\"\\\\$&\")}function aa(a,b){var c,d=b;for(\"string\"==typeof a&&(a=[a]),\"number\"==typeof b&&(d=function(a,c){c[b]=t(a)}),c=0;c<a.length;c++)Xd[a[c]]=d}function ba(a,b){aa(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function ca(a,b,c){null!=b&&h(Xd,a)&&Xd[a](b,c._a,c,a)}function da(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function ea(a,b){return a?c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||fe).test(b)?\"format\":\"standalone\"][a.month()]:this._months}function fa(a,b){return a?c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[fe.test(b)?\"format\":\"standalone\"][a.month()]:this._monthsShort}function ga(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(\n// this is not used\nthis._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=j([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,\"\").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,\"\").toLocaleLowerCase();return c?\"MMM\"===b?(e=sd.call(this._shortMonthsParse,g),e!==-1?e:null):(e=sd.call(this._longMonthsParse,g),e!==-1?e:null):\"MMM\"===b?(e=sd.call(this._shortMonthsParse,g),e!==-1?e:(e=sd.call(this._longMonthsParse,g),e!==-1?e:null)):(e=sd.call(this._longMonthsParse,g),e!==-1?e:(e=sd.call(this._shortMonthsParse,g),e!==-1?e:null))}function ha(a,b,c){var d,e,f;if(this._monthsParseExact)return ga.call(this,a,b,c);\n// TODO: add sorting\n// Sorting makes sure if one month (or abbr) is a prefix of another\n// see sorting in computeMonthsParse\nfor(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){\n// test the regex\nif(\n// make the regex if we don't have it already\ne=j([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp(\"^\"+this.months(e,\"\").replace(\".\",\"\")+\"$\",\"i\"),this._shortMonthsParse[d]=new RegExp(\"^\"+this.monthsShort(e,\"\").replace(\".\",\"\")+\"$\",\"i\")),c||this._monthsParse[d]||(f=\"^\"+this.months(e,\"\")+\"|^\"+this.monthsShort(e,\"\"),this._monthsParse[d]=new RegExp(f.replace(\".\",\"\"),\"i\")),c&&\"MMMM\"===b&&this._longMonthsParse[d].test(a))return d;if(c&&\"MMM\"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}\n// MOMENTS\nfunction ia(a,b){var c;if(!a.isValid())\n// No op\nreturn a;if(\"string\"==typeof b)if(/^\\d+$/.test(b))b=t(b);else\n// TODO: Another silent failure?\nif(b=a.localeData().monthsParse(b),\"number\"!=typeof b)return a;return c=Math.min(a.date(),da(a.year(),b)),a._d[\"set\"+(a._isUTC?\"UTC\":\"\")+\"Month\"](b,c),a}function ja(b){return null!=b?(ia(this,b),a.updateOffset(this,!0),this):O(this,\"Month\")}function ka(){return da(this.year(),this.month())}function la(a){return this._monthsParseExact?(h(this,\"_monthsRegex\")||na.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(h(this,\"_monthsShortRegex\")||(this._monthsShortRegex=ie),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function ma(a){return this._monthsParseExact?(h(this,\"_monthsRegex\")||na.call(this),a?this._monthsStrictRegex:this._monthsRegex):(h(this,\"_monthsRegex\")||(this._monthsRegex=je),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function na(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)\n// make the regex if we don't have it already\nc=j([2e3,b]),d.push(this.monthsShort(c,\"\")),e.push(this.months(c,\"\")),f.push(this.months(c,\"\")),f.push(this.monthsShort(c,\"\"));for(\n// Sorting makes sure if one month (or abbr) is a prefix of another it\n// will match the longer piece.\nd.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=_(d[b]),e[b]=_(e[b]);for(b=0;b<24;b++)f[b]=_(f[b]);this._monthsRegex=new RegExp(\"^(\"+f.join(\"|\")+\")\",\"i\"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp(\"^(\"+e.join(\"|\")+\")\",\"i\"),this._monthsShortStrictRegex=new RegExp(\"^(\"+d.join(\"|\")+\")\",\"i\")}\n// HELPERS\nfunction oa(a){return pa(a)?366:365}function pa(a){return a%4===0&&a%100!==0||a%400===0}function qa(){return pa(this.year())}function ra(a,b,c,d,e,f,g){\n//can't just apply() to create a date:\n//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply\nvar h=new Date(a,b,c,d,e,f,g);\n//the date constructor remaps years 0-99 to 1900-1999\nreturn a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function sa(a){var b=new Date(Date.UTC.apply(null,arguments));\n//the Date.UTC function remaps years 0-99 to 1900-1999\nreturn a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}\n// start-of-first-week - start-of-year\nfunction ta(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)\nd=7+b-c,\n// first-week day local weekday -- which local weekday is fwd\ne=(7+sa(a,0,d).getUTCDay()-b)%7;return-e+d-1}\n//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday\nfunction ua(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ta(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=oa(f)+j):j>oa(a)?(f=a+1,g=j-oa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function va(a,b,c){var d,e,f=ta(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+wa(e,b,c)):g>wa(a.year(),b,c)?(d=g-wa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function wa(a,b,c){var d=ta(a,b,c),e=ta(a+1,b,c);return(oa(a)-d+e)/7}\n// HELPERS\n// LOCALES\nfunction xa(a){return va(a,this._week.dow,this._week.doy).week}function ya(){return this._week.dow}function za(){return this._week.doy}\n// MOMENTS\nfunction Aa(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),\"d\")}function Ba(a){var b=va(this,1,4).week;return null==a?b:this.add(7*(a-b),\"d\")}\n// HELPERS\nfunction Ca(a,b){return\"string\"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),\"number\"==typeof a?a:null):parseInt(a,10)}function Da(a,b){return\"string\"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Ea(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?\"format\":\"standalone\"][a.day()]:this._weekdays}function Fa(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ga(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=j([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,\"\").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,\"\").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,\"\").toLocaleLowerCase();return c?\"dddd\"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:null):\"ddd\"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null):\"dddd\"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):\"ddd\"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ia(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ha.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){\n// test the regex\nif(\n// make the regex if we don't have it already\ne=j([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp(\"^\"+this.weekdays(e,\"\").replace(\".\",\".?\")+\"$\",\"i\"),this._shortWeekdaysParse[d]=new RegExp(\"^\"+this.weekdaysShort(e,\"\").replace(\".\",\".?\")+\"$\",\"i\"),this._minWeekdaysParse[d]=new RegExp(\"^\"+this.weekdaysMin(e,\"\").replace(\".\",\".?\")+\"$\",\"i\")),this._weekdaysParse[d]||(f=\"^\"+this.weekdays(e,\"\")+\"|^\"+this.weekdaysShort(e,\"\")+\"|^\"+this.weekdaysMin(e,\"\"),this._weekdaysParse[d]=new RegExp(f.replace(\".\",\"\"),\"i\")),c&&\"dddd\"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&\"ddd\"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&\"dd\"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}\n// MOMENTS\nfunction Ja(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Ca(a,this.localeData()),this.add(a-b,\"d\")):b}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,\"d\")}function La(a){if(!this.isValid())return null!=a?this:NaN;\n// behaves the same as moment#day except\n// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)\n// as a setter, sunday should belong to the previous week.\nif(null!=a){var b=Da(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Ma(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(h(this,\"_weekdaysRegex\")||(this._weekdaysRegex=pe),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Na(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(h(this,\"_weekdaysShortRegex\")||(this._weekdaysShortRegex=qe),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Oa(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(h(this,\"_weekdaysMinRegex\")||(this._weekdaysMinRegex=re),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Pa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],k=[];for(b=0;b<7;b++)\n// make the regex if we don't have it already\nc=j([2e3,1]).day(b),d=this.weekdaysMin(c,\"\"),e=this.weekdaysShort(c,\"\"),f=this.weekdays(c,\"\"),g.push(d),h.push(e),i.push(f),k.push(d),k.push(e),k.push(f);for(\n// Sorting makes sure if one weekday (or abbr) is a prefix of another it\n// will match the longer piece.\ng.sort(a),h.sort(a),i.sort(a),k.sort(a),b=0;b<7;b++)h[b]=_(h[b]),i[b]=_(i[b]),k[b]=_(k[b]);this._weekdaysRegex=new RegExp(\"^(\"+k.join(\"|\")+\")\",\"i\"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp(\"^(\"+i.join(\"|\")+\")\",\"i\"),this._weekdaysShortStrictRegex=new RegExp(\"^(\"+h.join(\"|\")+\")\",\"i\"),this._weekdaysMinStrictRegex=new RegExp(\"^(\"+g.join(\"|\")+\")\",\"i\")}\n// FORMATTING\nfunction Qa(){return this.hours()%12||12}function Ra(){return this.hours()||24}function Sa(a,b){T(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}\n// PARSING\nfunction Ta(a,b){return b._meridiemParse}\n// LOCALES\nfunction Ua(a){\n// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays\n// Using charAt should be more compatible.\nreturn\"p\"===(a+\"\").toLowerCase().charAt(0)}function Va(a,b,c){return a>11?c?\"pm\":\"PM\":c?\"am\":\"AM\"}function Wa(a){return a?a.toLowerCase().replace(\"_\",\"-\"):a}\n// pick the locale from the array\n// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each\n// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root\nfunction Xa(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Wa(a[f]).split(\"-\"),b=e.length,c=Wa(a[f+1]),c=c?c.split(\"-\"):null;b>0;){if(d=Ya(e.slice(0,b).join(\"-\")))return d;if(c&&c.length>=b&&u(e,c,!0)>=b-1)\n//the next array item is better than a shallower substring of this one\nbreak;b--}f++}return null}function Ya(a){var b=null;\n// TODO: Find a better way to register and load all the locales in Node\nif(!we[a]&&\"undefined\"!=typeof module&&module&&module.exports)try{b=se._abbr,require(\"./locale/\"+a),\n// because defineLocale currently also sets the global locale, we\n// want to undo that for lazy loaded locales\nZa(b)}catch(a){}return we[a]}\n// This function will load locale and then set the global locale.  If\n// no arguments are passed in, it will simply return the current global\n// locale key.\nfunction Za(a,b){var c;\n// moment.duration._locale = moment._locale = data;\nreturn a&&(c=o(b)?ab(a):$a(a,b),c&&(se=c)),se._abbr}function $a(a,b){if(null!==b){var c=ve;\n// treat as if there is no base config\n// backwards compat for now: also set the locale\nreturn b.abbr=a,null!=we[a]?(x(\"defineLocaleOverride\",\"use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info.\"),c=we[a]._config):null!=b.parentLocale&&(null!=we[b.parentLocale]?c=we[b.parentLocale]._config:x(\"parentLocaleUndefined\",\"specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/\")),we[a]=new B(A(c,b)),Za(a),we[a]}\n// useful for testing\nreturn delete we[a],null}function _a(a,b){if(null!=b){var c,d=ve;\n// MERGE\nnull!=we[a]&&(d=we[a]._config),b=A(d,b),c=new B(b),c.parentLocale=we[a],we[a]=c,\n// backwards compat for now: also set the locale\nZa(a)}else\n// pass null for config to unupdate, useful for tests\nnull!=we[a]&&(null!=we[a].parentLocale?we[a]=we[a].parentLocale:null!=we[a]&&delete we[a]);return we[a]}\n// returns locale data\nfunction ab(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return se;if(!c(a)){if(\n//short-circuit everything else\nb=Ya(a))return b;a=[a]}return Xa(a)}function bb(){return rd(we)}function cb(a){var b,c=a._a;return c&&l(a).overflow===-2&&(b=c[Zd]<0||c[Zd]>11?Zd:c[$d]<1||c[$d]>da(c[Yd],c[Zd])?$d:c[_d]<0||c[_d]>24||24===c[_d]&&(0!==c[ae]||0!==c[be]||0!==c[ce])?_d:c[ae]<0||c[ae]>59?ae:c[be]<0||c[be]>59?be:c[ce]<0||c[ce]>999?ce:-1,l(a)._overflowDayOfYear&&(b<Yd||b>$d)&&(b=$d),l(a)._overflowWeeks&&b===-1&&(b=de),l(a)._overflowWeekday&&b===-1&&(b=ee),l(a).overflow=b),a}\n// date from iso format\nfunction db(a){var b,c,d,e,f,g,h=a._i,i=xe.exec(h)||ye.exec(h);if(i){for(l(a).iso=!0,b=0,c=Ae.length;b<c;b++)if(Ae[b][1].exec(i[1])){e=Ae[b][0],d=Ae[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Be.length;b<c;b++)if(Be[b][1].exec(i[3])){\n// match[2] should be 'T' or space\nf=(i[2]||\" \")+Be[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!ze.exec(i[4]))return void(a._isValid=!1);g=\"Z\"}a._f=e+(f||\"\")+(g||\"\"),jb(a)}else a._isValid=!1}\n// date from iso format or fallback\nfunction eb(b){var c=Ce.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(db(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}\n// Pick the first defined of two or three arguments.\nfunction fb(a,b,c){return null!=a?a:null!=b?b:c}function gb(b){\n// hooks is actually the exported moment object\nvar c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}\n// convert an array to a date.\n// the array should mirror the parameters below\n// note: all values past the year are optional and will default to the lowest possible value.\n// [year, month, day , hour, minute, second, millisecond]\nfunction hb(a){var b,c,d,e,f=[];if(!a._d){\n// Default to current date.\n// * if no year, month, day of month are given, default to today\n// * if day of month is given, default month and year\n// * if month is given, default only year\n// * if year is given, don't default anything\nfor(d=gb(a),\n//compute day of the year from weeks and weekdays\na._w&&null==a._a[$d]&&null==a._a[Zd]&&ib(a),\n//if the day of the year is set, figure out what it is\na._dayOfYear&&(e=fb(a._a[Yd],d[Yd]),a._dayOfYear>oa(e)&&(l(a)._overflowDayOfYear=!0),c=sa(e,0,a._dayOfYear),a._a[Zd]=c.getUTCMonth(),a._a[$d]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];\n// Zero out whatever was not defaulted, including time\nfor(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];\n// Check for 24:00:00.000\n24===a._a[_d]&&0===a._a[ae]&&0===a._a[be]&&0===a._a[ce]&&(a._nextDay=!0,a._a[_d]=0),a._d=(a._useUTC?sa:ra).apply(null,f),\n// Apply timezone offset from input. The actual utcOffset can be changed\n// with parseZone.\nnull!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[_d]=24)}}function ib(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,\n// TODO: We need to take the current isoWeekYear, but that depends on\n// how we interpret now (local, utc, fixed offset). So create\n// a now version of current config (take local/utc/offset flags, and\n// create now).\nc=fb(b.GG,a._a[Yd],va(rb(),1,4).year),d=fb(b.W,1),e=fb(b.E,1),(e<1||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=fb(b.gg,a._a[Yd],va(rb(),f,g).year),d=fb(b.w,1),null!=b.d?(\n// weekday -- low day numbers are considered next week\ne=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(\n// local weekday -- counting starts from begining of week\ne=b.e+f,(b.e<0||b.e>6)&&(i=!0)):\n// default to begining of week\ne=f),d<1||d>wa(c,f,g)?l(a)._overflowWeeks=!0:null!=i?l(a)._overflowWeekday=!0:(h=ua(c,d,e,f,g),a._a[Yd]=h.year,a._dayOfYear=h.dayOfYear)}\n// date from string and format string\nfunction jb(b){\n// TODO: Move this to another part of the creation flow to prevent circular deps\nif(b._f===a.ISO_8601)return void db(b);b._a=[],l(b).empty=!0;\n// This array is used to make a Date, either with `new Date` or `Date.UTC`\nvar c,d,e,f,g,h=\"\"+b._i,i=h.length,j=0;for(e=X(b._f,b._locale).match(Bd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(Z(f,b))||[])[0],\n// console.log('token', token, 'parsedInput', parsedInput,\n//         'regex', getParseRegexForToken(token, config));\nd&&(g=h.substr(0,h.indexOf(d)),g.length>0&&l(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),\n// don't parse if it's not a known token\nEd[f]?(d?l(b).empty=!1:l(b).unusedTokens.push(f),ca(f,d,b)):b._strict&&!d&&l(b).unusedTokens.push(f);\n// add remaining unparsed input length to the string\nl(b).charsLeftOver=i-j,h.length>0&&l(b).unusedInput.push(h),\n// clear _12h flag if hour is <= 12\nb._a[_d]<=12&&l(b).bigHour===!0&&b._a[_d]>0&&(l(b).bigHour=void 0),l(b).parsedDateParts=b._a.slice(0),l(b).meridiem=b._meridiem,\n// handle meridiem\nb._a[_d]=kb(b._locale,b._a[_d],b._meridiem),hb(b),cb(b)}function kb(a,b,c){var d;\n// Fallback\nreturn null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}\n// date from string and array of format strings\nfunction lb(a){var b,c,d,e,f;if(0===a._f.length)return l(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=p({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],jb(b),m(b)&&(\n// if there is any input that was not parsed add a penalty for that format\nf+=l(b).charsLeftOver,\n//or tokens\nf+=10*l(b).unusedTokens.length,l(b).score=f,(null==d||f<d)&&(d=f,c=b));i(a,c||b)}function mb(a){if(!a._d){var b=K(a._i);a._a=g([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),hb(a)}}function nb(a){var b=new q(cb(ob(a)));\n// Adding is smart enough around DST\nreturn b._nextDay&&(b.add(1,\"d\"),b._nextDay=void 0),b}function ob(a){var b=a._i,d=a._f;return a._locale=a._locale||ab(a._l),null===b||void 0===d&&\"\"===b?n({nullInput:!0}):(\"string\"==typeof b&&(a._i=b=a._locale.preparse(b)),r(b)?new q(cb(b)):(c(d)?lb(a):f(b)?a._d=b:d?jb(a):pb(a),m(a)||(a._d=null),a))}function pb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):f(d)?b._d=new Date(d.valueOf()):\"string\"==typeof d?eb(b):c(d)?(b._a=g(d.slice(0),function(a){return parseInt(a,10)}),hb(b)):\"object\"==typeof d?mb(b):\"number\"==typeof d?\n// from milliseconds\nb._d=new Date(d):a.createFromInputFallback(b)}function qb(a,b,f,g,h){var i={};\n// object construction must be done this way.\n// https://github.com/moment/moment/issues/1423\nreturn\"boolean\"==typeof f&&(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,nb(i)}function rb(a,b,c,d){return qb(a,b,c,d,!1)}\n// Pick a moment m from moments so that m[fn](other) is true for all\n// other. This relies on the function fn to be transitive.\n//\n// moments should either be an array of moment objects or an array, whose\n// first element is an array of moment objects.\nfunction sb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return rb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}\n// TODO: Use [].sort instead?\nfunction tb(){var a=[].slice.call(arguments,0);return sb(\"isBefore\",a)}function ub(){var a=[].slice.call(arguments,0);return sb(\"isAfter\",a)}function vb(a){var b=K(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;\n// representation for dateAddRemove\nthis._milliseconds=+k+1e3*j+// 1000\n6e4*i+// 1000 * 60\n1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978\n// Because of dateAddRemove treats 24 hours as different from a\n// day when working around DST, we need to store them separately\nthis._days=+g+7*f,\n// It is impossible translate months into days without knowing\n// which months you are are talking about, so we have to store\n// it separately.\nthis._months=+e+3*d+12*c,this._data={},this._locale=ab(),this._bubble()}function wb(a){return a instanceof vb}function xb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}\n// FORMATTING\nfunction yb(a,b){T(a,0,0,function(){var a=this.utcOffset(),c=\"+\";return a<0&&(a=-a,c=\"-\"),c+S(~~(a/60),2)+b+S(~~a%60,2)})}function zb(a,b){var c=(b||\"\").match(a)||[],d=c[c.length-1]||[],e=(d+\"\").match(Ge)||[\"-\",0,0],f=+(60*e[1])+t(e[2]);return\"+\"===e[0]?f:-f}\n// Return a moment from input, that is local/utc/zone equivalent to model.\nfunction Ab(b,c){var d,e;\n// Use low-level api, because this fn is low-level api.\nreturn c._isUTC?(d=c.clone(),e=(r(b)||f(b)?b.valueOf():rb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):rb(b).local()}function Bb(a){\n// On Firefox.24 Date#getTimezoneOffset returns a floating point.\n// https://github.com/moment/moment/pull/1871\nreturn 15*-Math.round(a._d.getTimezoneOffset()/15)}\n// MOMENTS\n// keepLocalTime = true means only change the timezone, without\n// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->\n// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset\n// +0200, so we adjust the time as needed, to be valid.\n//\n// Keeping the time actually adds/subtracts (one hour)\n// from the actual represented time. That is why we call updateOffset\n// a second time. In case it wants us to change the offset again\n// _changeInProgress == true case, then we have to adjust, because\n// there is no such time in the given timezone.\nfunction Cb(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?(\"string\"==typeof b?b=zb(Td,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Bb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,\"m\"),e!==b&&(!c||this._changeInProgress?Sb(this,Nb(b-e,\"m\"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Bb(this):null!=b?this:NaN}function Db(a,b){return null!=a?(\"string\"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Eb(a){return this.utcOffset(0,a)}function Fb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Bb(this),\"m\")),this}function Gb(){if(this._tzm)this.utcOffset(this._tzm);else if(\"string\"==typeof this._i){var a=zb(Sd,this._i);0===a?this.utcOffset(0,!0):this.utcOffset(zb(Sd,this._i))}return this}function Hb(a){return!!this.isValid()&&(a=a?rb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Ib(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Jb(){if(!o(this._isDSTShifted))return this._isDSTShifted;var a={};if(p(a,this),a=ob(a),a._a){var b=a._isUTC?j(a._a):rb(a._a);this._isDSTShifted=this.isValid()&&u(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Kb(){return!!this.isValid()&&!this._isUTC}function Lb(){return!!this.isValid()&&this._isUTC}function Mb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Nb(a,b){var c,d,e,f=a,\n// matching against regexp is expensive, do it on demand\ng=null;// checks for null or undefined\nreturn wb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:\"number\"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(g=He.exec(a))?(c=\"-\"===g[1]?-1:1,f={y:0,d:t(g[$d])*c,h:t(g[_d])*c,m:t(g[ae])*c,s:t(g[be])*c,ms:t(xb(1e3*g[ce]))*c}):(g=Ie.exec(a))?(c=\"-\"===g[1]?-1:1,f={y:Ob(g[2],c),M:Ob(g[3],c),w:Ob(g[4],c),d:Ob(g[5],c),h:Ob(g[6],c),m:Ob(g[7],c),s:Ob(g[8],c)}):null==f?f={}:\"object\"==typeof f&&(\"from\"in f||\"to\"in f)&&(e=Qb(rb(f.from),rb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new vb(f),wb(a)&&h(a,\"_locale\")&&(d._locale=a._locale),d}function Ob(a,b){\n// We'd normally use ~~inp for this, but unfortunately it also\n// converts floats to ints.\n// inp may be undefined, so careful calling replace on it.\nvar c=a&&parseFloat(a.replace(\",\",\".\"));\n// apply sign while we're at it\nreturn(isNaN(c)?0:c)*b}function Pb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,\"M\").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,\"M\"),c}function Qb(a,b){var c;return a.isValid()&&b.isValid()?(b=Ab(b,a),a.isBefore(b)?c=Pb(a,b):(c=Pb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}\n// TODO: remove 'name' arg after deprecation is removed\nfunction Rb(a,b){return function(c,d){var e,f;\n//invert the arguments, but complain about it\nreturn null===d||isNaN(+d)||(x(b,\"moment().\"+b+\"(period, number) is deprecated. Please use moment().\"+b+\"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.\"),f=c,c=d,d=f),c=\"string\"==typeof c?+c:c,e=Nb(c,d),Sb(this,e,a),this}}function Sb(b,c,d,e){var f=c._milliseconds,g=xb(c._days),h=xb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&P(b,\"Date\",O(b,\"Date\")+g*d),h&&ia(b,O(b,\"Month\")+h*d),e&&a.updateOffset(b,g||h))}function Tb(a,b){var c=a.diff(b,\"days\",!0);return c<-6?\"sameElse\":c<-1?\"lastWeek\":c<0?\"lastDay\":c<1?\"sameDay\":c<2?\"nextDay\":c<7?\"nextWeek\":\"sameElse\"}function Ub(b,c){\n// We want to compare the start of today, vs this.\n// Getting start-of-today depends on whether we're local/utc/offset or not.\nvar d=b||rb(),e=Ab(d,this).startOf(\"day\"),f=a.calendarFormat(this,e)||\"sameElse\",g=c&&(y(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,rb(d)))}function Vb(){return new q(this)}function Wb(a,b){var c=r(a)?a:rb(a);return!(!this.isValid()||!c.isValid())&&(b=J(o(b)?\"millisecond\":b),\"millisecond\"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function Xb(a,b){var c=r(a)?a:rb(a);return!(!this.isValid()||!c.isValid())&&(b=J(o(b)?\"millisecond\":b),\"millisecond\"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function Yb(a,b,c,d){return d=d||\"()\",(\"(\"===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(\")\"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function Zb(a,b){var c,d=r(a)?a:rb(a);return!(!this.isValid()||!d.isValid())&&(b=J(b||\"millisecond\"),\"millisecond\"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function $b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function _b(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function ac(a,b,c){var d,e,f,g;// 1000\n// 1000 * 60\n// 1000 * 60 * 60\n// 1000 * 60 * 60 * 24, negate dst\n// 1000 * 60 * 60 * 24 * 7, negate dst\nreturn this.isValid()?(d=Ab(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=J(b),\"year\"===b||\"month\"===b||\"quarter\"===b?(g=bc(this,d),\"quarter\"===b?g/=3:\"year\"===b&&(g/=12)):(f=this-d,g=\"second\"===b?f/1e3:\"minute\"===b?f/6e4:\"hour\"===b?f/36e5:\"day\"===b?(f-e)/864e5:\"week\"===b?(f-e)/6048e5:f),c?g:s(g)):NaN):NaN}function bc(a,b){\n// difference in months\nvar c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),\n// b is in (anchor - 1 month, anchor + 1 month)\nf=a.clone().add(e,\"months\");\n//check for negative zero, return zero if negative zero\n// linear across the month\n// linear across the month\nreturn b-f<0?(c=a.clone().add(e-1,\"months\"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,\"months\"),d=(b-f)/(c-f)),-(e+d)||0}function cc(){return this.clone().locale(\"en\").format(\"ddd MMM DD YYYY HH:mm:ss [GMT]ZZ\")}function dc(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?y(Date.prototype.toISOString)?this.toDate().toISOString():W(a,\"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]\"):W(a,\"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]\")}function ec(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=W(this,b);return this.localeData().postformat(c)}function fc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Nb({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function gc(a){return this.from(rb(),a)}function hc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Nb({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.to(rb(),a)}\n// If passed a locale key, it will set the locale for this\n// instance.  Otherwise, it will return the locale configuration\n// variables for this instance.\nfunction jc(a){var b;return void 0===a?this._locale._abbr:(b=ab(a),null!=b&&(this._locale=b),this)}function kc(){return this._locale}function lc(a){\n// the following switch intentionally omits break keywords\n// to utilize falling through the cases.\nswitch(a=J(a)){case\"year\":this.month(0);/* falls through */\ncase\"quarter\":case\"month\":this.date(1);/* falls through */\ncase\"week\":case\"isoWeek\":case\"day\":case\"date\":this.hours(0);/* falls through */\ncase\"hour\":this.minutes(0);/* falls through */\ncase\"minute\":this.seconds(0);/* falls through */\ncase\"second\":this.milliseconds(0)}\n// weeks are a special case\n// quarters are also special\nreturn\"week\"===a&&this.weekday(0),\"isoWeek\"===a&&this.isoWeekday(1),\"quarter\"===a&&this.month(3*Math.floor(this.month()/3)),this}function mc(a){\n// 'date' is an alias for 'day', so it should be considered as such.\nreturn a=J(a),void 0===a||\"millisecond\"===a?this:(\"date\"===a&&(a=\"day\"),this.startOf(a).add(1,\"isoWeek\"===a?\"week\":a).subtract(1,\"ms\"))}function nc(){return this._d.valueOf()-6e4*(this._offset||0)}function oc(){return Math.floor(this.valueOf()/1e3)}function pc(){return new Date(this.valueOf())}function qc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function rc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function sc(){\n// new Date(NaN).toJSON() === null\nreturn this.isValid()?this.toISOString():null}function tc(){return m(this)}function uc(){return i({},l(this))}function vc(){return l(this).overflow}function wc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function xc(a,b){T(0,[a,a.length],0,b)}\n// MOMENTS\nfunction yc(a){return Cc.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function zc(a){return Cc.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Ac(){return wa(this.year(),1,4)}function Bc(){var a=this.localeData()._week;return wa(this.year(),a.dow,a.doy)}function Cc(a,b,c,d,e){var f;return null==a?va(this,d,e).year:(f=wa(a,d,e),b>f&&(b=f),Dc.call(this,a,b,c,d,e))}function Dc(a,b,c,d,e){var f=ua(a,b,c,d,e),g=sa(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}\n// MOMENTS\nfunction Ec(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}\n// HELPERS\n// MOMENTS\nfunction Fc(a){var b=Math.round((this.clone().startOf(\"day\")-this.clone().startOf(\"year\"))/864e5)+1;return null==a?b:this.add(a-b,\"d\")}function Gc(a,b){b[ce]=t(1e3*(\"0.\"+a))}\n// MOMENTS\nfunction Hc(){return this._isUTC?\"UTC\":\"\"}function Ic(){return this._isUTC?\"Coordinated Universal Time\":\"\"}function Jc(a){return rb(1e3*a)}function Kc(){return rb.apply(null,arguments).parseZone()}function Lc(a){return a}function Mc(a,b,c,d){var e=ab(),f=j().set(d,b);return e[c](f,a)}function Nc(a,b,c){if(\"number\"==typeof a&&(b=a,a=void 0),a=a||\"\",null!=b)return Mc(a,b,c,\"month\");var d,e=[];for(d=0;d<12;d++)e[d]=Mc(a,d,c,\"month\");return e}\n// ()\n// (5)\n// (fmt, 5)\n// (fmt)\n// (true)\n// (true, 5)\n// (true, fmt, 5)\n// (true, fmt)\nfunction Oc(a,b,c,d){\"boolean\"==typeof a?(\"number\"==typeof b&&(c=b,b=void 0),b=b||\"\"):(b=a,c=b,a=!1,\"number\"==typeof b&&(c=b,b=void 0),b=b||\"\");var e=ab(),f=a?e._week.dow:0;if(null!=c)return Mc(b,(c+f)%7,d,\"day\");var g,h=[];for(g=0;g<7;g++)h[g]=Mc(b,(g+f)%7,d,\"day\");return h}function Pc(a,b){return Nc(a,b,\"months\")}function Qc(a,b){return Nc(a,b,\"monthsShort\")}function Rc(a,b,c){return Oc(a,b,c,\"weekdays\")}function Sc(a,b,c){return Oc(a,b,c,\"weekdaysShort\")}function Tc(a,b,c){return Oc(a,b,c,\"weekdaysMin\")}function Uc(){var a=this._data;return this._milliseconds=Ue(this._milliseconds),this._days=Ue(this._days),this._months=Ue(this._months),a.milliseconds=Ue(a.milliseconds),a.seconds=Ue(a.seconds),a.minutes=Ue(a.minutes),a.hours=Ue(a.hours),a.months=Ue(a.months),a.years=Ue(a.years),this}function Vc(a,b,c,d){var e=Nb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}\n// supports only 2.0-style add(1, 's') or add(duration)\nfunction Wc(a,b){return Vc(this,a,b,1)}\n// supports only 2.0-style subtract(1, 's') or subtract(duration)\nfunction Xc(a,b){return Vc(this,a,b,-1)}function Yc(a){return a<0?Math.floor(a):Math.ceil(a)}function Zc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;\n// if we have a mix of positive and negative values, bubble down first\n// check: https://github.com/moment/moment/issues/2166\n// The following code bubbles up values, see the tests for\n// examples of what that means.\n// convert days to months\n// 12 months -> 1 year\nreturn f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*Yc(_c(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=s(f/1e3),i.seconds=a%60,b=s(a/60),i.minutes=b%60,c=s(b/60),i.hours=c%24,g+=s(c/24),e=s($c(g)),h+=e,g-=Yc(_c(e)),d=s(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function $c(a){\n// 400 years have 146097 days (taking into account leap year rules)\n// 400 years have 12 months === 4800\nreturn 4800*a/146097}function _c(a){\n// the reverse of daysToMonths\nreturn 146097*a/4800}function ad(a){var b,c,d=this._milliseconds;if(a=J(a),\"month\"===a||\"year\"===a)return b=this._days+d/864e5,c=this._months+$c(b),\"month\"===a?c:c/12;switch(\n// handle milliseconds separately because of floating point math errors (issue #1867)\nb=this._days+Math.round(_c(this._months)),a){case\"week\":return b/7+d/6048e5;case\"day\":return b+d/864e5;case\"hour\":return 24*b+d/36e5;case\"minute\":return 1440*b+d/6e4;case\"second\":return 86400*b+d/1e3;\n// Math.floor prevents floating point math errors here\ncase\"millisecond\":return Math.floor(864e5*b)+d;default:throw new Error(\"Unknown unit \"+a)}}\n// TODO: Use this.as('ms')?\nfunction bd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*t(this._months/12)}function cd(a){return function(){return this.as(a)}}function dd(a){return a=J(a),this[a+\"s\"]()}function ed(a){return function(){return this._data[a]}}function fd(){return s(this.days()/7)}\n// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize\nfunction gd(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function hd(a,b,c){var d=Nb(a).abs(),e=jf(d.as(\"s\")),f=jf(d.as(\"m\")),g=jf(d.as(\"h\")),h=jf(d.as(\"d\")),i=jf(d.as(\"M\")),j=jf(d.as(\"y\")),k=e<kf.s&&[\"s\",e]||f<=1&&[\"m\"]||f<kf.m&&[\"mm\",f]||g<=1&&[\"h\"]||g<kf.h&&[\"hh\",g]||h<=1&&[\"d\"]||h<kf.d&&[\"dd\",h]||i<=1&&[\"M\"]||i<kf.M&&[\"MM\",i]||j<=1&&[\"y\"]||[\"yy\",j];return k[2]=b,k[3]=+a>0,k[4]=c,gd.apply(null,k)}\n// This function allows you to set the rounding function for relative time strings\nfunction id(a){return void 0===a?jf:\"function\"==typeof a&&(jf=a,!0)}\n// This function allows you to set a threshold for relative time strings\nfunction jd(a,b){return void 0!==kf[a]&&(void 0===b?kf[a]:(kf[a]=b,!0))}function kd(a){var b=this.localeData(),c=hd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function ld(){\n// for ISO strings we do not use the normal bubbling rules:\n//  * milliseconds bubble up until they become hours\n//  * days do not bubble at all\n//  * months bubble up until they become years\n// This is because there is no context-free conversion between hours and days\n// (think of clock changes)\n// and also not between days and months (28-31 days per month)\nvar a,b,c,d=lf(this._milliseconds)/1e3,e=lf(this._days),f=lf(this._months);\n// 3600 seconds -> 60 minutes -> 1 hour\na=s(d/60),b=s(a/60),d%=60,a%=60,\n// 12 months -> 1 year\nc=s(f/12),f%=12;\n// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js\nvar g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?\"-\":\"\")+\"P\"+(g?g+\"Y\":\"\")+(h?h+\"M\":\"\")+(i?i+\"D\":\"\")+(j||k||l?\"T\":\"\")+(j?j+\"H\":\"\")+(k?k+\"M\":\"\")+(l?l+\"S\":\"\"):\"P0D\"}var md,nd;nd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};\n// Plugins that add properties should also add the key here (null value),\n// so we can properly clone ourselves.\nvar od=a.momentProperties=[],pd=!1,qd={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var rd;rd=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)h(a,b)&&c.push(b);return c};var sd,td={sameDay:\"[Today at] LT\",nextDay:\"[Tomorrow at] LT\",nextWeek:\"dddd [at] LT\",lastDay:\"[Yesterday at] LT\",lastWeek:\"[Last] dddd [at] LT\",sameElse:\"L\"},ud={LTS:\"h:mm:ss A\",LT:\"h:mm A\",L:\"MM/DD/YYYY\",LL:\"MMMM D, YYYY\",LLL:\"MMMM D, YYYY h:mm A\",LLLL:\"dddd, MMMM D, YYYY h:mm A\"},vd=\"Invalid date\",wd=\"%d\",xd=/\\d{1,2}/,yd={future:\"in %s\",past:\"%s ago\",s:\"a few seconds\",m:\"a minute\",mm:\"%d minutes\",h:\"an hour\",hh:\"%d hours\",d:\"a day\",dd:\"%d days\",M:\"a month\",MM:\"%d months\",y:\"a year\",yy:\"%d years\"},zd={},Ad={},Bd=/(\\[[^\\[]*\\])|(\\\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Cd=/(\\[[^\\[]*\\])|(\\\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Dd={},Ed={},Fd=/\\d/,Gd=/\\d\\d/,Hd=/\\d{3}/,Id=/\\d{4}/,Jd=/[+-]?\\d{6}/,Kd=/\\d\\d?/,Ld=/\\d\\d\\d\\d?/,Md=/\\d\\d\\d\\d\\d\\d?/,Nd=/\\d{1,3}/,Od=/\\d{1,4}/,Pd=/[+-]?\\d{1,6}/,Qd=/\\d+/,Rd=/[+-]?\\d+/,Sd=/Z|[+-]\\d\\d:?\\d\\d/gi,Td=/Z|[+-]\\d\\d(?::?\\d\\d)?/gi,Ud=/[+-]?\\d+(\\.\\d{1,3})?/,Vd=/[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i,Wd={},Xd={},Yd=0,Zd=1,$d=2,_d=3,ae=4,be=5,ce=6,de=7,ee=8;sd=Array.prototype.indexOf?Array.prototype.indexOf:function(a){\n// I know\nvar b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1},\n// FORMATTING\nT(\"M\",[\"MM\",2],\"Mo\",function(){return this.month()+1}),T(\"MMM\",0,0,function(a){return this.localeData().monthsShort(this,a)}),T(\"MMMM\",0,0,function(a){return this.localeData().months(this,a)}),\n// ALIASES\nI(\"month\",\"M\"),\n// PRIORITY\nL(\"month\",8),\n// PARSING\nY(\"M\",Kd),Y(\"MM\",Kd,Gd),Y(\"MMM\",function(a,b){return b.monthsShortRegex(a)}),Y(\"MMMM\",function(a,b){return b.monthsRegex(a)}),aa([\"M\",\"MM\"],function(a,b){b[Zd]=t(a)-1}),aa([\"MMM\",\"MMMM\"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);\n// if we didn't find a month name, mark the date as invalid.\nnull!=e?b[Zd]=e:l(c).invalidMonth=a});\n// LOCALES\nvar fe=/D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?/,ge=\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),he=\"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec\".split(\"_\"),ie=Vd,je=Vd;\n// FORMATTING\nT(\"Y\",0,0,function(){var a=this.year();return a<=9999?\"\"+a:\"+\"+a}),T(0,[\"YY\",2],0,function(){return this.year()%100}),T(0,[\"YYYY\",4],0,\"year\"),T(0,[\"YYYYY\",5],0,\"year\"),T(0,[\"YYYYYY\",6,!0],0,\"year\"),\n// ALIASES\nI(\"year\",\"y\"),\n// PRIORITIES\nL(\"year\",1),\n// PARSING\nY(\"Y\",Rd),Y(\"YY\",Kd,Gd),Y(\"YYYY\",Od,Id),Y(\"YYYYY\",Pd,Jd),Y(\"YYYYYY\",Pd,Jd),aa([\"YYYYY\",\"YYYYYY\"],Yd),aa(\"YYYY\",function(b,c){c[Yd]=2===b.length?a.parseTwoDigitYear(b):t(b)}),aa(\"YY\",function(b,c){c[Yd]=a.parseTwoDigitYear(b)}),aa(\"Y\",function(a,b){b[Yd]=parseInt(a,10)}),\n// HOOKS\na.parseTwoDigitYear=function(a){return t(a)+(t(a)>68?1900:2e3)};\n// MOMENTS\nvar ke=N(\"FullYear\",!0);\n// FORMATTING\nT(\"w\",[\"ww\",2],\"wo\",\"week\"),T(\"W\",[\"WW\",2],\"Wo\",\"isoWeek\"),\n// ALIASES\nI(\"week\",\"w\"),I(\"isoWeek\",\"W\"),\n// PRIORITIES\nL(\"week\",5),L(\"isoWeek\",5),\n// PARSING\nY(\"w\",Kd),Y(\"ww\",Kd,Gd),Y(\"W\",Kd),Y(\"WW\",Kd,Gd),ba([\"w\",\"ww\",\"W\",\"WW\"],function(a,b,c,d){b[d.substr(0,1)]=t(a)});var le={dow:0,// Sunday is the first day of the week.\ndoy:6};\n// FORMATTING\nT(\"d\",0,\"do\",\"day\"),T(\"dd\",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),T(\"ddd\",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),T(\"dddd\",0,0,function(a){return this.localeData().weekdays(this,a)}),T(\"e\",0,0,\"weekday\"),T(\"E\",0,0,\"isoWeekday\"),\n// ALIASES\nI(\"day\",\"d\"),I(\"weekday\",\"e\"),I(\"isoWeekday\",\"E\"),\n// PRIORITY\nL(\"day\",11),L(\"weekday\",11),L(\"isoWeekday\",11),\n// PARSING\nY(\"d\",Kd),Y(\"e\",Kd),Y(\"E\",Kd),Y(\"dd\",function(a,b){return b.weekdaysMinRegex(a)}),Y(\"ddd\",function(a,b){return b.weekdaysShortRegex(a)}),Y(\"dddd\",function(a,b){return b.weekdaysRegex(a)}),ba([\"dd\",\"ddd\",\"dddd\"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);\n// if we didn't get a weekday name, mark the date as invalid\nnull!=e?b.d=e:l(c).invalidWeekday=a}),ba([\"d\",\"e\",\"E\"],function(a,b,c,d){b[d]=t(a)});\n// LOCALES\nvar me=\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),ne=\"Sun_Mon_Tue_Wed_Thu_Fri_Sat\".split(\"_\"),oe=\"Su_Mo_Tu_We_Th_Fr_Sa\".split(\"_\"),pe=Vd,qe=Vd,re=Vd;T(\"H\",[\"HH\",2],0,\"hour\"),T(\"h\",[\"hh\",2],0,Qa),T(\"k\",[\"kk\",2],0,Ra),T(\"hmm\",0,0,function(){return\"\"+Qa.apply(this)+S(this.minutes(),2)}),T(\"hmmss\",0,0,function(){return\"\"+Qa.apply(this)+S(this.minutes(),2)+S(this.seconds(),2)}),T(\"Hmm\",0,0,function(){return\"\"+this.hours()+S(this.minutes(),2)}),T(\"Hmmss\",0,0,function(){return\"\"+this.hours()+S(this.minutes(),2)+S(this.seconds(),2)}),Sa(\"a\",!0),Sa(\"A\",!1),\n// ALIASES\nI(\"hour\",\"h\"),\n// PRIORITY\nL(\"hour\",13),Y(\"a\",Ta),Y(\"A\",Ta),Y(\"H\",Kd),Y(\"h\",Kd),Y(\"HH\",Kd,Gd),Y(\"hh\",Kd,Gd),Y(\"hmm\",Ld),Y(\"hmmss\",Md),Y(\"Hmm\",Ld),Y(\"Hmmss\",Md),aa([\"H\",\"HH\"],_d),aa([\"a\",\"A\"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),aa([\"h\",\"hh\"],function(a,b,c){b[_d]=t(a),l(c).bigHour=!0}),aa(\"hmm\",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d)),l(c).bigHour=!0}),aa(\"hmmss\",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e)),l(c).bigHour=!0}),aa(\"Hmm\",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d))}),aa(\"Hmmss\",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e))});var se,te=/[ap]\\.?m?\\.?/i,ue=N(\"Hours\",!0),ve={calendar:td,longDateFormat:ud,invalidDate:vd,ordinal:wd,ordinalParse:xd,relativeTime:yd,months:ge,monthsShort:he,week:le,weekdays:me,weekdaysMin:oe,weekdaysShort:ne,meridiemParse:te},we={},xe=/^\\s*((?:[+-]\\d{6}|\\d{4})-(?:\\d\\d-\\d\\d|W\\d\\d-\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?::\\d\\d(?::\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?/,ye=/^\\s*((?:[+-]\\d{6}|\\d{4})(?:\\d\\d\\d\\d|W\\d\\d\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?:\\d\\d(?:\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?/,ze=/Z|[+-]\\d\\d(?::?\\d\\d)?/,Ae=[[\"YYYYYY-MM-DD\",/[+-]\\d{6}-\\d\\d-\\d\\d/],[\"YYYY-MM-DD\",/\\d{4}-\\d\\d-\\d\\d/],[\"GGGG-[W]WW-E\",/\\d{4}-W\\d\\d-\\d/],[\"GGGG-[W]WW\",/\\d{4}-W\\d\\d/,!1],[\"YYYY-DDD\",/\\d{4}-\\d{3}/],[\"YYYY-MM\",/\\d{4}-\\d\\d/,!1],[\"YYYYYYMMDD\",/[+-]\\d{10}/],[\"YYYYMMDD\",/\\d{8}/],\n// YYYYMM is NOT allowed by the standard\n[\"GGGG[W]WWE\",/\\d{4}W\\d{3}/],[\"GGGG[W]WW\",/\\d{4}W\\d{2}/,!1],[\"YYYYDDD\",/\\d{7}/]],Be=[[\"HH:mm:ss.SSSS\",/\\d\\d:\\d\\d:\\d\\d\\.\\d+/],[\"HH:mm:ss,SSSS\",/\\d\\d:\\d\\d:\\d\\d,\\d+/],[\"HH:mm:ss\",/\\d\\d:\\d\\d:\\d\\d/],[\"HH:mm\",/\\d\\d:\\d\\d/],[\"HHmmss.SSSS\",/\\d\\d\\d\\d\\d\\d\\.\\d+/],[\"HHmmss,SSSS\",/\\d\\d\\d\\d\\d\\d,\\d+/],[\"HHmmss\",/\\d\\d\\d\\d\\d\\d/],[\"HHmm\",/\\d\\d\\d\\d/],[\"HH\",/\\d\\d/]],Ce=/^\\/?Date\\((\\-?\\d+)/i;a.createFromInputFallback=w(\"value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.\",function(a){a._d=new Date(a._i+(a._useUTC?\" UTC\":\"\"))}),\n// constant that refers to the ISO standard\na.ISO_8601=function(){};var De=w(\"moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:n()}),Ee=w(\"moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:n()}),Fe=function(){return Date.now?Date.now():+new Date};yb(\"Z\",\":\"),yb(\"ZZ\",\"\"),\n// PARSING\nY(\"Z\",Td),Y(\"ZZ\",Td),aa([\"Z\",\"ZZ\"],function(a,b,c){c._useUTC=!0,c._tzm=zb(Td,a)});\n// HELPERS\n// timezone chunker\n// '+10:00' > ['10',  '00']\n// '-1530'  > ['-15', '30']\nvar Ge=/([\\+\\-]|\\d\\d)/gi;\n// HOOKS\n// This function will be called whenever a moment is mutated.\n// It is intended to keep the offset in sync with the timezone.\na.updateOffset=function(){};\n// ASP.NET json date format regex\nvar He=/^(\\-)?(?:(\\d*)[. ])?(\\d+)\\:(\\d+)(?:\\:(\\d+)(\\.\\d*)?)?$/,Ie=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Nb.fn=vb.prototype;var Je=Rb(1,\"add\"),Ke=Rb(-1,\"subtract\");a.defaultFormat=\"YYYY-MM-DDTHH:mm:ssZ\",a.defaultFormatUtc=\"YYYY-MM-DDTHH:mm:ss[Z]\";var Le=w(\"moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.\",function(a){return void 0===a?this.localeData():this.locale(a)});\n// FORMATTING\nT(0,[\"gg\",2],0,function(){return this.weekYear()%100}),T(0,[\"GG\",2],0,function(){return this.isoWeekYear()%100}),xc(\"gggg\",\"weekYear\"),xc(\"ggggg\",\"weekYear\"),xc(\"GGGG\",\"isoWeekYear\"),xc(\"GGGGG\",\"isoWeekYear\"),\n// ALIASES\nI(\"weekYear\",\"gg\"),I(\"isoWeekYear\",\"GG\"),\n// PRIORITY\nL(\"weekYear\",1),L(\"isoWeekYear\",1),\n// PARSING\nY(\"G\",Rd),Y(\"g\",Rd),Y(\"GG\",Kd,Gd),Y(\"gg\",Kd,Gd),Y(\"GGGG\",Od,Id),Y(\"gggg\",Od,Id),Y(\"GGGGG\",Pd,Jd),Y(\"ggggg\",Pd,Jd),ba([\"gggg\",\"ggggg\",\"GGGG\",\"GGGGG\"],function(a,b,c,d){b[d.substr(0,2)]=t(a)}),ba([\"gg\",\"GG\"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),\n// FORMATTING\nT(\"Q\",0,\"Qo\",\"quarter\"),\n// ALIASES\nI(\"quarter\",\"Q\"),\n// PRIORITY\nL(\"quarter\",7),\n// PARSING\nY(\"Q\",Fd),aa(\"Q\",function(a,b){b[Zd]=3*(t(a)-1)}),\n// FORMATTING\nT(\"D\",[\"DD\",2],\"Do\",\"date\"),\n// ALIASES\nI(\"date\",\"D\"),\n// PRIOROITY\nL(\"date\",9),\n// PARSING\nY(\"D\",Kd),Y(\"DD\",Kd,Gd),Y(\"Do\",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),aa([\"D\",\"DD\"],$d),aa(\"Do\",function(a,b){b[$d]=t(a.match(Kd)[0],10)});\n// MOMENTS\nvar Me=N(\"Date\",!0);\n// FORMATTING\nT(\"DDD\",[\"DDDD\",3],\"DDDo\",\"dayOfYear\"),\n// ALIASES\nI(\"dayOfYear\",\"DDD\"),\n// PRIORITY\nL(\"dayOfYear\",4),\n// PARSING\nY(\"DDD\",Nd),Y(\"DDDD\",Hd),aa([\"DDD\",\"DDDD\"],function(a,b,c){c._dayOfYear=t(a)}),\n// FORMATTING\nT(\"m\",[\"mm\",2],0,\"minute\"),\n// ALIASES\nI(\"minute\",\"m\"),\n// PRIORITY\nL(\"minute\",14),\n// PARSING\nY(\"m\",Kd),Y(\"mm\",Kd,Gd),aa([\"m\",\"mm\"],ae);\n// MOMENTS\nvar Ne=N(\"Minutes\",!1);\n// FORMATTING\nT(\"s\",[\"ss\",2],0,\"second\"),\n// ALIASES\nI(\"second\",\"s\"),\n// PRIORITY\nL(\"second\",15),\n// PARSING\nY(\"s\",Kd),Y(\"ss\",Kd,Gd),aa([\"s\",\"ss\"],be);\n// MOMENTS\nvar Oe=N(\"Seconds\",!1);\n// FORMATTING\nT(\"S\",0,0,function(){return~~(this.millisecond()/100)}),T(0,[\"SS\",2],0,function(){return~~(this.millisecond()/10)}),T(0,[\"SSS\",3],0,\"millisecond\"),T(0,[\"SSSS\",4],0,function(){return 10*this.millisecond()}),T(0,[\"SSSSS\",5],0,function(){return 100*this.millisecond()}),T(0,[\"SSSSSS\",6],0,function(){return 1e3*this.millisecond()}),T(0,[\"SSSSSSS\",7],0,function(){return 1e4*this.millisecond()}),T(0,[\"SSSSSSSS\",8],0,function(){return 1e5*this.millisecond()}),T(0,[\"SSSSSSSSS\",9],0,function(){return 1e6*this.millisecond()}),\n// ALIASES\nI(\"millisecond\",\"ms\"),\n// PRIORITY\nL(\"millisecond\",16),\n// PARSING\nY(\"S\",Nd,Fd),Y(\"SS\",Nd,Gd),Y(\"SSS\",Nd,Hd);var Pe;for(Pe=\"SSSS\";Pe.length<=9;Pe+=\"S\")Y(Pe,Qd);for(Pe=\"S\";Pe.length<=9;Pe+=\"S\")aa(Pe,Gc);\n// MOMENTS\nvar Qe=N(\"Milliseconds\",!1);\n// FORMATTING\nT(\"z\",0,0,\"zoneAbbr\"),T(\"zz\",0,0,\"zoneName\");var Re=q.prototype;Re.add=Je,Re.calendar=Ub,Re.clone=Vb,Re.diff=ac,Re.endOf=mc,Re.format=ec,Re.from=fc,Re.fromNow=gc,Re.to=hc,Re.toNow=ic,Re.get=Q,Re.invalidAt=vc,Re.isAfter=Wb,Re.isBefore=Xb,Re.isBetween=Yb,Re.isSame=Zb,Re.isSameOrAfter=$b,Re.isSameOrBefore=_b,Re.isValid=tc,Re.lang=Le,Re.locale=jc,Re.localeData=kc,Re.max=Ee,Re.min=De,Re.parsingFlags=uc,Re.set=R,Re.startOf=lc,Re.subtract=Ke,Re.toArray=qc,Re.toObject=rc,Re.toDate=pc,Re.toISOString=dc,Re.toJSON=sc,Re.toString=cc,Re.unix=oc,Re.valueOf=nc,Re.creationData=wc,\n// Year\nRe.year=ke,Re.isLeapYear=qa,\n// Week Year\nRe.weekYear=yc,Re.isoWeekYear=zc,\n// Quarter\nRe.quarter=Re.quarters=Ec,\n// Month\nRe.month=ja,Re.daysInMonth=ka,\n// Week\nRe.week=Re.weeks=Aa,Re.isoWeek=Re.isoWeeks=Ba,Re.weeksInYear=Bc,Re.isoWeeksInYear=Ac,\n// Day\nRe.date=Me,Re.day=Re.days=Ja,Re.weekday=Ka,Re.isoWeekday=La,Re.dayOfYear=Fc,\n// Hour\nRe.hour=Re.hours=ue,\n// Minute\nRe.minute=Re.minutes=Ne,\n// Second\nRe.second=Re.seconds=Oe,\n// Millisecond\nRe.millisecond=Re.milliseconds=Qe,\n// Offset\nRe.utcOffset=Cb,Re.utc=Eb,Re.local=Fb,Re.parseZone=Gb,Re.hasAlignedHourOffset=Hb,Re.isDST=Ib,Re.isLocal=Kb,Re.isUtcOffset=Lb,Re.isUtc=Mb,Re.isUTC=Mb,\n// Timezone\nRe.zoneAbbr=Hc,Re.zoneName=Ic,\n// Deprecations\nRe.dates=w(\"dates accessor is deprecated. Use date instead.\",Me),Re.months=w(\"months accessor is deprecated. Use month instead\",ja),Re.years=w(\"years accessor is deprecated. Use year instead\",ke),Re.zone=w(\"moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/\",Db),Re.isDSTShifted=w(\"isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information\",Jb);var Se=Re,Te=B.prototype;Te.calendar=C,Te.longDateFormat=D,Te.invalidDate=E,Te.ordinal=F,Te.preparse=Lc,Te.postformat=Lc,Te.relativeTime=G,Te.pastFuture=H,Te.set=z,\n// Month\nTe.months=ea,Te.monthsShort=fa,Te.monthsParse=ha,Te.monthsRegex=ma,Te.monthsShortRegex=la,\n// Week\nTe.week=xa,Te.firstDayOfYear=za,Te.firstDayOfWeek=ya,\n// Day of Week\nTe.weekdays=Ea,Te.weekdaysMin=Ga,Te.weekdaysShort=Fa,Te.weekdaysParse=Ia,Te.weekdaysRegex=Ma,Te.weekdaysShortRegex=Na,Te.weekdaysMinRegex=Oa,\n// Hours\nTe.isPM=Ua,Te.meridiem=Va,Za(\"en\",{ordinalParse:/\\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===t(a%100/10)?\"th\":1===b?\"st\":2===b?\"nd\":3===b?\"rd\":\"th\";return a+c}}),\n// Side effect imports\na.lang=w(\"moment.lang is deprecated. Use moment.locale instead.\",Za),a.langData=w(\"moment.langData is deprecated. Use moment.localeData instead.\",ab);var Ue=Math.abs,Ve=cd(\"ms\"),We=cd(\"s\"),Xe=cd(\"m\"),Ye=cd(\"h\"),Ze=cd(\"d\"),$e=cd(\"w\"),_e=cd(\"M\"),af=cd(\"y\"),bf=ed(\"milliseconds\"),cf=ed(\"seconds\"),df=ed(\"minutes\"),ef=ed(\"hours\"),ff=ed(\"days\"),gf=ed(\"months\"),hf=ed(\"years\"),jf=Math.round,kf={s:45,// seconds to minute\nm:45,// minutes to hour\nh:22,// hours to day\nd:26,// days to month\nM:11},lf=Math.abs,mf=vb.prototype;mf.abs=Uc,mf.add=Wc,mf.subtract=Xc,mf.as=ad,mf.asMilliseconds=Ve,mf.asSeconds=We,mf.asMinutes=Xe,mf.asHours=Ye,mf.asDays=Ze,mf.asWeeks=$e,mf.asMonths=_e,mf.asYears=af,mf.valueOf=bd,mf._bubble=Zc,mf.get=dd,mf.milliseconds=bf,mf.seconds=cf,mf.minutes=df,mf.hours=ef,mf.days=ff,mf.weeks=fd,mf.months=gf,mf.years=hf,mf.humanize=kd,mf.toISOString=ld,mf.toString=ld,mf.toJSON=ld,mf.locale=jc,mf.localeData=kc,\n// Deprecations\nmf.toIsoString=w(\"toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)\",ld),mf.lang=Le,\n// Side effect imports\n// FORMATTING\nT(\"X\",0,0,\"unix\"),T(\"x\",0,0,\"valueOf\"),\n// PARSING\nY(\"x\",Rd),Y(\"X\",Ud),aa(\"X\",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa(\"x\",function(a,b,c){c._d=new Date(t(a))}),\n// Side effect imports\na.version=\"2.15.2\",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Nb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf});"
  },
  {
    "path": "web/vue/dist/vendor/toml.js",
    "content": "// https://github.com/jakwings/toml-j0.4\n!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var r;r=\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:this,r.toml=e()}}(function(){return function e(r,t,n){function i(u,a){if(!t[u]){if(!r[u]){var c=\"function\"==typeof require&&require;if(!a&&c)return c(u,!0);if(o)return o(u,!0);var s=new Error(\"Cannot find module '\"+u+\"'\");throw s.code=\"MODULE_NOT_FOUND\",s}var l=t[u]={exports:{}};r[u][0].call(l.exports,function(e){var t=r[u][1][e];return i(t?t:e)},l,l.exports,e,r,t,n)}return t[u].exports}for(var o=\"function\"==typeof require&&require,u=0;u<n.length;u++)i(n[u]);return i}({1:[function(e,r,t){r.exports=function(){function e(e,r){function t(){this.constructor=e}t.prototype=r.prototype,e.prototype=new t}function r(e,r,t,n,i,o){this.message=e,this.expected=r,this.found=t,this.offset=n,this.line=i,this.column=o,this.name=\"SyntaxError\"}function t(e){function t(){return e.substring(Ot,Dt)}function n(e){throw u(e,null,Ot)}function i(r){function t(r,t,n){var i,o;for(i=t;n>i;i++)o=e.charAt(i),\"\\n\"===o?(r.seenCR||r.line++,r.column=1,r.seenCR=!1):\"\\r\"===o||\"\\u2028\"===o||\"\\u2029\"===o?(r.line++,r.column=1,r.seenCR=!0):(r.column++,r.seenCR=!1)}return Tt!==r&&(Tt>r&&(Tt=0,jt={line:1,column:1,seenCR:!1}),t(jt,Tt,r),Tt=r),jt}function o(e){Nt>Dt||(Dt>Nt&&(Nt=Dt,Ut=[]),Ut.push(e))}function u(t,n,o){function u(e){var r=1;for(e.sort(function(e,r){return e.description<r.description?-1:e.description>r.description?1:0});r<e.length;)e[r-1]===e[r]?e.splice(r,1):r++}function a(e,r){function t(e){function r(e){return e.charCodeAt(0).toString(16).toUpperCase()}return e.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\x08/g,\"\\\\b\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\f/g,\"\\\\f\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g,function(e){return\"\\\\x0\"+r(e)}).replace(/[\\x10-\\x1F\\x80-\\xFF]/g,function(e){return\"\\\\x\"+r(e)}).replace(/[\\u0180-\\u0FFF]/g,function(e){return\"\\\\u0\"+r(e)}).replace(/[\\u1080-\\uFFFF]/g,function(e){return\"\\\\u\"+r(e)})}var n,i,o,u=new Array(e.length);for(o=0;o<e.length;o++)u[o]=e[o].description;return n=e.length>1?u.slice(0,-1).join(\", \")+\" or \"+u[e.length-1]:u[0],i=r?'\"'+t(r)+'\"':\"end of input\",\"Expected \"+n+\" but \"+i+\" found.\"}var c=i(o),s=o<e.length?e.charAt(o):null;return null!==n&&u(n),new r(null!==t?t:a(n,s),n,s,o,c.line,c.column)}function a(){var e,r,t,n,i,o,u,p;for(e=Dt,r=[],t=l(),t===ye&&(t=s(),t===ye&&(t=f()));t!==ye;)r.push(t),t=l(),t===ye&&(t=s(),t===ye&&(t=f()));if(r!==ye){if(t=Dt,n=c(),n!==ye){for(i=[],o=l(),o===ye&&(o=f());o!==ye;)i.push(o),o=l(),o===ye&&(o=f());i!==ye?(o=Dt,u=s(),u!==ye?(p=a(),p!==ye?(u=[u,p],o=u):(Dt=o,o=Ce)):(Dt=o,o=Ce),o===ye&&(o=be),o!==ye?(n=[n,i,o],t=n):(Dt=t,t=Ce)):(Dt=t,t=Ce)}else Dt=t,t=Ce;t===ye&&(t=be),t!==ye?(Ot=e,r=xe(),e=r):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function c(){var e,r;return e=Dt,r=pe(),r!==ye&&(Ot=e,r=me(r)),e=r,e===ye&&(e=Dt,r=he(),r!==ye&&(Ot=e,r=Fe(r)),e=r,e===ye&&(e=Dt,r=p(),r!==ye&&(Ot=e,r=Se(r)),e=r)),e}function s(){var r,t;return Zt++,10===e.charCodeAt(Dt)?(r=Ee,Dt++):(r=ye,0===Zt&&o(Re)),r===ye&&(e.substr(Dt,2)===_e?(r=_e,Dt+=2):(r=ye,0===Zt&&o(De))),Zt--,r===ye&&(t=ye,0===Zt&&o(we)),r}function l(){var r,t;return Zt++,Te.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(je)),Zt--,r===ye&&(t=ye,0===Zt&&o(Oe)),r}function f(){var r,t,n,i,u,a;if(Zt++,r=Dt,35===e.charCodeAt(Dt)?(t=Ue,Dt++):(t=ye,0===Zt&&o(Ze)),t!==ye){for(n=[],i=Dt,u=Dt,Zt++,a=s(),Zt--,a===ye?u=He:(Dt=u,u=Ce),u!==ye?(e.length>Dt?(a=e.charAt(Dt),Dt++):(a=ye,0===Zt&&o(Me)),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);i!==ye;)n.push(i),i=Dt,u=Dt,Zt++,a=s(),Zt--,a===ye?u=He:(Dt=u,u=Ce),u!==ye?(e.length>Dt?(a=e.charAt(Dt),Dt++):(a=ye,0===Zt&&o(Me)),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return Zt--,r===ye&&(t=ye,0===Zt&&o(Ne)),r}function p(){var r,t,n,i,u,a;if(r=Dt,t=h(),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye)if(61===e.charCodeAt(Dt)?(i=Ie,Dt++):(i=ye,0===Zt&&o(qe)),i!==ye){for(u=[],a=l();a!==ye;)u.push(a),a=l();u!==ye?(a=x(),a!==ye?(Ot=r,t=ze(t,a),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce;else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function h(){var e;return e=d(),e===ye&&(e=y()),e}function d(){var e,r,t;if(e=Dt,r=[],t=v(),t!==ye)for(;t!==ye;)r.push(t),t=v();else r=Ce;return r!==ye&&(Ot=e,r=Be()),e=r}function v(){var r,t;return Zt++,Ye.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(Je)),Zt--,r===ye&&(t=ye,0===Zt&&o(Qe)),r}function y(){var e,r,t,n;if(e=Dt,r=g(),r!==ye){if(t=[],n=S(),n!==ye)for(;n!==ye;)t.push(n),n=S();else t=Ce;t!==ye?(n=g(),n!==ye?(Ot=e,r=Pe(t),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function g(){var r,t;return Zt++,34===e.charCodeAt(Dt)?(r=Le,Dt++):(r=ye,0===Zt&&o(Ve)),Zt--,r===ye&&(t=ye,0===Zt&&o(ke)),r}function A(){var r,t;return Zt++,39===e.charCodeAt(Dt)?(r=Ge,Dt++):(r=ye,0===Zt&&o(Ke)),Zt--,r===ye&&(t=ye,0===Zt&&o(We)),r}function C(){var r,t;return Zt++,e.substr(Dt,3)===$e?(r=$e,Dt+=3):(r=ye,0===Zt&&o(er)),Zt--,r===ye&&(t=ye,0===Zt&&o(Xe)),r}function b(){var r,t;return Zt++,e.substr(Dt,3)===tr?(r=tr,Dt+=3):(r=ye,0===Zt&&o(nr)),Zt--,r===ye&&(t=ye,0===Zt&&o(rr)),r}function x(){var e;return e=m(),e===ye&&(e=B(),e===ye&&(e=G(),e===ye&&(e=Q(),e===ye&&(e=P(),e===ye&&(e=ce(),e===ye&&(e=fe())))))),e}function m(){var e;return e=U(),e===ye&&(e=F(),e===ye&&(e=I(),e===ye&&(e=j()))),e}function F(){var e,r,t,n;if(e=Dt,r=g(),r!==ye){for(t=[],n=S();n!==ye;)t.push(n),n=S();t!==ye?(n=g(),n!==ye?(Ot=e,r=ir(t),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function S(){var e;return e=w(),e===ye&&(e=E()),e}function w(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(ur.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(ar)),n!==ye?(Ot=r,t=Be(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function E(){var r,t,n,i,u;return r=Dt,t=_(),t!==ye?(n=R(),n===ye&&(n=g(),n===ye&&(n=_(),n===ye&&(n=Dt,117===e.charCodeAt(Dt)?(i=cr,Dt++):(i=ye,0===Zt&&o(sr)),i!==ye?(u=D(),u!==ye?(i=[i,u],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce),n===ye&&(n=Dt,85===e.charCodeAt(Dt)?(i=lr,Dt++):(i=ye,0===Zt&&o(fr)),i!==ye?(u=O(),u!==ye?(i=[i,u],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce))))),n!==ye?(Ot=r,t=pr(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function R(){var r,t;return Zt++,dr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(vr)),Zt--,r===ye&&(t=ye,0===Zt&&o(hr)),r}function _(){var r,t;return Zt++,92===e.charCodeAt(Dt)?(r=gr,Dt++):(r=ye,0===Zt&&o(Ar)),Zt--,r===ye&&(t=ye,0===Zt&&o(yr)),r}function D(){var e,r,t,n,i;return Zt++,e=Dt,r=T(),r!==ye?(t=T(),t!==ye?(n=T(),n!==ye?(i=T(),i!==ye?(r=[r,t,n,i],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(Cr)),e}function O(){var e,r,t,n,i,u,a,c,s;return Zt++,e=Dt,r=T(),r!==ye?(t=T(),t!==ye?(n=T(),n!==ye?(i=T(),i!==ye?(u=T(),u!==ye?(a=T(),a!==ye?(c=T(),c!==ye?(s=T(),s!==ye?(r=[r,t,n,i,u,a,c,s],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(br)),e}function T(){var r;return xr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(mr)),r}function j(){var e,r,t,n;if(e=Dt,r=A(),r!==ye){for(t=[],n=N();n!==ye;)t.push(n),n=N();t!==ye?(n=A(),n!==ye?(Ot=e,r=Fr(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function N(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Sr.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(wr)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function U(){var e,r,t,n,i;if(e=Dt,r=C(),r!==ye)if(t=s(),t===ye&&(t=be),t!==ye){for(n=[],i=Z();i!==ye;)n.push(i),i=Z();n!==ye?(i=C(),i!==ye?(Ot=e,r=Er(n),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;else Dt=e,e=Ce;return e}function Z(){var e,r,t;return e=H(),e===ye&&(e=Dt,r=_(),r!==ye?(t=s(),t!==ye?(Ot=e,r=Be(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e===ye&&(e=s())),e}function H(){var e,r,t;return e=Dt,r=Dt,Zt++,t=C(),Zt--,t===ye?r=He:(Dt=r,r=Ce),r!==ye?(t=M(),t!==ye?(Ot=e,r=Be(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e===ye&&(e=E()),e}function M(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Rr.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(_r)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function I(){var e,r,t,n,i;if(e=Dt,r=b(),r!==ye)if(t=s(),t===ye&&(t=be),t!==ye){for(n=[],i=q();i!==ye;)n.push(i),i=q();n!==ye?(i=b(),i!==ye?(Ot=e,r=ir(n),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;else Dt=e,e=Ce;return e}function q(){var r,t,n;return r=Dt,t=Dt,Zt++,e.substr(Dt,3)===tr?(n=tr,Dt+=3):(n=ye,0===Zt&&o(nr)),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(n=z(),n!==ye?(Ot=r,t=Be(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r===ye&&(r=s()),r}function z(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Or.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(Tr)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(Dr)),r}function B(){var r,t;return r=Dt,e.substr(Dt,4)===jr?(t=jr,Dt+=4):(t=ye,0===Zt&&o(Nr)),t!==ye&&(Ot=r,t=Ur()),r=t,r===ye&&(r=Dt,e.substr(Dt,5)===Zr?(t=Zr,Dt+=5):(t=ye,0===Zt&&o(Hr)),t!==ye&&(Ot=r,t=Mr()),r=t),r}function Q(){var e,r,t,n,i;return e=Dt,r=P(),r!==ye?(t=Dt,n=Y(),n!==ye?(i=J(),i===ye&&(i=be),i!==ye?(n=[n,i],t=n):(Dt=t,t=Ce)):(Dt=t,t=Ce),t===ye&&(t=J()),t!==ye?(Ot=e,r=Ir(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function Y(){var r,t,n,i,u,a,c;if(r=Dt,46===e.charCodeAt(Dt)?(t=qr,Dt++):(t=ye,0===Zt&&o(zr)),t!==ye)if(n=W(),n!==ye){for(i=[],u=Dt,95===e.charCodeAt(Dt)?(a=Br,Dt++):(a=ye,0===Zt&&o(Qr)),a===ye&&(a=be),a!==ye?(c=W(),c!==ye?(a=[a,c],u=a):(Dt=u,u=Ce)):(Dt=u,u=Ce);u!==ye;)i.push(u),u=Dt,95===e.charCodeAt(Dt)?(a=Br,Dt++):(a=ye,0===Zt&&o(Qr)),a===ye&&(a=be),a!==ye?(c=W(),c!==ye?(a=[a,c],u=a):(Dt=u,u=Ce)):(Dt=u,u=Ce);i!==ye?(t=[t,n,i],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;else Dt=r,r=Ce;return r}function J(){var r,t,n;return r=Dt,101===e.charCodeAt(Dt)?(t=Yr,Dt++):(t=ye,0===Zt&&o(Jr)),t===ye&&(69===e.charCodeAt(Dt)?(t=Pr,Dt++):(t=ye,0===Zt&&o(kr))),t!==ye?(n=P(),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function P(){var e,r,t;return e=Dt,r=k(),r===ye&&(r=be),r!==ye?(t=L(),t!==ye?(Ot=e,r=Lr(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function k(){var r;return 43===e.charCodeAt(Dt)?(r=Vr,Dt++):(r=ye,0===Zt&&o(Wr)),r===ye&&(45===e.charCodeAt(Dt)?(r=Gr,Dt++):(r=ye,0===Zt&&o(Kr))),r}function L(){var r,t,n,i,u,a;if(r=Dt,t=V(),t!==ye){if(n=[],i=Dt,95===e.charCodeAt(Dt)?(u=Br,Dt++):(u=ye,0===Zt&&o(Qr)),u===ye&&(u=be),u!==ye?(a=W(),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce),i!==ye)for(;i!==ye;)n.push(i),i=Dt,95===e.charCodeAt(Dt)?(u=Br,Dt++):(u=ye,0===Zt&&o(Qr)),u===ye&&(u=be),u!==ye?(a=W(),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);else n=Ce;n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r===ye&&(r=W()),r}function V(){var r;return Xr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o($r)),r}function W(){var r;return et.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(rt)),r}function G(){var r,t,n,i;return r=Dt,t=K(),t!==ye?(84===e.charCodeAt(Dt)?(n=tt,Dt++):(n=ye,0===Zt&&o(nt)),n!==ye?(i=re(),i!==ye?(Ot=r,t=it(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function K(){var r,t,n,i,u,a;return Zt++,r=Dt,t=X(),t!==ye?(45===e.charCodeAt(Dt)?(n=Gr,Dt++):(n=ye,0===Zt&&o(Kr)),n!==ye?(i=$(),i!==ye?(45===e.charCodeAt(Dt)?(u=Gr,Dt++):(u=ye,0===Zt&&o(Kr)),u!==ye?(a=ee(),a!==ye?(t=[t,n,i,u,a],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(ot)),r}function X(){var e,r,t,n,i;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(n=W(),n!==ye?(i=W(),i!==ye?(r=[r,t,n,i],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function $(){var e,r,t;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function ee(){var e,r,t;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function re(){var e,r,t;return e=Dt,r=te(),r!==ye?(t=ae(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function te(){var r,t,n,i,u,a,c;return r=Dt,t=ne(),t!==ye?(58===e.charCodeAt(Dt)?(n=ut,Dt++):(n=ye,0===Zt&&o(at)),n!==ye?(i=ie(),i!==ye?(58===e.charCodeAt(Dt)?(u=ut,Dt++):(u=ye,0===Zt&&o(at)),u!==ye?(a=oe(),a!==ye?(c=ue(),c===ye&&(c=be),c!==ye?(t=[t,n,i,u,a,c],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function ne(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(ct)),e}function ie(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(st)),e}function oe(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(lt)),e}function ue(){var r,t,n,i;if(r=Dt,46===e.charCodeAt(Dt)?(t=qr,Dt++):(t=ye,0===Zt&&o(zr)),t!==ye){if(n=[],i=W(),i!==ye)for(;i!==ye;)n.push(i),i=W();else n=Ce;n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r}function ae(){var r,t,n,i,u;return Zt++,90===e.charCodeAt(Dt)?(r=pt,Dt++):(r=ye,0===Zt&&o(ht)),r===ye&&(r=Dt,t=k(),t!==ye?(n=ne(),n!==ye?(58===e.charCodeAt(Dt)?(i=ut,Dt++):(i=ye,0===Zt&&o(at)),i!==ye?(u=ie(),u!==ye?(t=[t,n,i,u],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)),Zt--,r===ye&&(t=ye,0===Zt&&o(ft)),r}function ce(){var r,t,n,i,u,a,c,s,l,f;if(r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye){for(n=[],i=le();i!==ye;)n.push(i),i=le();if(n!==ye){if(i=Dt,u=se(),u!==ye){for(a=[],c=le();c!==ye;)a.push(c),c=le();if(a!==ye){if(c=Dt,44===e.charCodeAt(Dt)?(s=yt,Dt++):(s=ye,0===Zt&&o(gt)),s!==ye){for(l=[],f=le();f!==ye;)l.push(f),f=le();l!==ye?(s=[s,l],c=s):(Dt=c,c=Ce)}else Dt=c,c=Ce;c===ye&&(c=be),c!==ye?(u=[u,a,c],i=u):(Dt=i,i=Ce)}else Dt=i,i=Ce}else Dt=i,i=Ce;i===ye&&(i=be),i!==ye?(93===e.charCodeAt(Dt)?(u=At,Dt++):(u=ye,0===Zt&&o(Ct)),u!==ye?(Ot=r,t=bt(i),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function se(){var r,t,n,i,u,a,c;if(r=Dt,t=x(),t!==ye){for(n=Dt,i=[],u=le();u!==ye;)i.push(u),u=le();if(i!==ye)if(44===e.charCodeAt(Dt)?(u=yt,Dt++):(u=ye,0===Zt&&o(gt)),u!==ye){for(a=[],c=le();c!==ye;)a.push(c),c=le();a!==ye?(c=se(),c!==ye?(i=[i,u,a,c],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce)}else Dt=n,n=Ce;else Dt=n,n=Ce;n===ye&&(n=be),n!==ye?(Ot=r,t=xt(t,n),r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r}function le(){var e;return e=l(),e===ye&&(e=s(),e===ye&&(e=f())),e}function fe(){var r,t,n,i,u,a,c,s,f,h,d;if(r=Dt,123===e.charCodeAt(Dt)?(t=mt,Dt++):(t=ye,0===Zt&&o(Ft)),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye){if(i=Dt,u=p(),u!==ye){for(a=[],c=Dt,s=[],f=l();f!==ye;)s.push(f),f=l();if(s!==ye)if(44===e.charCodeAt(Dt)?(f=yt,Dt++):(f=ye,0===Zt&&o(gt)),f!==ye){for(h=[],d=l();d!==ye;)h.push(d),d=l();h!==ye?(d=p(),d!==ye?(s=[s,f,h,d],c=s):(Dt=c,c=Ce)):(Dt=c,c=Ce)}else Dt=c,c=Ce;else Dt=c,c=Ce;for(;c!==ye;){for(a.push(c),c=Dt,s=[],f=l();f!==ye;)s.push(f),f=l();if(s!==ye)if(44===e.charCodeAt(Dt)?(f=yt,Dt++):(f=ye,0===Zt&&o(gt)),f!==ye){for(h=[],d=l();d!==ye;)h.push(d),d=l();h!==ye?(d=p(),d!==ye?(s=[s,f,h,d],c=s):(Dt=c,c=Ce)):(Dt=c,c=Ce)}else Dt=c,c=Ce;else Dt=c,c=Ce}if(a!==ye){for(c=[],s=l();s!==ye;)c.push(s),s=l();c!==ye?(u=[u,a,c],i=u):(Dt=i,i=Ce)}else Dt=i,i=Ce}else Dt=i,i=Ce;i===ye&&(i=be),i!==ye?(125===e.charCodeAt(Dt)?(u=St,Dt++):(u=ye,0===Zt&&o(wt)),u!==ye?(Ot=r,t=Et(i),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function pe(){var r,t,n,i;return r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye?(n=he(),n!==ye?(93===e.charCodeAt(Dt)?(i=At,Dt++):(i=ye,0===Zt&&o(Ct)),i!==ye?(Ot=r,t=Rt(n),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function he(){var r,t,n,i,u,a,c,s,f,p;if(r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye)if(i=h(),i!==ye){for(u=[],a=Dt,c=[],s=l();s!==ye;)c.push(s),s=l();if(c!==ye)if(46===e.charCodeAt(Dt)?(s=qr,Dt++):(s=ye,0===Zt&&o(zr)),s!==ye){for(f=[],p=l();p!==ye;)f.push(p),p=l();f!==ye?(p=h(),p!==ye?(c=[c,s,f,p],a=c):(Dt=a,a=Ce)):(Dt=a,a=Ce)}else Dt=a,a=Ce;else Dt=a,a=Ce;for(;a!==ye;){for(u.push(a),a=Dt,c=[],s=l();s!==ye;)c.push(s),s=l();if(c!==ye)if(46===e.charCodeAt(Dt)?(s=qr,Dt++):(s=ye,0===Zt&&o(zr)),s!==ye){for(f=[],p=l();p!==ye;)f.push(p),p=l();f!==ye?(p=h(),p!==ye?(c=[c,s,f,p],a=c):(Dt=a,a=Ce)):(Dt=a,a=Ce)}else Dt=a,a=Ce;else Dt=a,a=Ce}if(u!==ye){for(a=[],c=l();c!==ye;)a.push(c),c=l();a!==ye?(93===e.charCodeAt(Dt)?(c=At,Dt++):(c=ye,0===Zt&&o(Ct)),c!==ye?(Ot=r,t=_t(i,u),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;else Dt=r,r=Ce}else Dt=r,r=Ce;return r}var de,ve=arguments.length>1?arguments[1]:{},ye={},ge={Expressions:a},Ae=a,Ce=ye,be=null,xe=function(){return Pt},me=function(e){kt=Jt(Pt,!0,e)},Fe=function(e){kt=Jt(Pt,!1,e)},Se=function(e){Yt(kt.table,e[0]),kt.table[e[0]]=e[1]},we={type:\"other\",description:\"Newline\"},Ee=\"\\n\",Re={type:\"literal\",value:\"\\n\",description:'\"\\\\n\"'},_e=\"\\r\\n\",De={type:\"literal\",value:\"\\r\\n\",description:'\"\\\\r\\\\n\"'},Oe={type:\"other\",description:\"Whitespace\"},Te=/^[ \\t]/,je={type:\"class\",value:\"[ \\\\t]\",description:\"[ \\\\t]\"},Ne={type:\"other\",description:\"Comment\"},Ue=\"#\",Ze={type:\"literal\",value:\"#\",description:'\"#\"'},He=void 0,Me={type:\"any\",description:\"any character\"},Ie=\"=\",qe={type:\"literal\",value:\"=\",description:'\"=\"'},ze=function(e,r){return[e,r.value]},Be=function(){return t()},Qe={type:\"other\",description:'[a-z], [A-Z], [0-9], \"-\", \"_\"'},Ye=/^[a-zA-Z0-9\\-_]/,Je={type:\"class\",value:\"[a-zA-Z0-9\\\\-_]\",description:\"[a-zA-Z0-9\\\\-_]\"},Pe=function(e){return e.join(\"\")},ke={type:\"other\",description:\"DoubleQuote\"},Le='\"',Ve={type:\"literal\",value:'\"',description:'\"\\\\\"\"'},We={type:\"other\",description:\"SingleQuote\"},Ge=\"'\",Ke={type:\"literal\",value:\"'\",description:'\"\\'\"'},Xe={type:\"other\",description:\"ThreeDoubleQuotes\"},$e='\"\"\"',er={type:\"literal\",value:'\"\"\"',description:'\"\\\\\"\\\\\"\\\\\"\"'},rr={type:\"other\",description:\"ThreeSingleQuotes\"},tr=\"'''\",nr={type:\"literal\",value:\"'''\",description:\"\\\"'''\\\"\"},ir=function(e){return{type:\"String\",value:e.join(\"\")}},or={type:\"other\",description:\"NormalCharacter\"},ur=/^[^\\0-\\x1F\"\\\\]/,ar={type:\"class\",value:'[^\\\\0-\\\\x1F\"\\\\\\\\]',description:'[^\\\\0-\\\\x1F\"\\\\\\\\]'},cr=\"u\",sr={type:\"literal\",value:\"u\",description:'\"u\"'},lr=\"U\",fr={type:\"literal\",value:\"U\",description:'\"U\"'},pr=function(){var e=t();return e.length<=2?Bt(e[1]):Qt(parseInt(e.substr(2),16))},hr={type:\"other\",description:'\"b\", \"f\", \"n\", \"r\", \"t\"'},dr=/^[bfnrt]/,vr={type:\"class\",value:\"[bfnrt]\",description:\"[bfnrt]\"},yr={type:\"other\",description:\"Backslash\"},gr=\"\\\\\",Ar={type:\"literal\",value:\"\\\\\",description:'\"\\\\\\\\\"'},Cr={type:\"other\",description:\"FourHexadecimalDigits\"},br={type:\"other\",description:\"EightHexadecimalDigits\"},xr=/^[0-9A-Fa-f]/,mr={type:\"class\",value:\"[0-9A-Fa-f]\",description:\"[0-9A-Fa-f]\"},Fr=function(){var e=t();return{type:\"String\",value:e.substr(1,e.length-2)}},Sr=/^[^\\0-\\x08\\n-\\x1F']/,wr={type:\"class\",value:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F']\",description:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F']\"},Er=function(e){return{type:\"String\",value:e.join(\"\").replace(/\\\\\\r?\\n(?:\\r?\\n|[ \\t])*/g,\"\")}},Rr=/^[^\\0-\\x1F\\\\]/,_r={type:\"class\",value:\"[^\\\\0-\\\\x1F\\\\\\\\]\",description:\"[^\\\\0-\\\\x1F\\\\\\\\]\"},Dr={type:\"other\",description:\"AnyCharacter\"},Or=/^[^\\0-\\x08\\n-\\x1F]/,Tr={type:\"class\",value:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F]\",description:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F]\"},jr=\"true\",Nr={type:\"literal\",value:\"true\",description:'\"true\"'},Ur=function(){return{type:\"Boolean\",value:!0}},Zr=\"false\",Hr={type:\"literal\",value:\"false\",description:'\"false\"'},Mr=function(){return{type:\"Boolean\",value:!1}},Ir=function(){var e=t(),r=parseFloat(e.replace(/_/g,\"\"));return Mt(r)||n(e+\"is not a 64-bit floating-point number.\"),{type:\"Float\",value:r}},qr=\".\",zr={type:\"literal\",value:\".\",description:'\".\"'},Br=\"_\",Qr={type:\"literal\",value:\"_\",description:'\"_\"'},Yr=\"e\",Jr={type:\"literal\",value:\"e\",description:'\"e\"'},Pr=\"E\",kr={type:\"literal\",value:\"E\",description:'\"E\"'},Lr=function(){var e=t(),r=e.replace(/_/g,\"\"),i=!1;if(\"-\"===r[0]){var o=\"-9223372036854775808\";(r.length>o.length||r.length===o.length&&r>o)&&(i=!0)}else{\"+\"===r[0]&&(r=r.substr(1));var u=\"9223372036854775807\";(r.length>u.length||r.length===u.length&&r>u)&&(i=!0)}return i&&n(e+\" is not a 64-bit signed integer.\"),r=parseInt(r,10),Mt(r)||n(e+\" is not a 64-bit signed integer.\"),{type:\"Integer\",value:r}},Vr=\"+\",Wr={type:\"literal\",value:\"+\",description:'\"+\"'},Gr=\"-\",Kr={type:\"literal\",value:\"-\",description:'\"-\"'},Xr=/^[1-9]/,$r={type:\"class\",value:\"[1-9]\",description:\"[1-9]\"},et=/^[0-9]/,rt={type:\"class\",value:\"[0-9]\",description:\"[0-9]\"},tt=\"T\",nt={type:\"literal\",value:\"T\",description:'\"T\"'},it=function(){var e=t(),r=new Date(e);return Mt(r.getTime())||n(\"Date-time \"+e+\" is invalid. It does not conform to RFC 3339 or this is a browser-specific problem.\"),{type:\"DateTime\",value:r}},ot={type:\"other\",description:\"FullDate (YYYY-mm-dd)\"},ut=\":\",at={type:\"literal\",value:\":\",description:'\":\"'},ct={type:\"other\",description:\"Hour (HH)\"},st={type:\"other\",description:\"Minute (MM)\"},lt={type:\"other\",description:\"Second (SS)\"},ft={type:\"other\",description:\"TimeOffset (Z or +/-HH:MM)\"},pt=\"Z\",ht={type:\"literal\",value:\"Z\",description:'\"Z\"'},dt=\"[\",vt={type:\"literal\",value:\"[\",description:'\"[\"'},yt=\",\",gt={type:\"literal\",value:\",\",description:'\",\"'},At=\"]\",Ct={type:\"literal\",value:\"]\",description:'\"]\"'},bt=function(e){for(var r={type:\"Array\",value:e?e[0]:[]},t=0,n=r.value,i=n.length;i>t;t++)n[t]=n[t].value;return r},xt=function(e,r){var t=[e];if(r)for(var i=e.type,o=0,u=r[3],a=u.length;a>o;o++)i!==u[o].type&&n(zt(u[o].value)+' should be of type \"'+i+'\".'),t.push(u[o]);return t},mt=\"{\",Ft={type:\"literal\",value:\"{\",description:'\"{\"'},St=\"}\",wt={type:\"literal\",value:\"}\",description:'\"}\"'},Et=function(e){var r={};if(e){r[e[0][0]]=e[0][1];for(var t=0,n=e[1],i=n.length;i>t;t++){var o=n[t][3];Yt(r,o[0]),r[o[0]]=o[1]}}return{type:\"InlineTable\",value:r}},Rt=function(e){return e},_t=function(e,r){for(var t=[e],n=0,i=r.length;i>n;n++)t.push(r[n][3]);return t},Dt=0,Ot=0,Tt=0,jt={line:1,column:1,seenCR:!1},Nt=0,Ut=[],Zt=0;if(\"startRule\"in ve){if(!(ve.startRule in ge))throw new Error(\"Can't start parsing from rule \\\"\"+ve.startRule+'\".');Ae=ge[ve.startRule]}var Ht,Mt,It,qt,zt,Bt,Qt,Yt,Jt;Ht=function(e){return\"Value for \"+e+\" should not be redefined in the same table.\"},Mt=Number.isFinite||function(e){return\"number\"==typeof e&&isFinite(e)},It=Array.isArray||function(e){return\"[object Array]\"===Object.prototype.toString.call(e)},qt=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},zt=\"object\"==typeof JSON&&JSON?JSON.stringify:function(e){return'\"'+String(e).replace(/[\\x00-\\x1F\"\\\\]/g,function(e){switch(e){case'\"':case\"\\\\\":return\"\\\\\"+e;case\"  \":return\"\\\\t\";case\"\\n\":return\"\\\\n\";case\"\\r\":return\"\\\\r\";case\"\\b\":return\"\\\\b\";case\"\\f\":return\"\\\\f\";default:var r=e.charCodeAt(0).toString(16);return\"\\\\u\"+\"0000\".substr(r.length)+r}})+'\"'},Bt=function(e){switch(e){case'\"':case\"\\\\\":return e;case\"t\":return\" \";case\"n\":return\"\\n\";case\"r\":return\"\\r\";case\"b\":return\"\\b\";case\"f\":return\"\\f\";default:n(zt(e)+\" cannot be escaped.\")}},Qt=function(e){if((!Mt(e)||0>e||e>1114111)&&n(\"U+\"+e.toString(16)+\" is not a valid Unicode code point.\"),String.fromCodePoint)return String.fromCodePoint(e);var r=\"\";return e>65535&&(e-=65536,r+=String.fromCharCode(e>>>10&1023|55296),e=56320|1023&e),r+=String.fromCharCode(e)},Yt=function(e,r){qt(e,r)&&n(Ht(zt(r)))},Jt=function(e,r,t){for(var i=\"\",o=0,u=t.length;u>o;o++){var a=t[o];if(i+=(i?\".\":\"\")+zt(a),qt(e,a))if(r)if(It(e[a]))if(Wt[i]||n(Ht(i)),o+1===u){var c={};e[a].push(c),e=c}else i+=\".\"+zt(e[a].length-1),e=e[a][e[a].length-1];else Lt[i]||n(Ht(i)),e=e[a];else It(e[a])?(Wt[i]&&o+1!==u||n(Ht(i)),i+=\".\"+zt(e[a].length-1),e=e[a][e[a].length-1]):(Lt[i]||n(Ht(i)),e=e[a]);else if(r&&o+1===u){var c={};e[a]=[c],e=c,Wt[i]=!0}else e=e[a]={},Lt[i]=!0}return r?Wt[i]||n(Ht(i)):((Vt[i]||Wt[i])&&n(Ht(i)),Vt[i]=!0),{table:e,path:t}};var Pt={},kt={table:Pt,path:[]},Lt={},Vt={},Wt={};if(de=Ae(),de!==ye&&Dt===e.length)return de;throw de!==ye&&Dt<e.length&&o({type:\"end\",description:\"end of input\"}),u(null,Ut,Nt)}return e(r,Error),{SyntaxError:r,parse:t}}()},{}],2:[function(e,r,t){\"use strict\";var n=e(\"./lib/parser\"),i={parse:function(e){return n.parse(e)},SyntaxError:n.SyntaxError};r.exports=i},{\"./lib/parser\":1}]},{},[2])(2)});"
  },
  {
    "path": "web/vue/package.json",
    "content": "{\n  \"name\": \"gekko-vue-ui\",\n  \"version\": \"0.2.3\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\"\n  },\n  \"dependencies\": {\n    \"marked\": \"^0.4.0\",\n    \"superagent\": \"^3.8.3\",\n    \"superagent-no-cache\": \"github:uditalias/superagent-no-cache\",\n    \"vue\": \"^2.5.16\",\n    \"vue-router\": \"^3.0.1\",\n    \"vuex\": \"^3.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"^3.0.0-beta.15\",\n    \"@vue/cli-service\": \"^3.0.0-beta.15\",\n    \"babel-plugin-transform-commonjs-es2015-modules\": \"^4.0.1\",\n    \"copy-webpack-plugin\": \"^4.5.2\",\n    \"pug\": \"^2.0.3\",\n    \"pug-plain-loader\": \"^1.0.0\",\n    \"vue-template-compiler\": \"^2.5.16\"\n  },\n  \"postcss\": {\n    \"plugins\": {\n      \"autoprefixer\": {}\n    }\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\",\n    \"not ie <= 8\"\n  ]\n}\n"
  },
  {
    "path": "web/vue/public/UIconfig.js",
    "content": "// Note: this file gets copied around, make sure you edit\n// the UIconfig located at `gekko/web/vue/dist/UIconfig.js`.\n\n// This config is used by both the frontend as well as the web server.\n// see https://gekko.wizb.it/docs/installation/installing_gekko_on_a_server.html#Configuring-Gekko\n\nconst CONFIG = {\n  headless: false,\n  api: {\n    host: '127.0.0.1',\n    port: 3000,\n    timeout: 120000 // 2 minutes\n  },\n  ui: {\n    ssl: false,\n    host: 'localhost',\n    port: 3000,\n    path: '/'\n  },\n  adapter: 'sqlite'\n}\n\nif(typeof window === 'undefined')\n  module.exports = CONFIG;\nelse\n  window.CONFIG = CONFIG;\n"
  },
  {
    "path": "web/vue/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <link rel=\"stylesheet\" href=\"vendor/furtive.min.css\">\n    <title>Gekko</title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but gekko-vue-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <script src='UIconfig.js'></script>\n    <script src='vendor/reconnecting-websocket.min.js'></script>\n    <script src='vendor/moment.js'></script>\n    <script src='vendor/d3.js'></script>\n    <script src='vendor/toml.js'></script>\n    <script src='vendor/humanize-duration.js'></script>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "web/vue/public/vendor/d3.js",
    "content": "// https://d3js.org Version 4.3.0. Copyright 2016 Mike Bostock.\n(function(t,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?n(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],n):n(t.d3=t.d3||{})})(this,function(t){\"use strict\";function n(t){return function(n,e){return Ms(t(n),e)}}function e(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Fs?i*=10:o>=Is?i*=5:o>=Ys&&(i*=2),n<t?-i:i}function r(t){return t.length}function i(){}function o(t,n){var e=new i;if(t instanceof i)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,o=-1,u=t.length;if(null==n)for(;++o<u;)e.set(o,t[o]);else for(;++o<u;)e.set(n(r=t[o],o,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function u(){return{}}function a(t,n,e){t[n]=e}function c(){return o()}function s(t,n,e){t.set(n,e)}function f(){}function l(t,n){var e=new f;if(t instanceof f)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function h(t){return+t}function p(t){return t*t}function d(t){return t*(2-t)}function v(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function _(t){return t*t*t}function y(t){return--t*t*t+1}function g(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function m(t){return 1-Math.cos(t*Tf)}function x(t){return Math.sin(t*Tf)}function b(t){return(1-Math.cos(Mf*t))/2}function w(t){return Math.pow(2,10*t-10)}function M(t){return 1-Math.pow(2,-10*t)}function T(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function N(t){return 1-Math.sqrt(1-t*t)}function k(t){return Math.sqrt(1- --t*t)}function S(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function A(t){return 1-E(1-t)}function E(t){return(t=+t)<Nf?Lf*t*t:t<Sf?Lf*(t-=kf)*t+Af:t<Cf?Lf*(t-=Ef)*t+zf:Lf*(t-=Pf)*t+qf}function C(t){return((t*=2)<=1?1-E(1-t):E(t-1)+1)/2}function z(t,n){return t[0]-n[0]||t[1]-n[1]}function P(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&Wf(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function q(){this._x0=this._y0=this._x1=this._y1=null,this._=[]}function L(){return new q}function R(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u;while((l=f<<1|s)===(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function U(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-(1/0),l=-(1/0);for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)R(this,u[e],a[e],t[e]);return this}function D(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this}function O(t){return t[0]}function F(t){return t[1]}function I(t,n,e){var r=new Y(null==n?O:n,null==e?F:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Y(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function B(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function j(t){if(!(t>=1))throw new Error;this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function H(t){if(!t._start)try{X(t)}catch(n){if(t._tasks[t._ended+t._active-1])W(t,n);else if(!t._data)throw n}}function X(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=V(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||_l)}}function V(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?W(t,e):(t._data[n]=r,t._waiting?H(t):$(t))))}}function W(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(t){}t._active=NaN,$(t)}function $(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Z(t){return new j(arguments.length?+t:1/0)}function G(t){return t.innerRadius}function J(t){return t.outerRadius}function Q(t){return t.startAngle}function K(t){return t.endAngle}function tt(t){return t&&t.padAngle}function nt(t){return t>=1?xl:t<=-1?-xl:Math.asin(t)}function et(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function rt(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/Math.sqrt(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*Math.sqrt(Math.max(0,b*b*x-w*w)),T=(w*m-g*M)/x,N=(-w*g-m*M)/x,k=(w*m+g*M)/x,S=(-w*g+m*M)/x,A=T-_,E=N-y,C=k-_,z=S-y;return A*A+E*E>C*C+z*z&&(T=k,N=S),{cx:T,cy:N,x01:-f,y01:-l,x11:T*(i/b-1),y11:N*(i/b-1)}}function it(t){this._context=t}function ot(t){return t[0]}function ut(t){return t[1]}function at(t){this._curve=t}function ct(t){function n(n){return new at(t(n))}return n._curve=t,n}function st(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(ct(t)):n()._curve},t}function ft(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function lt(t){this._context=t}function ht(t){this._context=t}function pt(t){this._context=t}function dt(t,n){this._basis=new lt(t),this._beta=n}function vt(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function _t(t,n){this._context=t,this._k=(1-n)/6}function yt(t,n){this._context=t,this._k=(1-n)/6}function gt(t,n){this._context=t,this._k=(1-n)/6}function mt(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>gl){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>gl){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function xt(t,n){this._context=t,this._alpha=n}function bt(t,n){this._context=t,this._alpha=n}function wt(t,n){this._context=t,this._alpha=n}function Mt(t){this._context=t}function Tt(t){return t<0?-1:1}function Nt(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(Tt(o)+Tt(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function kt(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function St(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function At(t){this._context=t}function Et(t){this._context=new Ct(t)}function Ct(t){this._context=t}function zt(t){return new At(t)}function Pt(t){return new Et(t)}function qt(t){this._context=t}function Lt(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function Rt(t,n){this._context=t,this._t=n}function Ut(t){return new Rt(t,0)}function Dt(t){return new Rt(t,1)}function Ot(t,n){return t[n]}function Ft(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function It(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Yt(){}function Bt(t){var n;return t=(t+\"\").trim().toLowerCase(),(n=kh.exec(t))?(n=parseInt(n[1],16),new Wt(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=Sh.exec(t))?jt(parseInt(n[1],16)):(n=Ah.exec(t))?new Wt(n[1],n[2],n[3],1):(n=Eh.exec(t))?new Wt(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ch.exec(t))?Ht(n[1],n[2],n[3],n[4]):(n=zh.exec(t))?Ht(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ph.exec(t))?$t(n[1],n[2]/100,n[3]/100,1):(n=qh.exec(t))?$t(n[1],n[2]/100,n[3]/100,n[4]):Lh.hasOwnProperty(t)?jt(Lh[t]):\"transparent\"===t?new Wt(NaN,NaN,NaN,0):null}function jt(t){return new Wt(t>>16&255,t>>8&255,255&t,1)}function Ht(t,n,e,r){return r<=0&&(t=n=e=NaN),new Wt(t,n,e,r)}function Xt(t){return t instanceof Yt||(t=Bt(t)),t?(t=t.rgb(),new Wt(t.r,t.g,t.b,t.opacity)):new Wt}function Vt(t,n,e,r){return 1===arguments.length?Xt(t):new Wt(t,n,e,null==r?1:r)}function Wt(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function $t(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Jt(t,n,e,r)}function Zt(t){if(t instanceof Jt)return new Jt(t.h,t.s,t.l,t.opacity);if(t instanceof Yt||(t=Bt(t)),!t)return new Jt;if(t instanceof Jt)return t;t=t.rgb();var n=t.r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Jt(u,a,c,t.opacity)}function Gt(t,n,e,r){return 1===arguments.length?Zt(t):new Jt(t,n,e,null==r?1:r)}function Jt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Qt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function Kt(t){if(t instanceof nn)return new nn(t.l,t.a,t.b,t.opacity);if(t instanceof sn){var n=t.h*Rh;return new nn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Wt||(t=Xt(t));var e=un(t.r),r=un(t.g),i=un(t.b),o=en((.4124564*e+.3575761*r+.1804375*i)/Oh),u=en((.2126729*e+.7151522*r+.072175*i)/Fh),a=en((.0193339*e+.119192*r+.9503041*i)/Ih);return new nn(116*u-16,500*(o-u),200*(u-a),t.opacity)}function tn(t,n,e,r){return 1===arguments.length?Kt(t):new nn(t,n,e,null==r?1:r)}function nn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function en(t){return t>Hh?Math.pow(t,1/3):t/jh+Yh}function rn(t){return t>Bh?t*t*t:jh*(t-Yh)}function on(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function un(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function an(t){if(t instanceof sn)return new sn(t.h,t.c,t.l,t.opacity);t instanceof nn||(t=Kt(t));var n=Math.atan2(t.b,t.a)*Uh;return new sn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function cn(t,n,e,r){return 1===arguments.length?an(t):new sn(t,n,e,null==r?1:r)}function sn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function fn(t){if(t instanceof hn)return new hn(t.h,t.s,t.l,t.opacity);t instanceof Wt||(t=Xt(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Qh*r+Gh*n-Jh*e)/(Qh+Gh-Jh),o=r-i,u=(Zh*(e-i)-Wh*o)/$h,a=Math.sqrt(u*u+o*o)/(Zh*i*(1-i)),c=a?Math.atan2(u,o)*Uh-120:NaN;return new hn(c<0?c+360:c,a,i,t.opacity)}function ln(t,n,e,r){return 1===arguments.length?fn(t):new hn(t,n,e,null==r?1:r)}function hn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pn(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function dn(t,n){return function(e){return t+e*n}}function vn(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function _n(t,n){var e=n-t;return e?dn(t,e>180||e<-180?e-360*Math.round(e/360):e):op(isNaN(t)?n:t)}function yn(t){return 1===(t=+t)?gn:function(n,e){return e-n?vn(n,e,t):op(isNaN(n)?e:n)}}function gn(t,n){var e=n-t;return e?dn(t,e):op(isNaN(t)?n:t)}function mn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Vt(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+\"\"}}}function xn(t){return function(){return t}}function bn(t){return function(n){return t(n)+\"\"}}function wn(t){return\"none\"===t?mp:(Kh||(Kh=document.createElement(\"DIV\"),tp=document.documentElement,np=document.defaultView),Kh.style.transform=t,t=np.getComputedStyle(tp.appendChild(Kh),null).getPropertyValue(\"transform\"),tp.removeChild(Kh),t=t.slice(7,-1).split(\",\"),xp(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))}function Mn(t){return null==t?mp:(ep||(ep=document.createElementNS(\"http://www.w3.org/2000/svg\",\"g\")),ep.setAttribute(\"transform\",t),(t=ep.transform.baseVal.consolidate())?(t=t.matrix,xp(t.a,t.b,t.c,t.d,t.e,t.f)):mp)}function Tn(t,n,e,r){function i(t){return t.length?t.pop()+\" \":\"\"}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push(\"translate(\",null,n,null,e);a.push({i:c-4,x:lp(t,i)},{i:c-2,x:lp(r,o)})}else(i||o)&&u.push(\"translate(\"+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+\"rotate(\",null,r)-2,x:lp(t,n)})):n&&e.push(i(e)+\"rotate(\"+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+\"skewX(\",null,r)-2,x:lp(t,n)}):n&&e.push(i(e)+\"skewX(\"+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+\"scale(\",null,\",\",null,\")\");u.push({i:a-4,x:lp(t,e)},{i:a-2,x:lp(n,r)})}else 1===e&&1===r||o.push(i(o)+\"scale(\"+e+\",\"+r+\")\")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join(\"\")}}}function Nn(t){return((t=Math.exp(t))+1/t)/2}function kn(t){return((t=Math.exp(t))-1/t)/2}function Sn(t){return((t=Math.exp(2*t))-1)/(t+1)}function An(t){return function(n,e){var r=t((n=Gt(n)).h,(e=Gt(e)).h),i=gn(n.s,e.s),o=gn(n.l,e.l),u=gn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+\"\"}}}function En(t,n){var e=gn((t=tn(t)).l,(n=tn(n)).l),r=gn(t.a,n.a),i=gn(t.b,n.b),o=gn(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+\"\"}}function Cn(t){return function(n,e){var r=t((n=cn(n)).h,(e=cn(e)).h),i=gn(n.c,e.c),o=gn(n.l,e.l),u=gn(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+\"\"}}}function zn(t){return function n(e){function r(n,r){var i=t((n=ln(n)).h,(r=ln(r)).h),o=gn(n.s,r.s),u=gn(n.l,r.l),a=gn(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+\"\"}}return e=+e,r.gamma=n,r}(1)}function Pn(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+\"\")||t in r)throw new Error(\"illegal type: \"+t);r[t]=[]}return new qn(r)}function qn(t){this._=t}function Ln(t,n){return t.trim().split(/^|\\s+/).map(function(t){var e=\"\",r=t.indexOf(\".\");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);return{type:t,name:e}})}function Rn(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function Un(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Rp,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function Dn(t){return new Function(\"d\",\"return {\"+t.map(function(t,n){return JSON.stringify(t)+\": d[\"+n+\"]\"}).join(\",\")+\"}\")}function On(t,n){var e=Dn(t);return function(r,i){return n(e(r),i,t)}}function Fn(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function In(t){return function(n,e){t(null==n?e:null)}}function Yn(t){var n=t.responseType;return n&&\"text\"!==n?t.response:t.responseText}function Bn(t,n){return function(e){return t(e.responseText,n)}}function jn(){return sd||(hd(Hn),sd=ld.now()+fd)}function Hn(){sd=0}function Xn(){this._call=this._time=this._next=null}function Vn(t,n,e){var r=new Xn;return r.restart(t,n,e),r}function Wn(){jn(),++id;for(var t,n=Up;n;)(t=sd-n._time)>=0&&n._call.call(null,t),n=n._next;--id}function $n(){sd=(cd=ld.now())+fd,id=od=0;try{Wn()}finally{id=0,Gn(),sd=0}}function Zn(){var t=ld.now(),n=t-cd;n>ad&&(fd-=n,cd=t)}function Gn(){for(var t,n,e=Up,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Up=n);Dp=t,Jn(r)}function Jn(t){if(!id){od&&(od=clearTimeout(od));var n=t-sd;n>24?(t<1/0&&(od=setTimeout($n,n)),ud&&(ud=clearInterval(ud))):(ud||(ud=setInterval(Zn,ad)),id=1,hd($n))}}function Qn(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do u.push(new Date(+e));while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Qn(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return vd.setTime(+n),_d.setTime(+r),t(vd),t(_d),Math.floor(e(vd,_d))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t===0}:function(n){return i.count(0,n)%t===0}):i:null}),i}function Kn(t){return Qn(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*xd)/Md})}function te(t){return Qn(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/Md})}function ne(t){if(!(n=Av.exec(t)))throw new Error(\"invalid format: \"+t);var n,e=n[1]||\" \",r=n[2]||\">\",i=n[3]||\"-\",o=n[4]||\"\",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||\"\";\"n\"===f?(c=!0,f=\"g\"):Sv[f]||(f=\"\"),(u||\"0\"===e&&\"=\"===r)&&(u=!0,e=\"0\",r=\"=\"),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function ee(t){return t}function re(n){return Cv=Pv(n),t.format=Cv.format,t.formatPrefix=Cv.formatPrefix,Cv}function ie(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function oe(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function ue(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function ae(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Dv[r=t.charAt(++a)])?r=t.charAt(++a):i=\"e\"===r?\" \":\"0\",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join(\"\")}}function e(t,n){return function(e){var i=ue(1900),o=r(i,t,e+=\"\",0);if(o!=e.length)return null;if(\"p\"in i&&(i.H=i.H%12+12*i.p),\"W\"in i||\"U\"in i){\"w\"in i||(i.w=\"W\"in i?1:0);var u=\"Z\"in i?oe(ue(i.y)).getUTCDay():n(ue(i.y)).getDay();i.m=0,i.d=\"W\"in i?(i.w+6)%7+7*i.W-(u+5)%7:i.w+7*i.U-(u+6)%7}return\"Z\"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,oe(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(i=n.charCodeAt(u++),37===i){if(i=n.charAt(u++),o=B[i in Dv?n.charAt(u++):i],!o||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function i(t,n,e){var r=C.exec(n.slice(e));return r?(t.p=z[r[0].toLowerCase()],e+r[0].length):-1}function o(t,n,e){var r=L.exec(n.slice(e));return r?(t.w=R[r[0].toLowerCase()],e+r[0].length):-1}function u(t,n,e){var r=P.exec(n.slice(e));return r?(t.w=q[r[0].toLowerCase()],e+r[0].length):-1}function a(t,n,e){var r=O.exec(n.slice(e));return r?(t.m=F[r[0].toLowerCase()],e+r[0].length):-1}function c(t,n,e){var r=U.exec(n.slice(e));return r?(t.m=D[r[0].toLowerCase()],e+r[0].length):-1}function s(t,n,e){return r(t,w,n,e)}function f(t,n,e){return r(t,M,n,e)}function l(t,n,e){return r(t,T,n,e)}function h(t){return S[t.getDay()]}function p(t){return k[t.getDay()]}function d(t){return E[t.getMonth()]}function v(t){return A[t.getMonth()]}function _(t){return N[+(t.getHours()>=12)]}function y(t){return S[t.getUTCDay()]}function g(t){return k[t.getUTCDay()]}function m(t){return E[t.getUTCMonth()]}function x(t){return A[t.getUTCMonth()]}function b(t){return N[+(t.getUTCHours()>=12)]}var w=t.dateTime,M=t.date,T=t.time,N=t.periods,k=t.days,S=t.shortDays,A=t.months,E=t.shortMonths,C=fe(N),z=le(N),P=fe(k),q=le(k),L=fe(S),R=le(S),U=fe(A),D=le(A),O=fe(E),F=le(E),I={a:h,A:p,b:d,B:v,c:null,d:ke,e:ke,H:Se,I:Ae,j:Ee,L:Ce,m:ze,M:Pe,p:_,S:qe,U:Le,w:Re,W:Ue,x:null,X:null,y:De,Y:Oe,Z:Fe,\"%\":tr},Y={a:y,A:g,b:m,B:x,c:null,d:Ie,e:Ie,H:Ye,I:Be,j:je,L:He,m:Xe,M:Ve,p:b,S:We,U:$e,w:Ze,W:Ge,x:null,X:null,y:Je,Y:Qe,Z:Ke,\"%\":tr},B={a:o,A:u,b:a,B:c,c:s,d:me,e:me,H:be,I:be,j:xe,L:Te,m:ge,M:we,p:i,S:Me,U:pe,w:he,W:de,x:f,X:l,y:_e,Y:ve,Z:ye,\"%\":Ne};return I.x=n(M,I),I.X=n(T,I),I.c=n(w,I),Y.x=n(M,Y),Y.X=n(T,Y),Y.c=n(w,Y),{format:function(t){var e=n(t+=\"\",I);return e.toString=function(){return t},e},parse:function(t){var n=e(t+=\"\",ie);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+=\"\",Y);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,oe);return n.toString=function(){return t},n}}}function ce(t,n,e){var r=t<0?\"-\":\"\",i=(r?-t:t)+\"\",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function se(t){return t.replace(Iv,\"\\\\$&\")}function fe(t){return new RegExp(\"^(?:\"+t.map(se).join(\"|\")+\")\",\"i\")}function le(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function he(t,n,e){var r=Ov.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function pe(t,n,e){var r=Ov.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function de(t,n,e){var r=Ov.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function ve(t,n,e){var r=Ov.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function _e(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ye(t,n,e){var r=/^(Z)|([+-]\\d\\d)(?:\\:?(\\d\\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||\"00\")),e+r[0].length):-1}function ge(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function me(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function xe(t,n,e){var r=Ov.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function be(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function we(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Me(t,n,e){var r=Ov.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function Te(t,n,e){var r=Ov.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Ne(t,n,e){var r=Fv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function ke(t,n){return ce(t.getDate(),n,2)}function Se(t,n){return ce(t.getHours(),n,2)}function Ae(t,n){return ce(t.getHours()%12||12,n,2)}function Ee(t,n){return ce(1+Cd.count($d(t),t),n,3)}function Ce(t,n){return ce(t.getMilliseconds(),n,3)}function ze(t,n){return ce(t.getMonth()+1,n,2)}function Pe(t,n){return ce(t.getMinutes(),n,2)}function qe(t,n){return ce(t.getSeconds(),n,2)}function Le(t,n){return ce(Pd.count($d(t),t),n,2)}function Re(t){return t.getDay()}function Ue(t,n){return ce(qd.count($d(t),t),n,2)}function De(t,n){return ce(t.getFullYear()%100,n,2)}function Oe(t,n){return ce(t.getFullYear()%1e4,n,4)}function Fe(t){var n=t.getTimezoneOffset();return(n>0?\"-\":(n*=-1,\"+\"))+ce(n/60|0,\"0\",2)+ce(n%60,\"0\",2)}function Ie(t,n){return ce(t.getUTCDate(),n,2)}function Ye(t,n){return ce(t.getUTCHours(),n,2)}function Be(t,n){return ce(t.getUTCHours()%12||12,n,2)}function je(t,n){return ce(1+tv.count(gv(t),t),n,3)}function He(t,n){return ce(t.getUTCMilliseconds(),n,3)}function Xe(t,n){return ce(t.getUTCMonth()+1,n,2)}function Ve(t,n){return ce(t.getUTCMinutes(),n,2)}function We(t,n){return ce(t.getUTCSeconds(),n,2)}function $e(t,n){return ce(ev.count(gv(t),t),n,2)}function Ze(t){return t.getUTCDay()}function Ge(t,n){return ce(rv.count(gv(t),t),n,2)}function Je(t,n){return ce(t.getUTCFullYear()%100,n,2)}function Qe(t,n){return ce(t.getUTCFullYear()%1e4,n,4)}function Ke(){return\"+0000\"}function tr(){return\"%\"}function nr(n){return qv=ae(n),t.timeFormat=qv.format,t.timeParse=qv.parse,t.utcFormat=qv.utcFormat,t.utcParse=qv.utcParse,qv}function er(t){return t.toISOString()}function rr(t){var n=new Date(t);return isNaN(n)?null:n}function ir(t){function n(n){var o=n+\"\",u=e.get(o);if(!u){if(i!==Wv)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=o(),r=[],i=Wv;return t=null==t?[]:Vv.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=o();for(var i,u,a=-1,c=t.length;++a<c;)e.has(u=(i=t[a])+\"\")||e.set(u,r.push(i));return n},n.range=function(e){return arguments.length?(t=Vv.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return ir().domain(r).range(t).unknown(i)},n}function or(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Os(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=ir().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return or().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function ur(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return ur(n())},t}function ar(){return ur(or().paddingInner(1))}function cr(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:$v(n)}function sr(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function fr(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function lr(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function hr(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=ks(t,n,1,i)-1;return u[e](o[e](n))}}function pr(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function dr(t,n){function e(){return i=Math.min(a.length,c.length)>2?hr:lr,o=u=null,r}function r(n){return(o||(o=i(a,c,f?sr(t):t,s)))(+n)}var i,o,u,a=Gv,c=Gv,s=_p,f=!1;return r.invert=function(t){return(u||(u=i(c,a,cr,f?fr(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=Xv.call(t,Zv),e()):a.slice()},r.range=function(t){return arguments.length?(c=Vv.call(t),e()):c.slice()},r.rangeRound=function(t){return c=Vv.call(t),s=yp,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function vr(t){var n=t.domain;return t.ticks=function(t){var e=n();return Bs(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return Jv(n(),t,e)},t.nice=function(r){var i=n(),o=i.length-1,u=null==r?10:r,a=i[0],c=i[o],s=e(a,c,u);return s&&(s=e(Math.floor(a/s)*s,Math.ceil(c/s)*s,u),i[0]=Math.floor(a/s)*s,i[o]=Math.ceil(c/s)*s,n(i)),t},t}function _r(){var t=dr(cr,lp);return t.copy=function(){return pr(t,_r())},vr(t)}function yr(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=Xv.call(e,Zv),t):n.slice()},t.copy=function(){return yr().domain(n)},vr(t)}function gr(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:$v(n)}function mr(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function xr(t){return isFinite(t)?+(\"1e\"+t):t<0?0:t}function br(t){return 10===t?xr:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function wr(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function Mr(t){return function(n){return-t(-n)}}function Tr(){function n(){return o=wr(i),u=br(i),r()[0]<0&&(o=Mr(o),u=Mr(u)),e}var e=dr(gr,mr).domain([1,10]),r=e.domain,i=10,o=wr(10),u=br(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(l=s*f,!(l<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(l=s*f,!(l<a)){if(l>c)break;v.push(l)}}else v=Bs(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?\".0e\":\",\"),\"function\"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):\"\"}},e.nice=function(){return r(Qv(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return pr(e,Tr().base(i))},e}function Nr(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function kr(){function t(t,n){return(n=Nr(n,e)-(t=Nr(t,e)))?function(r){return(Nr(r,e)-t)/n}:$v(n)}function n(t,n){return n=Nr(n,e)-(t=Nr(t,e)),function(r){return Nr(t+n*r,1/e)}}var e=1,r=dr(t,n),i=r.domain;return r.exponent=function(t){return arguments.length?(e=+t,i(i())):e},r.copy=function(){return pr(r,kr().exponent(e))},vr(r)}function Sr(){return kr().exponent(.5)}function Ar(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=Xs(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[ks(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)r=n[i],null==r||isNaN(r=+r)||e.push(r);return e.sort(Ms),t()},n.range=function(n){return arguments.length?(r=Vv.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return Ar().domain(e).range(r)},n}function Er(){function t(t){if(t<=t)return u[ks(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=Vv.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return Er().domain([e,r]).range(u)},vr(t)}function Cr(){function t(t){if(t<=t)return e[ks(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=Vv.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=Vv.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return Cr().domain(n).range(e)},t}function zr(t){return new Date(t);\n}function Pr(t){return t instanceof Date?+t:+new Date(+t)}function qr(t,n,r,i,o,u,a,c,s){function f(e){return(a(e)<e?v:u(e)<e?_:o(e)<e?y:i(e)<e?g:n(e)<e?r(e)<e?m:x:t(e)<e?b:w)(e)}function l(n,r,i,o){if(null==n&&(n=10),\"number\"==typeof n){var u=Math.abs(i-r)/n,a=Ts(function(t){return t[2]}).right(M,u);a===M.length?(o=e(r/o_,i/o_,n),n=t):a?(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a],o=a[1],n=a[0]):(o=e(r,i,n),n=c)}return null==o?n:n.every(o)}var h=dr(cr,lp),p=h.invert,d=h.domain,v=s(\".%L\"),_=s(\":%S\"),y=s(\"%I:%M\"),g=s(\"%I %p\"),m=s(\"%a %d\"),x=s(\"%b %d\"),b=s(\"%B\"),w=s(\"%Y\"),M=[[a,1,Kv],[a,5,5*Kv],[a,15,15*Kv],[a,30,30*Kv],[u,1,t_],[u,5,5*t_],[u,15,15*t_],[u,30,30*t_],[o,1,n_],[o,3,3*n_],[o,6,6*n_],[o,12,12*n_],[i,1,e_],[i,2,2*e_],[r,1,r_],[n,1,i_],[n,3,3*i_],[t,1,o_]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(Xv.call(t,Pr)):d().map(zr)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(Qv(e,t)):h},h.copy=function(){return pr(h,qr(t,n,r,i,o,u,a,c,s))},h}function Lr(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Rr(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Rr(t).domain([e,r]).clamp(i)},vr(n)}function Ur(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===w_&&n.documentElement.namespaceURI===w_?n.createElement(t):n.createElementNS(e,t)}}function Dr(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Or(){return new Fr}function Fr(){this._=\"@\"+(++k_).toString(36)}function Ir(t,n,e){return t=Yr(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Yr(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function Br(t){return t.trim().split(/^|\\s+/).map(function(t){var n=\"\",e=t.indexOf(\".\");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function jr(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function Hr(t,n,e){var r=z_.hasOwnProperty(t.type)?Ir:Yr;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function Xr(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Vr(){}function Wr(){return[]}function $r(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function Zr(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new $r(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function Gr(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=X_+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)s=X_+u.call(t,o[a],a,o),(c=f[s])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new $r(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function Jr(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function Qr(t){return function(){this.removeAttribute(t)}}function Kr(t){return function(){this.removeAttributeNS(t.space,t.local)}}function ti(t,n){return function(){this.setAttribute(t,n)}}function ni(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function ei(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function ri(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function ii(t){return function(){this.style.removeProperty(t)}}function oi(t,n,e){return function(){this.style.setProperty(t,n,e)}}function ui(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function ai(t){return function(){delete this[t]}}function ci(t,n){return function(){this[t]=n}}function si(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function fi(t){return t.trim().split(/^|\\s+/)}function li(t){return t.classList||new hi(t)}function hi(t){this._node=t,this._names=fi(t.getAttribute(\"class\")||\"\")}function pi(t,n){for(var e=li(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function di(t,n){for(var e=li(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function vi(t){return function(){pi(this,t)}}function _i(t){return function(){di(this,t)}}function yi(t,n){return function(){(n.apply(this,arguments)?pi:di)(this,t)}}function gi(){this.textContent=\"\"}function mi(t){return function(){this.textContent=t}}function xi(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?\"\":n}}function bi(){this.innerHTML=\"\"}function wi(t){return function(){this.innerHTML=t}}function Mi(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?\"\":n}}function Ti(){this.nextSibling&&this.parentNode.appendChild(this)}function Ni(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ki(){return null}function Si(){var t=this.parentNode;t&&t.removeChild(this)}function Ai(t,n,e){var r=iy(t),i=r.CustomEvent;i?i=new i(n,e):(i=r.document.createEvent(\"Event\"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function Ei(t,n){return function(){return Ai(this,t,n)}}function Ci(t,n){return function(){return Ai(this,t,n.apply(this,arguments))}}function zi(t,n){this._groups=t,this._parents=n}function Pi(){return new zi([[document.documentElement]],yy)}function qi(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Ty)throw new Error(\"too late\");return e}function Li(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ky)throw new Error(\"too late\");return e}function Ri(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error(\"too late\");return e}function Ui(t,n,e){function r(t){e.state=Ny,e.timer.restart(i,e.delay,e.time),e.delay<=t&&i(t-e.delay)}function i(r){var s,f,l,h;if(e.state!==Ny)return u();for(s in c)if(h=c[s],h.name===e.name){if(h.state===Sy)return pd(i);h.state===Ay?(h.state=Cy,h.timer.stop(),h.on.call(\"interrupt\",t,t.__data__,h.index,h.group),delete c[s]):+s<n&&(h.state=Cy,h.timer.stop(),delete c[s])}if(pd(function(){e.state===Sy&&(e.state=Ay,e.timer.restart(o,e.delay,e.time),o(r))}),e.state=ky,e.on.call(\"start\",t,t.__data__,e.index,e.group),e.state===ky){for(e.state=Sy,a=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(a[++f]=h);a.length=f+1}}function o(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=Ey,1),i=-1,o=a.length;++i<o;)a[i].call(null,r);e.state===Ey&&(e.on.call(\"end\",t,t.__data__,e.index,e.group),u())}function u(){e.state=Cy,e.timer.stop(),delete c[n];for(var r in c)return;delete t.__transition}var a,c=t.__transition;c[n]=e,e.timer=Vn(r,0,e.time)}function Di(t,n){var e,r;return function(){var i=Li(this,t),o=i.tween;if(o!==e){r=e=o;for(var u=0,a=r.length;u<a;++u)if(r[u].name===n){r=r.slice(),r.splice(u,1);break}}i.tween=r}}function Oi(t,n,e){var r,i;if(\"function\"!=typeof e)throw new Error;return function(){var o=Li(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Fi(t,n,e){var r=t._id;return t.each(function(){var t=Li(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Ri(t,r).value[n]}}function Ii(t){return function(){this.removeAttribute(t)}}function Yi(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Bi(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function ji(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function Hi(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttribute(t):(u=this.getAttribute(t),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Xi(t,n,e){var r,i,o;return function(){var u,a=e(this);return null==a?void this.removeAttributeNS(t.space,t.local):(u=this.getAttributeNS(t.space,t.local),u===a?null:u===r&&a===i?o:o=n(r=u,i=a))}}function Vi(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Wi(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function $i(t,n){return function(){qi(this,t).delay=+n.apply(this,arguments)}}function Zi(t,n){return n=+n,function(){qi(this,t).delay=n}}function Gi(t,n){return function(){Li(this,t).duration=+n.apply(this,arguments)}}function Ji(t,n){return n=+n,function(){Li(this,t).duration=n}}function Qi(t,n){if(\"function\"!=typeof n)throw new Error;return function(){Li(this,t).ease=n}}function Ki(t){return(t+\"\").trim().split(/^|\\s+/).every(function(t){var n=t.indexOf(\".\");return n>=0&&(t=t.slice(0,n)),!t||\"start\"===t})}function to(t,n,e){var r,i,o=Ki(n)?qi:Li;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function no(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function eo(t,n){var e,r,i;return function(){var o=iy(this).getComputedStyle(this,null),u=o.getPropertyValue(t),a=(this.style.removeProperty(t),o.getPropertyValue(t));return u===a?null:u===e&&a===r?i:i=n(e=u,r=a)}}function ro(t){return function(){this.style.removeProperty(t)}}function io(t,n,e){var r,i;return function(){var o=iy(this).getComputedStyle(this,null).getPropertyValue(t);return o===e?null:o===r?i:i=n(r=o,e)}}function oo(t,n,e){var r,i,o;return function(){var u=iy(this).getComputedStyle(this,null),a=u.getPropertyValue(t),c=e(this);return null==c&&(this.style.removeProperty(t),c=u.getPropertyValue(t)),a===c?null:a===r&&c===i?o:o=n(r=a,i=c)}}function uo(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function ao(t){return function(){this.textContent=t}}function co(t){return function(){var n=t(this);this.textContent=null==n?\"\":n}}function so(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function fo(t){return Pi().transition(t)}function lo(){return++Ky}function ho(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return ng.time=jn(),ng;return e}function po(t,n,e){var r=t(e);return\"translate(\"+(isFinite(r)?r:n(e))+\",0)\"}function vo(t,n,e){var r=t(e);return\"translate(0,\"+(isFinite(r)?r:n(e))+\")\"}function _o(t){var n=t.bandwidth()/2;return t.round()&&(n=Math.round(n)),function(e){return t(e)+n}}function yo(){return!this.__axis}function go(t,n){function e(e){var s,f=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,l=null==o?n.tickFormat?n.tickFormat.apply(n,r):ug:o,h=Math.max(u,0)+c,p=t===ag||t===sg?po:vo,d=n.range(),v=d[0]+.5,_=d[d.length-1]+.5,y=(n.bandwidth?_o:ug)(n.copy()),g=e.selection?e.selection():e,m=g.selectAll(\".domain\").data([null]),x=g.selectAll(\".tick\").data(f,n).order(),b=x.exit(),w=x.enter().append(\"g\").attr(\"class\",\"tick\"),M=x.select(\"line\"),T=x.select(\"text\"),N=t===ag||t===fg?-1:1,k=t===fg||t===cg?(s=\"x\",\"y\"):(s=\"y\",\"x\");m=m.merge(m.enter().insert(\"path\",\".tick\").attr(\"class\",\"domain\").attr(\"stroke\",\"#000\")),x=x.merge(w),M=M.merge(w.append(\"line\").attr(\"stroke\",\"#000\").attr(s+\"2\",N*u).attr(k+\"1\",.5).attr(k+\"2\",.5)),T=T.merge(w.append(\"text\").attr(\"fill\",\"#000\").attr(s,N*h).attr(k,.5).attr(\"dy\",t===ag?\"0em\":t===sg?\"0.71em\":\"0.32em\")),e!==g&&(m=m.transition(e),x=x.transition(e),M=M.transition(e),T=T.transition(e),b=b.transition(e).attr(\"opacity\",lg).attr(\"transform\",function(t){return p(y,this.parentNode.__axis||y,t)}),w.attr(\"opacity\",lg).attr(\"transform\",function(t){return p(this.parentNode.__axis||y,y,t)})),b.remove(),m.attr(\"d\",t===fg||t==cg?\"M\"+N*a+\",\"+v+\"H0.5V\"+_+\"H\"+N*a:\"M\"+v+\",\"+N*a+\"V0.5H\"+_+\"V\"+N*a),x.attr(\"opacity\",1).attr(\"transform\",function(t){return p(y,y,t)}),M.attr(s+\"2\",N*u),T.attr(s,N*h).text(l),g.filter(yo).attr(\"fill\",\"none\").attr(\"font-size\",10).attr(\"font-family\",\"sans-serif\").attr(\"text-anchor\",t===cg?\"start\":t===fg?\"end\":\"middle\"),g.each(function(){this.__axis=y})}var r=[],i=null,o=null,u=6,a=6,c=3;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=og.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:og.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:og.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(u=a=+t,e):u},e.tickSizeInner=function(t){return arguments.length?(u=+t,e):u},e.tickSizeOuter=function(t){return arguments.length?(a=+t,e):a},e.tickPadding=function(t){return arguments.length?(c=+t,e):c},e}function mo(t){return go(ag,t)}function xo(t){return go(cg,t)}function bo(t){return go(sg,t)}function wo(t){return go(fg,t)}function Mo(t,n){return t.parent===n.parent?1:2}function To(t){return t.reduce(No,0)/t.length}function No(t,n){return t+n.x}function ko(t){return 1+t.reduce(So,0)}function So(t,n){return Math.max(t,n.y)}function Ao(t){for(var n;n=t.children;)t=n[0];return t}function Eo(t){for(var n;n=t.children;)t=n[n.length-1];return t}function Co(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function zo(t,n){var e,r,i,o,u,a=new Uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=qo);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new Uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Ro)}function Po(){return zo(this).eachBefore(Lo)}function qo(t){return t.children}function Lo(t){t.data=t.data.data}function Ro(t){var n=0;do t.height=n;while((t=t.parent)&&t.height<++n)}function Uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function Do(t){this._=t,this.next=null}function Oo(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r-n.r;return i*i+1e-6>e*e+r*r}function Fo(t,n){var e,r,i,o=null,u=t.head;switch(n.length){case 1:e=Io(n[0]);break;case 2:e=Yo(n[0],n[1]);break;case 3:e=Bo(n[0],n[1],n[2])}for(;u;)i=u._,r=u.next,e&&Oo(e,i)?o=u:(o?(t.tail=o,o.next=null):t.head=t.tail=null,n.push(i),e=Fo(t,n),n.pop(),t.head?(u.next=t.head,t.head=u):(u.next=null,t.head=t.tail=u),o=t.tail,o.next=r),u=r;return t.tail=o,e}function Io(t){return{x:t.x,y:t.y,r:t.r}}function Yo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function Bo(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=2*(r-u),p=2*(i-a),d=2*(c-o),v=r*r+i*i-o*o-u*u-a*a+c*c,_=2*(r-s),y=2*(i-f),g=2*(l-o),m=r*r+i*i-o*o-s*s-f*f+l*l,x=_*p-h*y,b=(p*m-y*v)/x-r,w=(y*d-p*g)/x,M=(_*v-h*m)/x-i,T=(h*g-_*d)/x,N=w*w+T*T-1,k=2*(b*w+M*T+o),S=b*b+M*M-o*o,A=(-k-Math.sqrt(k*k-4*N*S))/(2*N);return{x:b+w*A+r,y:M+T*A+i,r:A}}function jo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function Ho(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i>e*e+r*r}function Xo(t,n,e){var r=t.x-n,i=t.y-e;return r*r+i*i}function Vo(t){this._=t,this.next=null,this.previous=null}function Wo(t){if(!(i=t.length))return 0;var n,e,r,i;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;jo(e,n,r=t[2]);var o,u,a,c,s,f,l,h=n.r*n.r,p=e.r*e.r,d=r.r*r.r,v=h+p+d,_=h*n.x+p*e.x+d*r.x,y=h*n.y+p*e.y+d*r.y;n=new Vo(n),e=new Vo(e),r=new Vo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){if(jo(n._,e._,r=t[a]),r=new Vo(r),(s=n.previous)===(c=e.next)){if(Ho(c._,r._)){n=e,e=c,--a;continue t}}else{f=c._.r,l=s._.r;do if(f<=l){if(Ho(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}c=c.next,f+=c._.r}else{if(Ho(s._,r._)){n=s,n.next=e,e.previous=n,--a;continue t}s=s.previous,l+=s._.r}while(c!==s.next)}for(r.previous=n,r.next=e,n.next=e.previous=e=r,v+=d=r._.r*r._.r,_+=d*r._.x,y+=d*r._.y,h=Xo(n._,o=_/v,u=y/v);(r=r.next)!==e;)(d=Xo(r._,o,u))<h&&(n=r,h=d);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Tg(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function $o(t){return null==t?null:Zo(t)}function Zo(t){if(\"function\"!=typeof t)throw new Error;return t}function Go(){return 0}function Jo(t){return Math.sqrt(t.value)}function Qo(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Ko(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=Wo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function tu(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function nu(t){return t.id}function eu(t){return t.parentId}function ru(t,n){return t.parent===n.parent?1:2}function iu(t){var n=t.children;return n?n[0]:t.t}function ou(t){var n=t.children;return n?n[n.length-1]:t.t}function uu(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function au(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)n=i[o],n.z+=e,n.m+=e,e+=n.s+(r+=n.c)}function cu(t,n,e){return t.a.parent===n.parent?t.a:e}function su(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function fu(t){for(var n,e,r,i,o,u=new su(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new su(r[i],i)),e.parent=n;return(u.parent=new su(null,0)).children=[u],u}function lu(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y,g=[],m=n.children,x=0,b=m.length,w=n.value;x<b;){for(s=i-e,f=o-r,h=p=l=m[x].value,_=Math.max(f/s,s/f)/(w*t),y=l*l*_,v=Math.max(p/y,y/h),c=x+1;c<b;++c){if(l+=a=m[c].value,a<h&&(h=a),a>p&&(p=a),y=l*l*_,d=Math.max(p/y,y/h),d>v){l-=a;break}v=d}g.push(u={value:l,dice:s<f,children:m.slice(x,c)}),u.dice?Eg(u,e,r,i,w?r+=f*l/w:o):Ug(u,e,r,w?e+=s*l/w:i,o),w-=l,x=c}return g}function hu(t){return t.x+t.vx}function pu(t){return t.y+t.vy}function du(t,n){return n}function vu(t,n){var e=t.get(n);if(!e)throw new Error(\"missing: \"+n);return e}function _u(t){return t.x}function yu(t){return t.y}function gu(){t.event.stopImmediatePropagation()}function mu(t,n){var e=t.document.documentElement,r=gy(t).on(\"dragstart.drag\",null);n&&(r.on(\"click.drag\",tm,!0),setTimeout(function(){r.on(\"click.drag\",null)},0)),\"onselectstart\"in e?r.on(\"selectstart.drag\",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function xu(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function bu(){return!t.event.button}function wu(){return this.parentNode}function Mu(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Tu(t){return t[0]}function Nu(t){return t[1]}function ku(){this._=null}function Su(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Au(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Eu(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Cu(t){for(;t.L;)t=t.L;return t}function zu(t,n,e,r){var i=[null,null],o=sm.push(i)-1;return i.left=t,i.right=n,e&&qu(i,t,n,e),r&&qu(i,n,t,r),am[t.index].halfedges.push(o),am[n.index].halfedges.push(o),i}function Pu(t,n,e){var r=[n,e];return r.left=t,r}function qu(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Lu(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=a[0],l=a[1],h=0,p=1,d=f-c,v=l-s;if(o=n-c,d||!(o>0)){if(o/=d,d<0){if(o<h)return;o<p&&(p=o)}else if(d>0){if(o>p)return;o>h&&(h=o)}if(o=r-c,d||!(o<0)){if(o/=d,d<0){if(o>p)return;o>h&&(h=o)}else if(d>0){if(o<h)return;o<p&&(p=o)}if(o=e-s,v||!(o>0)){if(o/=v,v<0){if(o<h)return;o<p&&(p=o)}else if(v>0){if(o>p)return;o>h&&(h=o)}if(o=i-s,v||!(o<0)){if(o/=v,v<0){if(o>p)return;o>h&&(h=o)}else if(v>0){if(o<h)return;o<p&&(p=o)}return!(h>0||p<1)||(h>0&&(t[0]=[c+h*d,s+h*v]),p<1&&(t[1]=[c+p*d,s+p*v]),!0)}}}}}function Ru(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Uu(t,n,e,r){for(var i,o=sm.length;o--;)Ru(i=sm[o],t,n,e,r)&&Lu(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>hm||Math.abs(i[0][1]-i[1][1])>hm)||delete sm[o]}function Du(t){return am[t.index]={site:t,halfedges:[]}}function Ou(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Fu(t,n){return n[+(n.left!==t.site)]}function Iu(t,n){return n[+(n.left===t.site)]}function Yu(){for(var t,n,e,r,i=0,o=am.length;i<o;++i)if((t=am[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Ou(t,sm[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Bu(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=am.length,y=!0;for(i=0;i<_;++i)if(o=am[i]){for(u=o.site,c=o.halfedges,a=c.length;a--;)sm[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)p=Iu(o,sm[c[a]]),d=p[0],v=p[1],f=Fu(o,sm[c[++a%s]]),l=f[0],h=f[1],(Math.abs(d-l)>hm||Math.abs(v-h)>hm)&&(c.splice(a,0,sm.push(Pu(u,p,Math.abs(d-t)<hm&&r-v>hm?[t,Math.abs(l-t)<hm?h:r]:Math.abs(v-r)<hm&&e-d>hm?[Math.abs(h-r)<hm?l:e,r]:Math.abs(d-e)<hm&&v-n>hm?[e,Math.abs(l-e)<hm?h:n]:Math.abs(v-n)<hm&&d-t>hm?[Math.abs(h-n)<hm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=am[i])&&(u=o.site,g=u[0]-t,m=u[1]-n,x=g*g+m*m,x<b&&(b=x,y=o));if(y){var w=[t,n],M=[t,r],T=[e,r],N=[e,n];y.halfedges.push(sm.push(Pu(u=y.site,w,M))-1,sm.push(Pu(u,M,T))-1,sm.push(Pu(u,T,N))-1,sm.push(Pu(u,N,w))-1)}}for(i=0;i<_;++i)(o=am[i])&&(o.halfedges.length||delete am[i])}function ju(){Su(this),this.x=this.y=this.arc=this.site=this.cy=null}function Hu(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-pm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=fm.pop()||new ju;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=cm._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}cm.insert(g,y),g||(om=y)}}}}function Xu(t){var n=t.circle;n&&(n.P||(om=n.N),cm.remove(n),fm.push(n),Su(n),t.circle=null)}function Vu(){Su(this),this.edge=this.site=this.circle=null}function Wu(t){var n=lm.pop()||new Vu;return n.site=t,n}function $u(t){Xu(t),um.remove(t),lm.push(t),Su(t)}function Zu(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$u(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<hm&&Math.abs(r-c.circle.cy)<hm;)o=c.P,a.unshift(c),$u(c),c=o;a.unshift(c),Xu(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<hm&&Math.abs(r-s.circle.cy)<hm;)u=s.N,a.push(s),$u(s),s=u;a.push(s),Xu(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],qu(s.edge,c.site,s.site,i);c=a[0],s=a[l-1],s.edge=zu(c.site,s.site,null,i),Hu(c),Hu(s)}function Gu(t){for(var n,e,r,i,o=t[0],u=t[1],a=um._;a;)if(r=Ju(a,u)-o,r>hm)a=a.L;else{if(i=o-Qu(a,u),!(i>hm)){r>-hm?(n=a.P,e=a):i>-hm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}Du(t);var c=Wu(t);if(um.insert(n,c),n||e){if(n===e)return Xu(n),e=Wu(n.site),um.insert(c,e),c.edge=e.edge=zu(n.site,c.site),Hu(n),void Hu(e);if(!e)return void(c.edge=zu(n.site,c.site));Xu(n),Xu(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];qu(e.edge,s,d,x),c.edge=zu(s,t,null,x),e.edge=zu(t,d,null,x),Hu(n),Hu(e)}}function Ju(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-(1/0);e=u.site;var a=e[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Qu(t,n){var e=t.N;if(e)return Ju(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Ku(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function ta(t,n){return n[1]-t[1]||n[0]-t[0]}function na(t,n){var e,r,i,o=t.sort(ta).pop();for(sm=[],am=new Array(t.length),um=new ku,cm=new ku;;)if(i=om,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Gu(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Zu(i.arc)}if(Yu(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Uu(u,a,c,s),Bu(u,a,c,s)}this.edges=sm,this.cells=am,um=cm=sm=am=null}function ea(t,n,e){this.target=t,this.type=n,this.transform=e}function ra(t,n,e){this.k=t,this.x=n,this.y=e}function ia(t){return t.__zoom||_m}function oa(){t.event.stopImmediatePropagation()}function ua(){return!t.event.button}function aa(){var t,n,e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,t=e.width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function ca(){return this.__zoom||_m}function sa(){t.event.stopImmediatePropagation()}function fa(t){return{type:t}}function la(){return!t.event.button}function ha(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function pa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function da(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function va(t){var n=t.__brush;return n?n.dim.output(n.selection):null}function _a(){return ga(km)}function ya(){return ga(Sm)}function ga(n){function e(t){var e=t.property(\"__brush\",a).selectAll(\".overlay\").data([fa(\"overlay\")]);e.enter().append(\"rect\").attr(\"class\",\"overlay\").attr(\"pointer-events\",\"all\").attr(\"cursor\",Em.overlay).merge(e).each(function(){var t=pa(this).extent;gy(this).attr(\"x\",t[0][0]).attr(\"y\",t[0][1]).attr(\"width\",t[1][0]-t[0][0]).attr(\"height\",t[1][1]-t[0][1])}),t.selectAll(\".selection\").data([fa(\"selection\")]).enter().append(\"rect\").attr(\"class\",\"selection\").attr(\"cursor\",Em.selection).attr(\"fill\",\"#777\").attr(\"fill-opacity\",.3).attr(\"stroke\",\"#fff\").attr(\"shape-rendering\",\"crispEdges\");var i=t.selectAll(\".handle\").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append(\"rect\").attr(\"class\",function(t){return\"handle handle--\"+t.type}).attr(\"cursor\",function(t){return Em[t.type]}),t.each(r).attr(\"fill\",\"none\").attr(\"pointer-events\",\"all\").style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\").on(\"mousedown.brush touchstart.brush\",u)}function r(){var t=gy(this),n=pa(this).selection;n?(t.selectAll(\".selection\").style(\"display\",null).attr(\"x\",n[0][0]).attr(\"y\",n[0][1]).attr(\"width\",n[1][0]-n[0][0]).attr(\"height\",n[1][1]-n[0][1]),t.selectAll(\".handle\").style(\"display\",null).attr(\"x\",function(t){return\"e\"===t.type[t.type.length-1]?n[1][0]-h/2:n[0][0]-h/2}).attr(\"y\",function(t){return\"s\"===t.type[0]?n[1][1]-h/2:n[0][1]-h/2}).attr(\"width\",function(t){return\"n\"===t.type||\"s\"===t.type?n[1][0]-n[0][0]+h:h}).attr(\"height\",function(t){return\"e\"===t.type||\"w\"===t.type?n[1][1]-n[0][1]+h:h})):t.selectAll(\".selection,.handle\").style(\"display\",\"none\").attr(\"x\",null).attr(\"y\",null).attr(\"width\",null).attr(\"height\",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=U_(T);!U||w||M||(Math.abs(t[0]-O[0])>Math.abs(t[1]-O[1])?M=!0:w=!0),O=t,b=!0,bm(),o()}function o(){var t;switch(m=O[0]-D[0],x=O[1]-D[1],k){case Mm:case wm:S&&(m=Math.max(P-l,Math.min(L-v,m)),h=l+m,_=v+m),A&&(x=Math.max(q-p,Math.min(R-y,x)),d=p+x,g=y+x);break;case Tm:S<0?(m=Math.max(P-l,Math.min(L-l,m)),h=l+m,_=v):S>0&&(m=Math.max(P-v,Math.min(L-v,m)),h=l,_=v+m),A<0?(x=Math.max(q-p,Math.min(R-p,x)),d=p+x,g=y):A>0&&(x=Math.max(q-y,Math.min(R-y,x)),d=p,g=y+x);break;case Nm:S&&(h=Math.max(P,Math.min(L,l-m*S)),_=Math.max(P,Math.min(L,v+m*S))),A&&(d=Math.max(q,Math.min(R,p-x*A)),g=Math.max(q,Math.min(R,y+x*A)))}_<h&&(S*=-1,t=l,l=v,v=t,t=h,h=_,_=t,N in Cm&&Y.attr(\"cursor\",Em[N=Cm[N]])),g<d&&(A*=-1,t=p,p=y,y=t,t=d,d=g,g=t,N in zm&&Y.attr(\"cursor\",Em[N=zm[N]])),E.selection&&(z=E.selection),w&&(h=z[0][0],_=z[1][0]),M&&(d=z[0][1],g=z[1][1]),z[0][0]===h&&z[0][1]===d&&z[1][0]===_&&z[1][1]===g||(E.selection=[[h,d],[_,g]],r.call(T),F.brush())}function u(){if(sa(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),I.on(\"touchmove.brush touchend.brush touchcancel.brush\",null)}else mu(t.event.view,b),B.on(\"keydown.brush keyup.brush mousemove.brush mouseup.brush\",null);I.attr(\"pointer-events\",\"all\"),Y.attr(\"cursor\",Em.overlay),E.selection&&(z=E.selection),da(z)&&(E.selection=null,r.call(T)),F.end()}function a(){switch(t.event.keyCode){case 16:U=S&&A;break;case 18:k===Tm&&(S&&(v=_-m*S,l=h+m*S),A&&(y=g-x*A,p=d+x*A),k=Nm,o());break;case 32:k!==Tm&&k!==Nm||(S<0?v=_-m:S>0&&(l=h-m),A<0?y=g-x:A>0&&(p=d-x),k=Mm,Y.attr(\"cursor\",Em.selection),o());break;default:return}bm()}function s(){switch(t.event.keyCode){case 16:U&&(w=M=U=!1,o());break;case 18:k===Nm&&(S<0?v=_:S>0&&(l=h),A<0?y=g:A>0&&(p=d),k=Tm,o());break;case 32:k===Mm&&(t.event.altKey?(S&&(v=_-m*S,l=h+m*S),A&&(y=g-x*A,p=d+x*A),k=Nm):(S<0?v=_:S>0&&(l=h),A<0?y=g:A>0&&(p=d),k=Tm),Y.attr(\"cursor\",Em[N]),o());break;default:return}bm()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return bm()}else if(c)return;if(f.apply(this,arguments)){var l,h,p,d,v,_,y,g,m,x,b,w,M,T=this,N=t.event.target.__data__.type,k=\"selection\"===(t.event.metaKey?N=\"overlay\":N)?wm:t.event.altKey?Nm:Tm,S=n===Sm?null:Pm[N],A=n===km?null:qm[N],E=pa(T),C=E.extent,z=E.selection,P=C[0][0],q=C[0][1],L=C[1][0],R=C[1][1],U=S&&A&&t.event.shiftKey,D=U_(T),O=D,F=i(T,arguments).beforestart();\"overlay\"===N?E.selection=z=[[l=n===Sm?P:D[0],p=n===km?q:D[1]],[v=n===Sm?L:l,y=n===km?R:p]]:(l=z[0][0],p=z[0][1],v=z[1][0],y=z[1][1]),h=l,d=p,_=v,g=y;var I=gy(T).attr(\"pointer-events\",\"none\"),Y=I.selectAll(\".overlay\").attr(\"cursor\",Em[N]);if(t.event.touches)I.on(\"touchmove.brush\",e,!0).on(\"touchend.brush touchcancel.brush\",u,!0);else{var B=gy(t.event.view).on(\"keydown.brush\",a,!0).on(\"keyup.brush\",s,!0).on(\"mousemove.brush\",e,!0).on(\"mouseup.brush\",u,!0);nm(t.event.view)}sa(),Py(T),r.call(T),F.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=ha,f=la,l=Pn(e,\"start\",\"brush\",\"end\"),h=6;return e.move=function(t,e){t.selection?t.on(\"start.brush\",function(){i(this,arguments).beforestart().start()}).on(\"interrupt.brush end.brush\",function(){i(this,arguments).end()}).tween(\"brush\",function(){function t(t){u.selection=1===t&&da(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input(\"function\"==typeof e?e.apply(this,arguments):e,u.extent),f=_p(c,s);\nreturn c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input(\"function\"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();Py(t),u.selection=null==a||da(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1===++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit(\"start\")),this},brush:function(){return this.emit(\"brush\"),this},end:function(){return 0===--this.active&&(delete this.state.emitter,this.emit(\"end\")),this},emit:function(t){Xr(new xm(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s=\"function\"==typeof t?t:mm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f=\"function\"==typeof t?t:mm(!!t),e):f},e.handleSize=function(t){return arguments.length?(h=+t,e):h},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function ma(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function xa(t){return t.source}function ba(t){return t.target}function wa(t){return t.radius}function Ma(t){return t.startAngle}function Ta(t){return t.endAngle}function Na(){this.reset()}function ka(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Sa(t){return t>1?0:t<-1?kx:Math.acos(t)}function Aa(t){return t>1?Sx:t<-1?-Sx:Math.asin(t)}function Ea(t){return(t=Ix(t/2))*t}function Ca(){}function za(t,n){t&&Xx.hasOwnProperty(t.type)&&Xx[t.type](t,n)}function Pa(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function qa(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)Pa(t[e],n,1);n.polygonEnd()}function La(){Zx.point=Ua}function Ra(){Da(Vm,Wm)}function Ua(t,n){Zx.point=Da,Vm=t,Wm=n,t*=zx,n*=zx,$m=t,Zm=Rx(n=n/2+Ax),Gm=Ix(n)}function Da(t,n){t*=zx,n*=zx,n=n/2+Ax;var e=t-$m,r=e>=0?1:-1,i=r*e,o=Rx(n),u=Ix(n),a=Gm*u,c=Zm*o+a*Rx(i),s=a*r*Ix(i);Wx.add(Lx(s,c)),$m=t,Zm=o,Gm=u}function Oa(t){return[Lx(t[1],t[0]),Aa(t[2])]}function Fa(t){var n=t[0],e=t[1],r=Rx(e);return[r*Rx(n),r*Ix(n),Ix(e)]}function Ia(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Ya(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Ba(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function ja(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Ha(t){var n=Bx(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function Xa(t,n){ox.push(ux=[Jm=t,Km=t]),n<Qm&&(Qm=n),n>tx&&(tx=n)}function Va(t,n){var e=Fa([t*zx,n*zx]);if(ix){var r=Ya(ix,e),i=[r[1],-r[0],0],o=Ya(i,r);Ha(o),o=Oa(o);var u,a=t-nx,c=a>0?1:-1,s=o[0]*Cx*c,f=Px(a)>180;f^(c*nx<s&&s<c*t)?(u=o[1]*Cx,u>tx&&(tx=u)):(s=(s+360)%360-180,f^(c*nx<s&&s<c*t)?(u=-o[1]*Cx,u<Qm&&(Qm=u)):(n<Qm&&(Qm=n),n>tx&&(tx=n))),f?t<nx?Qa(Jm,t)>Qa(Jm,Km)&&(Km=t):Qa(t,Km)>Qa(Jm,Km)&&(Jm=t):Km>=Jm?(t<Jm&&(Jm=t),t>Km&&(Km=t)):t>nx?Qa(Jm,t)>Qa(Jm,Km)&&(Km=t):Qa(t,Km)>Qa(Jm,Km)&&(Jm=t)}else Xa(t,n);ix=e,nx=t}function Wa(){Qx.point=Va}function $a(){ux[0]=Jm,ux[1]=Km,Qx.point=Xa,ix=null}function Za(t,n){if(ix){var e=t-nx;Jx.add(Px(e)>180?e+(e>0?360:-360):e)}else ex=t,rx=n;Zx.point(t,n),Va(t,n)}function Ga(){Zx.lineStart()}function Ja(){Za(ex,rx),Zx.lineEnd(),Px(Jx)>Tx&&(Jm=-(Km=180)),ux[0]=Jm,ux[1]=Km,ix=null}function Qa(t,n){return(n-=t)<0?n+360:n}function Ka(t,n){return t[0]-n[0]}function tc(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function nc(t,n){t*=zx,n*=zx;var e=Rx(n);ec(e*Rx(t),e*Ix(t),Ix(n))}function ec(t,n,e){++ax,sx+=(t-sx)/ax,fx+=(n-fx)/ax,lx+=(e-lx)/ax}function rc(){tb.point=ic}function ic(t,n){t*=zx,n*=zx;var e=Rx(n);xx=e*Rx(t),bx=e*Ix(t),wx=Ix(n),tb.point=oc,ec(xx,bx,wx)}function oc(t,n){t*=zx,n*=zx;var e=Rx(n),r=e*Rx(t),i=e*Ix(t),o=Ix(n),u=Lx(Bx((u=bx*o-wx*i)*u+(u=wx*r-xx*o)*u+(u=xx*i-bx*r)*u),xx*r+bx*i+wx*o);cx+=u,hx+=u*(xx+(xx=r)),px+=u*(bx+(bx=i)),dx+=u*(wx+(wx=o)),ec(xx,bx,wx)}function uc(){tb.point=nc}function ac(){tb.point=sc}function cc(){fc(gx,mx),tb.point=nc}function sc(t,n){gx=t,mx=n,t*=zx,n*=zx,tb.point=fc;var e=Rx(n);xx=e*Rx(t),bx=e*Ix(t),wx=Ix(n),ec(xx,bx,wx)}function fc(t,n){t*=zx,n*=zx;var e=Rx(n),r=e*Rx(t),i=e*Ix(t),o=Ix(n),u=bx*o-wx*i,a=wx*r-xx*o,c=xx*i-bx*r,s=Bx(u*u+a*a+c*c),f=xx*r+bx*i+wx*o,l=s&&-Sa(f)/s,h=Lx(s,f);vx+=l*u,_x+=l*a,yx+=l*c,cx+=h,hx+=h*(xx+(xx=r)),px+=h*(bx+(bx=i)),dx+=h*(wx+(wx=o)),ec(xx,bx,wx)}function lc(t,n){return[t>kx?t-Ex:t<-kx?t+Ex:t,n]}function hc(t,n,e){return(t%=Ex)?n||e?rb(dc(t),vc(n,e)):dc(t):n||e?vc(n,e):lc}function pc(t){return function(n,e){return n+=t,[n>kx?n-Ex:n<-kx?n+Ex:n,e]}}function dc(t){var n=pc(t);return n.invert=pc(-t),n}function vc(t,n){function e(t,n){var e=Rx(n),a=Rx(t)*e,c=Ix(t)*e,s=Ix(n),f=s*r+a*i;return[Lx(c*o-f*u,a*r-s*i),Aa(f*o+c*u)]}var r=Rx(t),i=Ix(t),o=Rx(n),u=Ix(n);return e.invert=function(t,n){var e=Rx(n),a=Rx(t)*e,c=Ix(t)*e,s=Ix(n),f=s*o-c*u;return[Lx(c*o+s*u,a*r+f*i),Aa(f*r-a*i)]},e}function _c(t,n,e,r,i,o){if(e){var u=Rx(n),a=Ix(n),c=r*e;null==i?(i=n+r*Ex,o=n-c/2):(i=yc(u,i),o=yc(u,o),(r>0?i<o:i>o)&&(i+=r*Ex));for(var s,f=i;r>0?f>o:f<o;f-=c)s=Oa([u,-a*Rx(f),-a*Ix(f)]),t.point(s[0],s[1])}}function yc(t,n){n=Fa(n),n[0]-=t,Ha(n);var e=Sa(-n[1]);return((-n[2]<0?-e:e)+Ex-Tx)%Ex}function gc(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function mc(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function xc(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0){do s.point(0===f||3===f?t:e,f>1?r:n);while((f=(f+a+4)%4)!==l)}else s.point(o[0],o[1])}function u(r,i){return Px(r[0]-t)<Tx?i>0?0:3:Px(r[0]-e)<Tx?i>0?2:1:Px(r[1]-n)<Tx?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&k.point(t,n)}function s(){for(var n=0,e=0,i=_.length;e<i;++e)for(var o,u,a=_[e],c=1,s=a.length,f=a[0],l=f[0],h=f[1];c<s;++c)o=l,u=h,f=a[c],l=f[0],h=f[1],u<=r?h>r&&(l-o)*(r-u)>(h-u)*(t-o)&&++n:h<=r&&(l-o)*(r-u)<(h-u)*(t-o)&&--n;return n}function f(){k=S,v=[],_=[],N=!0}function l(){var t=s(),n=N&&t,e=(v=Js(v)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&xb(v,a,t,o,u),u.polygonEnd()),k=u,v=_=y=null}function h(){A.point=d,_&&_.push(y=[]),T=!0,M=!1,b=w=NaN}function p(){v&&(d(g,m),x&&M&&S.rejoin(),v.push(S.result())),A.point=c,M&&k.lineEnd()}function d(o,u){var a=i(o,u);if(_&&y.push([o,u]),T)g=o,m=u,x=a,T=!1,a&&(k.lineStart(),k.point(o,u));else if(a&&M)k.point(o,u);else{var c=[b=Math.max(wb,Math.min(bb,b)),w=Math.max(wb,Math.min(bb,w))],s=[o=Math.max(wb,Math.min(bb,o)),u=Math.max(wb,Math.min(bb,u))];gb(c,s,t,n,e,r)?(M||(k.lineStart(),k.point(c[0],c[1])),k.point(s[0],s[1]),a||k.lineEnd(),N=!1):a&&(k.lineStart(),k.point(o,u),N=!1)}b=o,w=u,M=a}var v,_,y,g,m,x,b,w,M,T,N,k=u,S=yb(),A={point:c,lineStart:h,lineEnd:p,polygonStart:f,polygonEnd:l};return A}}function bc(){Nb.point=Mc,Nb.lineEnd=wc}function wc(){Nb.point=Nb.lineEnd=Ca}function Mc(t,n){t*=zx,n*=zx,ib=t,ob=Ix(n),ub=Rx(n),Nb.point=Tc}function Tc(t,n){t*=zx,n*=zx;var e=Ix(n),r=Rx(n),i=Px(t-ib),o=Rx(i),u=Ix(i),a=r*u,c=ub*e-ob*r*o,s=ob*e+ub*r*o;Tb.add(Lx(Bx(a*a+c*c),s)),ib=t,ob=e,ub=r}function Nc(t,n,e){var r=Os(t,n-Tx,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function kc(t,n,e){var r=Os(t,n-Tx,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Sc(){function t(){return{type:\"MultiLineString\",coordinates:n()}}function n(){return Os(Ux(o/_)*_,i,_).map(h).concat(Os(Ux(s/y)*y,c,y).map(p)).concat(Os(Ux(r/d)*d,e,d).filter(function(t){return Px(t%_)>Tx}).map(f)).concat(Os(Ux(a/v)*v,u,v).filter(function(t){return Px(t%y)>Tx}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:\"LineString\",coordinates:t}})},t.outline=function(){return{type:\"Polygon\",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Nc(a,u,90),l=kc(r,e,g),h=Nc(s,c,90),p=kc(o,i,g),t):g},t.extentMajor([[-180,-90+Tx],[180,90-Tx]]).extentMinor([[-180,-80-Tx],[180,80+Tx]])}function Ac(){return Sc()()}function Ec(){Lb.point=Cc}function Cc(t,n){Lb.point=zc,ab=sb=t,cb=fb=n}function zc(t,n){qb.add(fb*t-sb*n),sb=t,fb=n}function Pc(){zc(ab,cb)}function qc(t,n){t<Rb&&(Rb=t),t>Db&&(Db=t),n<Ub&&(Ub=n),n>Ob&&(Ob=n)}function Lc(t,n){Ib+=t,Yb+=n,++Bb}function Rc(){Zb.point=Uc}function Uc(t,n){Zb.point=Dc,Lc(pb=t,db=n)}function Dc(t,n){var e=t-pb,r=n-db,i=Bx(e*e+r*r);jb+=i*(pb+t)/2,Hb+=i*(db+n)/2,Xb+=i,Lc(pb=t,db=n)}function Oc(){Zb.point=Lc}function Fc(){Zb.point=Yc}function Ic(){Bc(lb,hb)}function Yc(t,n){Zb.point=Bc,Lc(lb=pb=t,hb=db=n)}function Bc(t,n){var e=t-pb,r=n-db,i=Bx(e*e+r*r);jb+=i*(pb+t)/2,Hb+=i*(db+n)/2,Xb+=i,i=db*t-pb*n,Vb+=i*(pb+t),Wb+=i*(db+n),$b+=3*i,Lc(pb=t,db=n)}function jc(t){this._context=t}function Hc(){this._string=[]}function Xc(t){return\"m0,\"+t+\"a\"+t+\",\"+t+\" 0 1,1 0,\"+-2*t+\"a\"+t+\",\"+t+\" 0 1,1 0,\"+2*t+\"z\"}function Vc(t){return t.length>1}function Wc(t,n){return((t=t.x)[0]<0?t[1]-Sx-Tx:Sx-t[1])-((n=n.x)[0]<0?n[1]-Sx-Tx:Sx-n[1])}function $c(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?kx:-kx,c=Px(o-e);Px(c-kx)<Tx?(t.point(e,r=(r+u)/2>0?Sx:-Sx),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=kx&&(Px(e-i)<Tx&&(e-=i*Tx),Px(o-a)<Tx&&(o-=a*Tx),r=Zc(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}function Zc(t,n,e,r){var i,o,u=Ix(t-e);return Px(u)>Tx?qx((Ix(n)*(o=Rx(r))*Ix(e)-Ix(r)*(i=Rx(n))*Ix(t))/(i*o*u)):(n+r)/2}function Gc(t,n,e,r){var i;if(null==t)i=e*Sx,r.point(-kx,i),r.point(0,i),r.point(kx,i),r.point(kx,0),r.point(kx,-i),r.point(0,-i),r.point(-kx,-i),r.point(-kx,0),r.point(-kx,i);else if(Px(t[0]-n[0])>Tx){var o=t[0]<n[0]?kx:-kx;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}function Jc(t){return function(n){var e=new Qc;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Qc(){}function Kc(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Vx(e,t.stream(Fb));var u=Fb.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ts(t,n,e){return Kc(t,[[0,0],n],e)}function ns(t){return Jc({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function es(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=Bx(x*x+b*b+w*w),T=Aa(w/=M),N=Px(Px(w)-1)<Tx||Px(o-l)<Tx?(o+l)/2:Lx(b,x),k=t(N,T),S=k[0],A=k[1],E=S-r,C=A-i,z=g*E-y*C;(z*z/m>n||Px((y*E+g*C)/m-.5)>.3||u*h+a*p+c*d<iw)&&(e(r,i,o,u,a,c,S,A,N,x/=M,b/=M,w,v,_),_.point(S,A),e(S,A,N,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=Fa([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],rw,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,rw,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function rs(t){return is(function(){return t})()}function is(t){function n(t){return t=f(t[0]*zx,t[1]*zx),[t[0]*_+a,c-t[1]*_]}function e(t){return t=f.invert((t[0]-a)/_,(c-t[1])/_),t&&[t[0]*Cx,t[1]*Cx]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=rb(s=hc(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,N=tw,k=null,S=zb,A=.5,E=ow(r,A);return n.stream=function(t){return d&&v===t?d:d=uw(N(s,E(S(v=t))))},n.clipAngle=function(t){return arguments.length?(N=+t?nw(T=t*zx,6*zx):(T=null,tw),o()):T*Cx},n.clipExtent=function(t){return arguments.length?(S=null==t?(k=l=h=p=null,zb):xc(k=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==k?null:[[k,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*zx,x=t[1]%360*zx,i()):[m*Cx,x*Cx]},n.rotate=function(t){return arguments.length?(b=t[0]%360*zx,w=t[1]%360*zx,M=t.length>2?t[2]%360*zx:0,i()):[b*Cx,w*Cx,M*Cx]},n.precision=function(t){return arguments.length?(E=ow(r,A=t*t),o()):Bx(A)},n.fitExtent=function(t,e){return Kc(n,t,e)},n.fitSize=function(t,e){return ts(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function os(t){var n=0,e=kx/3,r=is(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*zx,e=t[1]*zx):[n*Cx,e*Cx]},i}function us(t){function n(t,n){return[t*e,Ix(n)/e]}var e=Rx(t);return n.invert=function(t,n){return[t/e,Aa(n*e)]},n}function as(t,n){function e(t,n){var e=Bx(o-2*i*Ix(n))/i;return[e*Ix(t*=i),u-e*Rx(t)]}var r=Ix(t),i=(r+Ix(n))/2;if(Px(i)<Tx)return us(t);var o=1+r*(2*i-r),u=Bx(o)/i;return e.invert=function(t,n){var e=u-n;return[Lx(t,Px(e))/i*Yx(e),Aa((o-(t*t+e*e)*i*i)/(2*i))]},e}function cs(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function ss(t){return function(n,e){var r=Rx(n),i=Rx(e),o=t(r*i);return[o*i*Ix(n),o*Ix(e)]}}function fs(t){return function(n,e){var r=Bx(n*n+e*e),i=t(r),o=Ix(i),u=Rx(i);return[Lx(n*o,r*u),Aa(r&&e*o/r)]}}function ls(t,n){return[t,Ox(jx((Sx+n)/2))]}function hs(t){var n,e=rs(t),r=e.scale,i=e.translate,o=e.clipExtent;return e.scale=function(t){return arguments.length?(r(t),n&&e.clipExtent(null),e):r()},e.translate=function(t){return arguments.length?(i(t),n&&e.clipExtent(null),e):i()},e.clipExtent=function(t){if(!arguments.length)return n?null:o();if(n=null==t){var u=kx*r(),a=i();t=[[a[0]-u,a[1]-u],[a[0]+u,a[1]+u]]}return o(t),e},e.clipExtent(null)}function ps(t){return jx((Sx+t)/2)}function ds(t,n){function e(t,n){o>0?n<-Sx+Tx&&(n=-Sx+Tx):n>Sx-Tx&&(n=Sx-Tx);var e=o/Fx(ps(n),i);return[e*Ix(i*t),o-e*Rx(i*t)]}var r=Rx(t),i=t===n?Ix(t):Ox(r/Rx(n))/Ox(ps(n)/ps(t)),o=r*Fx(ps(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=Yx(i)*Bx(t*t+e*e);return[Lx(t,Px(e))/i*Yx(e),2*qx(Fx(o/r,1/i))-Sx]},e):ls}function vs(t,n){return[t,n]}function _s(t,n){function e(t,n){var e=o-n,r=i*t;return[e*Ix(r),o-e*Rx(r)]}var r=Rx(t),i=t===n?Ix(t):(r-Rx(n))/(n-t),o=r/i+t;return Px(i)<Tx?vs:(e.invert=function(t,n){var e=o-n;return[Lx(t,Px(e))/i*Yx(e),o-Yx(i)*Bx(t*t+e*e)]},e)}function ys(t,n){var e=Rx(n),r=Rx(t)*e;return[e*Ix(t)/r,Ix(n)/r]}function gs(t,n,e){return 1===t&&0===n&&0===e?zb:Jc({point:function(r,i){this.stream.point(r*t+n,i*t+e)}})}function ms(t,n){return[Rx(n)*Ix(t),Ix(n)]}function xs(t,n){var e=Rx(n),r=1+Rx(t)*e;return[e*Ix(t)/r,Ix(n)/r]}function bs(t,n){return[Ox(jx((Sx+n)/2)),-t]}var ws=\"4.3.0\",Ms=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},Ts=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},Ns=Ts(Ms),ks=Ns.right,Ss=Ns.left,As=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Es=function(t){return null===t?NaN:+t},Cs=function(t,n){var e,r,i=t.length,o=0,u=0,a=-1,c=0;if(null==n)for(;++a<i;)isNaN(e=Es(t[a]))||(r=e-o,o+=r/++c,u+=r*(e-o));else for(;++a<i;)isNaN(e=Es(n(t[a],a,t)))||(r=e-o,o+=r/++c,u+=r*(e-o));if(c>1)return u/(c-1)},zs=function(t,n){var e=Cs(t,n);return e?Math.sqrt(e):e},Ps=function(t,n){var e,r,i,o=-1,u=t.length;if(null==n){for(;++o<u;)if(null!=(r=t[o])&&r>=r){e=i=r;break}for(;++o<u;)null!=(r=t[o])&&(e>r&&(e=r),i<r&&(i=r))}else{for(;++o<u;)if(null!=(r=n(t[o],o,t))&&r>=r){e=i=r;break}for(;++o<u;)null!=(r=n(t[o],o,t))&&(e>r&&(e=r),i<r&&(i=r))}return[e,i]},qs=Array.prototype,Ls=qs.slice,Rs=qs.map,Us=function(t){return function(){return t}},Ds=function(t){return t},Os=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Fs=Math.sqrt(50),Is=Math.sqrt(10),Ys=Math.sqrt(2),Bs=function(t,n,r){var i=e(t,n,r);return Os(Math.ceil(t/i)*i,Math.floor(n/i)*i+i/2,i)},js=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},Hs=function(){function t(t){var i,o,u=t.length,a=new Array(u);for(i=0;i<u;++i)a[i]=n(t[i],i,t);var c=e(a),s=c[0],f=c[1],l=r(a,s,f);Array.isArray(l)||(l=Bs(s,f,l));for(var h=l.length;l[0]<=s;)l.shift(),--h;for(;l[h-1]>=f;)l.pop(),--h;var p,d=new Array(h+1);for(i=0;i<=h;++i)p=d[i]=[],p.x0=i>0?l[i-1]:s,p.x1=i<h?l[i]:f;for(i=0;i<u;++i)o=a[i],s<=o&&o<=f&&d[ks(l,o,0,h)].push(t[i]);return d}var n=Ds,e=Ps,r=js;return t.value=function(e){return arguments.length?(n=\"function\"==typeof e?e:Us(e),t):n},t.domain=function(n){return arguments.length?(e=\"function\"==typeof n?n:Us([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r=\"function\"==typeof n?n:Us(Array.isArray(n)?Ls.call(n):n),t):r},t},Xs=function(t,n,e){if(null==e&&(e=Es),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t),a=+e(t[o+1],o+1,t);return u+(a-u)*(i-o)}},Vs=function(t,n,e){return t=Rs.call(t,Es).sort(Ms),Math.ceil((e-n)/(2*(Xs(t,.75)-Xs(t,.25))*Math.pow(t.length,-1/3)))},Ws=function(t,n,e){return Math.ceil((e-n)/(3.5*zs(t)*Math.pow(t.length,-1/3)))},$s=function(t,n){var e,r,i=-1,o=t.length;if(null==n){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&r>e&&(e=r)}else{for(;++i<o;)if(null!=(r=n(t[i],i,t))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n(t[i],i,t))&&r>e&&(e=r)}return e},Zs=function(t,n){var e,r=0,i=t.length,o=-1,u=i;if(null==n)for(;++o<i;)isNaN(e=Es(t[o]))?--u:r+=e;else for(;++o<i;)isNaN(e=Es(n(t[o],o,t)))?--u:r+=e;if(u)return r/u},Gs=function(t,n){var e,r=[],i=t.length,o=-1;if(null==n)for(;++o<i;)isNaN(e=Es(t[o]))||r.push(e);else for(;++o<i;)isNaN(e=Es(n(t[o],o,t)))||r.push(e);return Xs(r.sort(Ms),.5)},Js=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(r=t[i],n=r.length;--n>=0;)e[--u]=r[n];return e},Qs=function(t,n){var e,r,i=-1,o=t.length;if(null==n){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&e>r&&(e=r)}else{for(;++i<o;)if(null!=(r=n(t[i],i,t))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n(t[i],i,t))&&e>r&&(e=r)}return e},Ks=function(t){for(var n=0,e=t.length-1,r=t[0],i=new Array(e<0?0:e);n<e;)i[n]=[r,r=t[++n]];return i},tf=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},nf=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(n||(n=Ms);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},ef=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},rf=function(t,n){var e,r=0,i=t.length,o=-1;if(null==n)for(;++o<i;)(e=+t[o])&&(r+=e);else for(;++o<i;)(e=+n(t[o],o,t))&&(r+=e);return r},of=function(t){if(!(o=t.length))return[];for(var n=-1,e=Qs(t,r),i=new Array(e);++n<e;)for(var o,u=-1,a=i[n]=new Array(o);++u<o;)a[u]=t[u][n];return i},uf=function(){return of(arguments)},af=\"$\";i.prototype=o.prototype={constructor:i,has:function(t){return af+t in this},get:function(t){return this[af+t]},set:function(t,n){return this[af+t]=n,this},remove:function(t){var n=af+t;return n in this&&delete this[n]},clear:function(){for(var t in this)t[0]===af&&delete this[t]},keys:function(){var t=[];for(var n in this)n[0]===af&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)n[0]===af&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)n[0]===af&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)n[0]===af&&++t;return t},empty:function(){for(var t in this)if(t[0]===af)return!1;return!0},each:function(t){for(var n in this)n[0]===af&&t(this[n],n.slice(1),this)}};var cf=function(){function t(n,i,u,a){if(i>=f.length)return null!=r?r(n):null!=e?n.sort(e):n;for(var c,s,l,h=-1,p=n.length,d=f[i++],v=o(),_=u();++h<p;)(l=v.get(c=d(s=n[h])+\"\"))?l.push(s):v.set(c,[s]);return v.each(function(n,e){a(_,e,t(n,i,u,a))}),_}function n(t,e){if(++e>f.length)return t;var i,o=l[e-1];return null!=r&&e>=f.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=o?i.sort(function(t,n){return o(t.key,n.key)}):i}var e,r,i,f=[],l=[];return i={object:function(n){return t(n,0,u,a)},map:function(n){return t(n,0,c,s)},entries:function(e){return n(t(e,0,c,s),0)},key:function(t){return f.push(t),i},sortKeys:function(t){return l[f.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},sf=o.prototype;f.prototype=l.prototype={constructor:f,has:sf.has,add:function(t){return t+=\"\",this[af+t]=t,this},remove:sf.remove,clear:sf.clear,values:sf.keys,size:sf.size,empty:sf.empty,each:sf.each};var ff=function(t){var n=[];for(var e in t)n.push(e);return n},lf=function(t){var n=[];for(var e in t)n.push(t[e]);return n},hf=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},pf=function(t,n){return t=null==t?0:+t,n=null==n?1:+n,1===arguments.length?(n=t,t=0):n-=t,function(){return Math.random()*n+t}},df=function(t,n){var e,r;return t=null==t?0:+t,n=null==n?1:+n,function(){var i;if(null!=e)i=e,e=null;else do e=2*Math.random()-1,i=2*Math.random()-1,r=e*e+i*i;while(!r||r>1);return t+n*i*Math.sqrt(-2*Math.log(r)/r)}},vf=function(){var t=df.apply(this,arguments);return function(){return Math.exp(t())}},_f=function(t){return function(){for(var n=0,e=0;e<t;++e)n+=Math.random();return n}},yf=function(t){var n=_f(t);return function(){return n()/t}},gf=function(t){return function(){return-Math.log(1-Math.random())/t}},mf=3,xf=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(mf),bf=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(mf),wf=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(mf),Mf=Math.PI,Tf=Mf/2,Nf=4/11,kf=6/11,Sf=8/11,Af=.75,Ef=9/11,Cf=10/11,zf=.9375,Pf=21/22,qf=63/64,Lf=1/Nf/Nf,Rf=1.70158,Uf=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(Rf),Df=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(Rf),Of=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Rf),Ff=2*Math.PI,If=1,Yf=.3,Bf=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),jf=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),Hf=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=Ff);return r.amplitude=function(n){return t(n,e*Ff)},r.period=function(e){return t(n,e)},r}(If,Yf),Xf=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},Vf=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},Wf=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},$f=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(z),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=P(r),u=P(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},Zf=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)o=t[l],e=o[0],r=o[1],r>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},Gf=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,o=t[r],u=o[0],a=o[1],n-=u,e-=a,c+=Math.sqrt(n*n+e*e);return c},Jf=Math.PI,Qf=2*Jf,Kf=1e-6,tl=Qf-Kf;q.prototype=L.prototype={constructor:q,moveTo:function(t,n){this._.push(\"M\",this._x0=this._x1=+t,\",\",this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._.push(\"Z\"))},lineTo:function(t,n){this._.push(\"L\",this._x1=+t,\",\",this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._.push(\"Q\",+t,\",\",+n,\",\",this._x1=+e,\",\",this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._.push(\"C\",+t,\",\",+n,\",\",+e,\",\",+r,\",\",this._x1=+i,\",\",this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error(\"negative radius: \"+i);if(null===this._x1)this._.push(\"M\",this._x1=t,\",\",this._y1=n);else if(l>Kf)if(Math.abs(f*a-c*s)>Kf&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Jf-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>Kf&&this._.push(\"L\",t+m*s,\",\",n+m*f),this._.push(\"A\",i,\",\",i,\",0,0,\",+(f*h>s*p),\",\",this._x1=t+x*a,\",\",this._y1=n+x*c)}else this._.push(\"L\",this._x1=t,\",\",this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,e=+e;var u=e*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error(\"negative radius: \"+e);null===this._x1?this._.push(\"M\",c,\",\",s):(Math.abs(this._x1-c)>Kf||Math.abs(this._y1-s)>Kf)&&this._.push(\"L\",c,\",\",s),e&&(l>tl?this._.push(\"A\",e,\",\",e,\",0,1,\",f,\",\",t-u,\",\",n-a,\"A\",e,\",\",e,\",0,1,\",f,\",\",this._x1=c,\",\",this._y1=s):(l<0&&(l=l%Qf+Qf),this._.push(\"A\",e,\",\",e,\",0,\",+(l>=Jf),\",\",f,\",\",this._x1=t+e*Math.cos(i),\",\",this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._.push(\"M\",this._x0=this._x1=+t,\",\",this._y0=this._y1=+n,\"h\",+e,\"v\",+r,\"h\",-e,\"Z\")},toString:function(){return this._.join(\"\")}};var nl=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return R(this.cover(n,e),n,e,t)},el=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do u=new Array(4),u[a]=s,s=u;while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do u=new Array(4),u[a]=s,s=u;while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do u=new Array(4),u[a]=s,s=u;while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do u=new Array(4),u[a]=s,s=u;while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},rl=function(){var t=[];return this.visit(function(n){if(!n.length)do t.push(n.data);while(n=n.next)}),t},il=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},ol=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},ul=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ol(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ol(v[3],_,y,u,a),new ol(v[2],i,y,_,a),new ol(v[1],_,o,u,y),new ol(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},al=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},cl=function(){return this._root},sl=function(){var t=0;return this.visit(function(n){if(!n.length)do++t;while(n=n.next)}),t},fl=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ol(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ol(e,s,f,o,u)),(e=c[2])&&a.push(new ol(e,r,f,s,u)),(e=c[1])&&a.push(new ol(e,s,i,o,f)),(e=c[0])&&a.push(new ol(e,r,i,s,f))}return this},ll=function(t){var n,e=[],r=[];for(this._root&&e.push(new ol(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ol(o,u,a,f,l)),(o=i[1])&&e.push(new ol(o,f,a,c,l)),(o=i[2])&&e.push(new ol(o,u,l,f,s)),(o=i[3])&&e.push(new ol(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},hl=function(t){return arguments.length?(this._x=t,this):this._x},pl=function(t){return arguments.length?(this._y=t,this):this._y},dl=I.prototype=Y.prototype;dl.copy=function(){var t,n,e=new Y(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=B(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=B(n));return e},dl.add=nl,dl.addAll=U,dl.cover=el,dl.data=rl,dl.extent=il,dl.find=ul,dl.remove=al,dl.removeAll=D,dl.root=cl,dl.size=sl,dl.visit=fl,dl.visitAfter=ll,dl.x=hl,dl.y=pl;var vl=[].slice,_l={};j.prototype=Z.prototype={constructor:j,defer:function(t){if(\"function\"!=typeof t||this._call)throw new Error;if(null!=this._error)return this;var n=vl.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),H(this),this},abort:function(){return null==this._error&&W(this,new Error(\"abort\")),this},await:function(t){if(\"function\"!=typeof t||this._call)throw new Error;return this._call=function(n,e){t.apply(null,[n].concat(e))},$(this),this},awaitAll:function(t){if(\"function\"!=typeof t||this._call)throw new Error;return this._call=t,$(this),this}};var yl=function(t){\nreturn function(){return t}},gl=1e-12,ml=Math.PI,xl=ml/2,bl=2*ml,wl=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-xl,p=u.apply(this,arguments)-xl,d=Math.abs(p-h),v=p>h;if(c||(c=t=L()),l<f&&(s=l,l=f,f=s),l>gl)if(d>bl-gl)c.moveTo(l*Math.cos(h),l*Math.sin(h)),c.arc(0,0,l,h,p,!v),f>gl&&(c.moveTo(f*Math.cos(p),f*Math.sin(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,N=T>gl&&(i?+i.apply(this,arguments):Math.sqrt(f*f+l*l)),k=Math.min(Math.abs(l-f)/2,+r.apply(this,arguments)),S=k,A=k;if(N>gl){var E=nt(N/f*Math.sin(T)),C=nt(N/l*Math.sin(T));(w-=2*E)>gl?(E*=v?1:-1,x+=E,b-=E):(w=0,x=b=(h+p)/2),(M-=2*C)>gl?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*Math.cos(g),P=l*Math.sin(g),q=f*Math.cos(b),R=f*Math.sin(b);if(k>gl){var U=l*Math.cos(m),D=l*Math.sin(m),O=f*Math.cos(x),F=f*Math.sin(x);if(d<ml){var I=w>gl?et(z,P,O,F,U,D,q,R):[q,R],Y=z-I[0],B=P-I[1],j=U-I[0],H=D-I[1],X=1/Math.sin(Math.acos((Y*j+B*H)/(Math.sqrt(Y*Y+B*B)*Math.sqrt(j*j+H*H)))/2),V=Math.sqrt(I[0]*I[0]+I[1]*I[1]);S=Math.min(k,(f-V)/(X-1)),A=Math.min(k,(l-V)/(X+1))}}M>gl?A>gl?(_=rt(O,F,z,P,l,A,v),y=rt(U,D,q,R,l,A,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),A<k?c.arc(_.cx,_.cy,A,Math.atan2(_.y01,_.x01),Math.atan2(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,A,Math.atan2(_.y01,_.x01),Math.atan2(_.y11,_.x11),!v),c.arc(0,0,l,Math.atan2(_.cy+_.y11,_.cx+_.x11),Math.atan2(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,A,Math.atan2(y.y11,y.x11),Math.atan2(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>gl&&w>gl?S>gl?(_=rt(q,R,U,D,f,-S,v),y=rt(z,P,O,F,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<k?c.arc(_.cx,_.cy,S,Math.atan2(_.y01,_.x01),Math.atan2(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,Math.atan2(_.y01,_.x01),Math.atan2(_.y11,_.x11),!v),c.arc(0,0,f,Math.atan2(_.cy+_.y11,_.cx+_.x11),Math.atan2(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,Math.atan2(y.y11,y.x11),Math.atan2(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(q,R)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+\"\"||null}var n=G,e=J,r=yl(0),i=null,o=Q,u=K,a=tt,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-ml/2;return[Math.cos(r)*t,Math.sin(r)*t]},t.innerRadius=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.outerRadius=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r=\"function\"==typeof n?n:yl(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:\"function\"==typeof n?n:yl(+n),t):i},t.startAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:yl(+n),t):o},t.endAngle=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(+n),t):u},t.padAngle=function(n){return arguments.length?(a=\"function\"==typeof n?n:yl(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t};it.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Ml=function(t){return new it(t)},Tl=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=L())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+\"\"||null}var n=ot,e=ut,r=yl(!0),i=null,o=Ml,u=null;return t.x=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.y=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.defined=function(n){return arguments.length?(r=\"function\"==typeof n?n:yl(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},Nl=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=L())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+\"\"||null}function n(){return Tl().defined(u).curve(c).context(a)}var e=ot,r=null,i=yl(0),o=ut,u=yl(!0),a=null,c=Ml,s=null;return t.x=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:\"function\"==typeof n?n:yl(+n),t):r},t.y=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:\"function\"==typeof n?n:yl(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},kl=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},Sl=function(t){return t},Al=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(bl,Math.max(-bl,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],l=v[c],f=_+(l>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=Sl,e=kl,r=null,i=yl(0),o=yl(bl),u=yl(0);return t.value=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.endAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:yl(+n),t):o},t.padAngle=function(n){return arguments.length?(u=\"function\"==typeof n?n:yl(+n),t):u},t},El=ct(Ml);at.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var Cl=function(){return st(Tl().curve(El))},zl=function(){var t=Nl().curve(El),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return st(e())},delete t.lineX0,t.lineEndAngle=function(){return st(r())},delete t.lineX1,t.lineInnerRadius=function(){return st(i())},delete t.lineY0,t.lineOuterRadius=function(){return st(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(ct(t)):n()._curve},t},Pl={draw:function(t,n){var e=Math.sqrt(n/ml);t.moveTo(e,0),t.arc(0,0,e,0,bl)}},ql={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Ll=Math.sqrt(1/3),Rl=2*Ll,Ul={draw:function(t,n){var e=Math.sqrt(n/Rl),r=e*Ll;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Dl=.8908130915292852,Ol=Math.sin(ml/10)/Math.sin(7*ml/10),Fl=Math.sin(bl/10)*Ol,Il=-Math.cos(bl/10)*Ol,Yl={draw:function(t,n){var e=Math.sqrt(n*Dl),r=Fl*e,i=Il*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=bl*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},Bl={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},jl=Math.sqrt(3),Hl={draw:function(t,n){var e=-Math.sqrt(n/(3*jl));t.moveTo(0,2*e),t.lineTo(-jl*e,-e),t.lineTo(jl*e,-e),t.closePath()}},Xl=-.5,Vl=Math.sqrt(3)/2,Wl=1/Math.sqrt(12),$l=3*(Wl/2+1),Zl={draw:function(t,n){var e=Math.sqrt(n/$l),r=e/2,i=e*Wl,o=r,u=e*Wl+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Xl*r-Vl*i,Vl*r+Xl*i),t.lineTo(Xl*o-Vl*u,Vl*o+Xl*u),t.lineTo(Xl*a-Vl*c,Vl*a+Xl*c),t.lineTo(Xl*r+Vl*i,Xl*i-Vl*r),t.lineTo(Xl*o+Vl*u,Xl*u-Vl*o),t.lineTo(Xl*a+Vl*c,Xl*c-Vl*a),t.closePath()}},Gl=[Pl,ql,Ul,Bl,Yl,Hl,Zl],Jl=function(){function t(){var t;if(r||(r=t=L()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+\"\"||null}var n=yl(Pl),e=yl(64),r=null;return t.type=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(e),t):n},t.size=function(n){return arguments.length?(e=\"function\"==typeof n?n:yl(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},Ql=function(){};lt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:ft(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var Kl=function(t){return new lt(t)};ht.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var th=function(t){return new ht(t)};pt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:ft(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var nh=function(t){return new pt(t)};dt.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var eh=function t(n){function e(t){return 1===n?new lt(t):new dt(t,n)}return e.beta=function(n){return t(+n)},e}(.85);_t.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:vt(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var rh=function t(n){function e(t){return new _t(t,n)}return e.tension=function(n){return t(+n)},e}(0);yt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ih=function t(n){function e(t){return new yt(t,n)}return e.tension=function(n){return t(+n)},e}(0);gt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:vt(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var oh=function t(n){function e(t){return new gt(t,n)}return e.tension=function(n){return t(+n)},e}(0);xt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var uh=function t(n){function e(t){return n?new xt(t,n):new _t(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);bt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ah=function t(n){function e(t){return n?new bt(t,n):new yt(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);wt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:mt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var ch=function t(n){function e(t){return n?new wt(t,n):new gt(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);Mt.prototype={areaStart:Ql,areaEnd:Ql,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};var sh=function(t){return new Mt(t)};At.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:St(this,this._t0,kt(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,St(this,kt(this,e=Nt(this,t,n)),e);break;default:St(this,this._t0,e=Nt(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Et.prototype=Object.create(At.prototype)).point=function(t,n){At.prototype.point.call(this,n,t)},Ct.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},qt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=Lt(t),i=Lt(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var fh=function(t){return new qt(t)};Rt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var lh=function(t){return new Rt(t,.5)},hh=Array.prototype.slice,ph=function(t,n){if((r=t.length)>1)for(var e,r,i=1,o=t[n[0]],u=o.length;i<r;++i){e=o,o=t[n[i]];for(var a=0;a<u;++a)o[a][1]+=o[a][0]=isNaN(e[a][1])?e[a][0]:e[a][1]}},dh=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},vh=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=yl([]),e=dh,r=ph,i=Ot;return t.keys=function(e){return arguments.length?(n=\"function\"==typeof e?e:yl(hh.call(e)),t):n},t.value=function(n){return arguments.length?(i=\"function\"==typeof n?n:yl(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?dh:\"function\"==typeof n?n:yl(hh.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?ph:n,t):r},t},_h=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}ph(t,n)}},yh=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}ph(t,n)}},gh=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=f[u-1][1]||0,p=(l-h)/2,d=0;d<a;++d){var v=t[n[d]],_=v[u][1]||0,y=v[u-1][1]||0;p+=_-y}c+=l,s+=p*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,ph(t,n)}},mh=function(t){var n=t.map(Ft);return dh(t).sort(function(t,e){return n[t]-n[e]})},xh=function(t){return mh(t).reverse()},bh=function(t){var n,e,r=t.length,i=t.map(Ft),o=dh(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},wh=function(t){return dh(t).reverse()},Mh=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},Th=.7,Nh=1/Th,kh=/^#([0-9a-f]{3})$/,Sh=/^#([0-9a-f]{6})$/,Ah=/^rgb\\(\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*\\)$/,Eh=/^rgb\\(\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*\\)$/,Ch=/^rgba\\(\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,zh=/^rgba\\(\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,Ph=/^hsl\\(\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*\\)$/,qh=/^hsla\\(\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)%\\s*,\\s*([-+]?\\d+(?:\\.\\d+)?)\\s*\\)$/,Lh={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Mh(Yt,Bt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+\"\"}}),Mh(Wt,Vt,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new Wt(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new Wt(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return t=isNaN(t)?1:Math.max(0,Math.min(1,t)),(1===t?\"rgb(\":\"rgba(\")+Math.max(0,Math.min(255,Math.round(this.r)||0))+\", \"+Math.max(0,Math.min(255,Math.round(this.g)||0))+\", \"+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?\")\":\", \"+t+\")\")}})),Mh(Jt,Gt,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new Jt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new Jt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Wt(Qt(t>=240?t-240:t+120,i,r),Qt(t,i,r),Qt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Rh=Math.PI/180,Uh=180/Math.PI,Dh=18,Oh=.95047,Fh=1,Ih=1.08883,Yh=4/29,Bh=6/29,jh=3*Bh*Bh,Hh=Bh*Bh*Bh;Mh(nn,tn,It(Yt,{brighter:function(t){return new nn(this.l+Dh*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new nn(this.l-Dh*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Fh*rn(t),n=Oh*rn(n),e=Ih*rn(e),new Wt(on(3.2404542*n-1.5371385*t-.4985314*e),on(-.969266*n+1.8760108*t+.041556*e),on(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),Mh(sn,cn,It(Yt,{brighter:function(t){return new sn(this.h,this.c,this.l+Dh*(null==t?1:t),this.opacity)},darker:function(t){return new sn(this.h,this.c,this.l-Dh*(null==t?1:t),this.opacity)},rgb:function(){return Kt(this).rgb()}}));var Xh=-.14861,Vh=1.78277,Wh=-.29227,$h=-.90649,Zh=1.97294,Gh=Zh*$h,Jh=Zh*Vh,Qh=Vh*Wh-$h*Xh;Mh(hn,ln,It(Yt,{brighter:function(t){return t=null==t?Nh:Math.pow(Nh,t),new hn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Th:Math.pow(Th,t),new hn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Rh,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Wt(255*(n+e*(Xh*r+Vh*i)),255*(n+e*(Wh*r+$h*i)),255*(n+e*(Zh*r)),this.opacity)}}));var Kh,tp,np,ep,rp=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return pn((e-r/n)*n,u,i,o,a)}},ip=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return pn((e-r/n)*n,i,o,u,a)}},op=function(t){return function(){return t}},up=function t(n){function e(t,n){var e=r((t=Vt(t)).r,(n=Vt(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=r(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+\"\"}}var r=yn(n);return e.gamma=t,e}(1),ap=mn(rp),cp=mn(ip),sp=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=_p(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},fp=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},lp=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},hp=function(t,n){var e,r={},i={};null!==t&&\"object\"==typeof t||(t={}),null!==n&&\"object\"==typeof n||(n={});for(e in n)e in t?r[e]=_p(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},pp=/[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,dp=new RegExp(pp.source,\"g\"),vp=function(t,n){var e,r,i,o=pp.lastIndex=dp.lastIndex=0,u=-1,a=[],c=[];for(t+=\"\",n+=\"\";(e=pp.exec(t))&&(r=dp.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:lp(e,r)})),o=dp.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?bn(c[0].x):xn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join(\"\")})},_p=function(t,n){var e,r=typeof n;return null==n||\"boolean\"===r?op(n):(\"number\"===r?lp:\"string\"===r?(e=Bt(n))?(n=e,up):vp:n instanceof Bt?up:n instanceof Date?fp:Array.isArray(n)?sp:isNaN(n)?hp:lp)(t,n)},yp=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},gp=180/Math.PI,mp={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},xp=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*gp,skewX:Math.atan(c)*gp,scaleX:u,scaleY:a}},bp=Tn(wn,\"px, \",\"px)\",\"deg)\"),wp=Tn(Mn,\", \",\")\",\")\"),Mp=Math.SQRT2,Tp=2,Np=4,kp=1e-12,Sp=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<kp)r=Math.log(s/u)/Mp,e=function(t){return[i+t*f,o+t*l,u*Math.exp(Mp*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+Np*h)/(2*u*Tp*p),v=(s*s-u*u-Np*h)/(2*s*Tp*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/Mp,e=function(t){var n=t*r,e=Nn(_),a=u/(Tp*p)*(e*Sn(Mp*n+_)-kn(_));return[i+a*f,o+a*l,u*e/Nn(Mp*n+_)]}}return e.duration=1e3*r,e},Ap=An(_n),Ep=An(gn),Cp=Cn(_n),zp=Cn(gn),Pp=zn(_n),qp=zn(gn),Lp=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));\nreturn e},Rp={value:function(){}};qn.prototype=Pn.prototype={constructor:qn,on:function(t,n){var e,r=this._,i=Ln(t+\"\",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&\"function\"!=typeof n)throw new Error(\"invalid callback: \"+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=Un(r[e],t.name,n);else if(null==n)for(e in r)r[e]=Un(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=Rn(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new qn(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(r=this._[t],o=0,e=r.length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Up,Dp,Op=function(t){function n(t,n){var r,i,o=e(t,function(t,e){return r?r(t,e-1):(i=t,void(r=n?On(t,n):Dn(t)))});return o.columns=i,o}function e(t,n){function e(){if(f>=s)return u;if(i)return i=!1,o;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,n=t.charCodeAt(r+1),13===n?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/\"\"/g,'\"')}for(;f<s;){var a=1;if(n=t.charCodeAt(f++),10===n)i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++a);else if(n!==c)continue;return t.slice(e,f-a)}return t.slice(e)}for(var r,i,o={},u={},a=[],s=t.length,f=0,l=0;(r=e())!==u;){for(var h=[];r!==o&&r!==u;)h.push(r),r=e();n&&null==(h=n(h,l++))||a.push(h)}return a}function r(n,e){return null==e&&(e=Fn(n)),[e.map(u).join(t)].concat(n.map(function(n){return e.map(function(t){return u(n[t])}).join(t)})).join(\"\\n\")}function i(t){return t.map(o).join(\"\\n\")}function o(n){return n.map(u).join(t)}function u(t){return null==t?\"\":a.test(t+=\"\")?'\"'+t.replace(/\\\"/g,'\"\"')+'\"':t}var a=new RegExp('[\"'+t+\"\\n]\"),c=t.charCodeAt(0);return{parse:n,parseRows:e,format:r,formatRows:i}},Fp=Op(\",\"),Ip=Fp.parse,Yp=Fp.parseRows,Bp=Fp.format,jp=Fp.formatRows,Hp=Op(\"\\t\"),Xp=Hp.parse,Vp=Hp.parseRows,Wp=Hp.format,$p=Hp.formatRows,Zp=function(t,n){function e(t){var n,e=f.status;if(!e&&Yn(f)||e>=200&&e<300||304===e){if(u)try{n=u.call(r,f)}catch(t){return void c.call(\"error\",r,t)}else n=f;c.call(\"load\",r,n)}else c.call(\"error\",r,t)}var r,i,u,a,c=Pn(\"beforesend\",\"progress\",\"load\",\"error\"),s=o(),f=new XMLHttpRequest,l=null,h=null,p=0;if(\"undefined\"==typeof XDomainRequest||\"withCredentials\"in f||!/^(http(s)?:)?\\/\\//.test(t)||(f=new XDomainRequest),\"onload\"in f?f.onload=f.onerror=f.ontimeout=e:f.onreadystatechange=function(t){f.readyState>3&&e(t)},f.onprogress=function(t){c.call(\"progress\",r,t)},r={header:function(t,n){return t=(t+\"\").toLowerCase(),arguments.length<2?s.get(t):(null==n?s.remove(t):s.set(t,n+\"\"),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+\"\",r):i},responseType:function(t){return arguments.length?(a=t,r):a},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?l:(l=null==t?null:t+\"\",r)},password:function(t){return arguments.length<1?h:(h=null==t?null:t+\"\",r)},response:function(t){return u=t,r},get:function(t,n){return r.send(\"GET\",t,n)},post:function(t,n){return r.send(\"POST\",t,n)},send:function(n,e,o){return f.open(n,t,!0,l,h),null==i||s.has(\"accept\")||s.set(\"accept\",i+\",*/*\"),f.setRequestHeader&&s.each(function(t,n){f.setRequestHeader(n,t)}),null!=i&&f.overrideMimeType&&f.overrideMimeType(i),null!=a&&(f.responseType=a),p>0&&(f.timeout=p),null==o&&\"function\"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=In(o)),null!=o&&r.on(\"error\",o).on(\"load\",function(t){o(null,t)}),c.call(\"beforesend\",r,f),f.send(null==e?null:e),r},abort:function(){return f.abort(),r},on:function(){var t=c.on.apply(c,arguments);return t===c?r:t}},null!=n){if(\"function\"!=typeof n)throw new Error(\"invalid callback: \"+n);return r.get(n)}return r},Gp=function(t,n){return function(e,r){var i=Zp(e).mimeType(t).response(n);if(null!=r){if(\"function\"!=typeof r)throw new Error(\"invalid callback: \"+r);return i.get(r)}return i}},Jp=Gp(\"text/html\",function(t){return document.createRange().createContextualFragment(t.responseText)}),Qp=Gp(\"application/json\",function(t){return JSON.parse(t.responseText)}),Kp=Gp(\"text/plain\",function(t){return t.responseText}),td=Gp(\"application/xml\",function(t){var n=t.responseXML;if(!n)throw new Error(\"parse error\");return n}),nd=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=Zp(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Bn(n,r=t)):r},o.row(r),i?o.get(i):o}},ed=nd(\"text/csv\",Ip),rd=nd(\"text/tab-separated-values\",Xp),id=0,od=0,ud=0,ad=1e3,cd=0,sd=0,fd=0,ld=\"object\"==typeof performance&&performance.now?performance:Date,hd=\"function\"==typeof requestAnimationFrame?requestAnimationFrame:function(t){setTimeout(t,17)};Xn.prototype=Vn.prototype={constructor:Xn,restart:function(t,n,e){if(\"function\"!=typeof t)throw new TypeError(\"callback is not a function\");e=(null==e?jn():+e)+(null==n?0:+n),this._next||Dp===this||(Dp?Dp._next=this:Up=this,Dp=this),this._call=t,this._time=e,Jn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Jn())}};var pd=function(t,n,e){var r=new Xn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},dd=function(t,n,e){var r=new Xn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?jn():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},vd=new Date,_d=new Date,yd=Qn(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});yd.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Qn(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):yd:null};var gd=yd.range,md=1e3,xd=6e4,bd=36e5,wd=864e5,Md=6048e5,Td=Qn(function(t){t.setTime(Math.floor(t/md)*md)},function(t,n){t.setTime(+t+n*md)},function(t,n){return(n-t)/md},function(t){return t.getUTCSeconds()}),Nd=Td.range,kd=Qn(function(t){t.setTime(Math.floor(t/xd)*xd)},function(t,n){t.setTime(+t+n*xd)},function(t,n){return(n-t)/xd},function(t){return t.getMinutes()}),Sd=kd.range,Ad=Qn(function(t){var n=t.getTimezoneOffset()*xd%bd;n<0&&(n+=bd),t.setTime(Math.floor((+t-n)/bd)*bd+n)},function(t,n){t.setTime(+t+n*bd)},function(t,n){return(n-t)/bd},function(t){return t.getHours()}),Ed=Ad.range,Cd=Qn(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*xd)/wd},function(t){return t.getDate()-1}),zd=Cd.range,Pd=Kn(0),qd=Kn(1),Ld=Kn(2),Rd=Kn(3),Ud=Kn(4),Dd=Kn(5),Od=Kn(6),Fd=Pd.range,Id=qd.range,Yd=Ld.range,Bd=Rd.range,jd=Ud.range,Hd=Dd.range,Xd=Od.range,Vd=Qn(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Wd=Vd.range,$d=Qn(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});$d.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Qn(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var Zd=$d.range,Gd=Qn(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*xd)},function(t,n){return(n-t)/xd},function(t){return t.getUTCMinutes()}),Jd=Gd.range,Qd=Qn(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+n*bd)},function(t,n){return(n-t)/bd},function(t){return t.getUTCHours()}),Kd=Qd.range,tv=Qn(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/wd},function(t){return t.getUTCDate()-1}),nv=tv.range,ev=te(0),rv=te(1),iv=te(2),ov=te(3),uv=te(4),av=te(5),cv=te(6),sv=ev.range,fv=rv.range,lv=iv.range,hv=ov.range,pv=uv.range,dv=av.range,vv=cv.range,_v=Qn(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),yv=_v.range,gv=Qn(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});gv.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Qn(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var mv,xv=gv.range,bv=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf(\"e\"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},wv=function(t){return t=bv(Math.abs(t)),t?t[1]:NaN},Mv=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},Tv=function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,i=1,o=-1;i<r;++i)switch(t[i]){case\".\":o=e=i;break;case\"0\":0===o&&(o=i),e=i;break;case\"e\":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},Nv=function(t,n){var e=bv(t,n);if(!e)return t+\"\";var r=e[0],i=e[1],o=i-(mv=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join(\"0\"):o>0?r.slice(0,o)+\".\"+r.slice(o):\"0.\"+new Array(1-o).join(\"0\")+bv(t,Math.max(0,n+o-1))[0]},kv=function(t,n){var e=bv(t,n);if(!e)return t+\"\";var r=e[0],i=e[1];return i<0?\"0.\"+new Array(-i).join(\"0\")+r:r.length>i+1?r.slice(0,i+1)+\".\"+r.slice(i+1):r+new Array(i-r.length+2).join(\"0\")},Sv={\"\":Tv,\"%\":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+\"\"},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return kv(100*t,n)},r:kv,s:Nv,X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Av=/^(?:(.)?([<>=^]))?([+\\-\\( ])?([$#])?(0)?(\\d+)?(,)?(\\.\\d+)?([a-z%])?$/i,Ev=function(t){return new ne(t)};ne.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?\"0\":\"\")+(null==this.width?\"\":Math.max(1,0|this.width))+(this.comma?\",\":\"\")+(null==this.precision?\"\":\".\"+Math.max(0,0|this.precision))+this.type};var Cv,zv=[\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"µ\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"],Pv=function(t){function n(t){function n(t){var n,i,c,g=d,m=v;if(\"c\"===p)m=_(t)+m,t=\"\";else{t=+t;var x=(t<0||1/t<0)&&(t*=-1,!0);if(t=_(t,h),x)for(n=-1,i=t.length,x=!1;++n<i;)if(c=t.charCodeAt(n),48<c&&c<58||\"x\"===p&&96<c&&c<103||\"X\"===p&&64<c&&c<71){x=!0;break}if(g=(x?\"(\"===a?a:\"-\":\"-\"===a||\"(\"===a?\"\":a)+g,m=m+(\"s\"===p?zv[8+mv/3]:\"\")+(x&&\"(\"===a?\")\":\"\"),y)for(n=-1,i=t.length;++n<i;)if(c=t.charCodeAt(n),48>c||c>57){m=(46===c?o+t.slice(n+1):t.slice(n))+m,t=t.slice(0,n);break}}l&&!s&&(t=r(t,1/0));var b=g.length+t.length+m.length,w=b<f?new Array(f-b+1).join(e):\"\";switch(l&&s&&(t=r(w+t,w.length?f-m.length:1/0),w=\"\"),u){case\"<\":return g+t+m+w;case\"=\":return g+w+t+m;case\"^\":return w.slice(0,b=w.length>>1)+g+t+m+w.slice(b)}return w+g+t+m}t=Ev(t);var e=t.fill,u=t.align,a=t.sign,c=t.symbol,s=t.zero,f=t.width,l=t.comma,h=t.precision,p=t.type,d=\"$\"===c?i[0]:\"#\"===c&&/[boxX]/.test(p)?\"0\"+p.toLowerCase():\"\",v=\"$\"===c?i[1]:/[%p]/.test(p)?\"%\":\"\",_=Sv[p],y=!p||/[defgprs%]/.test(p);return h=null==h?p?6:12:/[gprs]/.test(p)?Math.max(1,Math.min(21,h)):Math.max(0,Math.min(20,h)),n.toString=function(){return t+\"\"},n}function e(t,e){var r=n((t=Ev(t),t.type=\"f\",t)),i=3*Math.max(-8,Math.min(8,Math.floor(wv(e)/3))),o=Math.pow(10,-i),u=zv[8+i/3];return function(t){return r(o*t)+u}}var r=t.grouping&&t.thousands?Mv(t.grouping,t.thousands):ee,i=t.currency,o=t.decimal;return{format:n,formatPrefix:e}};re({decimal:\".\",thousands:\",\",grouping:[3],currency:[\"$\",\"\"]});var qv,Lv=function(t){return Math.max(0,-wv(Math.abs(t)))},Rv=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(wv(n)/3)))-wv(Math.abs(t)))},Uv=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,wv(n)-wv(t))+1},Dv={\"-\":\"\",_:\" \",0:\"0\"},Ov=/^\\s*\\d+/,Fv=/^%/,Iv=/[\\\\\\^\\$\\*\\+\\?\\|\\[\\]\\(\\)\\.\\{\\}]/g;nr({dateTime:\"%x, %X\",date:\"%-m/%-d/%Y\",time:\"%-I:%M:%S %p\",periods:[\"AM\",\"PM\"],days:[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],shortDays:[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"],months:[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],shortMonths:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"]});var Yv=\"%Y-%m-%dT%H:%M:%S.%LZ\",Bv=Date.prototype.toISOString?er:t.utcFormat(Yv),jv=+new Date(\"2000-01-01T00:00:00.000Z\")?rr:t.utcParse(Yv),Hv=Array.prototype,Xv=Hv.map,Vv=Hv.slice,Wv={name:\"implicit\"},$v=function(t){return function(){return t}},Zv=function(t){return+t},Gv=[0,1],Jv=function(n,r,i){var o,u=n[0],a=n[n.length-1],c=e(u,a,null==r?10:r);switch(i=Ev(null==i?\",f\":i),i.type){case\"s\":var s=Math.max(Math.abs(u),Math.abs(a));return null!=i.precision||isNaN(o=Rv(c,s))||(i.precision=o),t.formatPrefix(i,s);case\"\":case\"e\":case\"g\":case\"p\":case\"r\":null!=i.precision||isNaN(o=Uv(c,Math.max(Math.abs(u),Math.abs(a))))||(i.precision=o-(\"e\"===i.type));break;case\"f\":case\"%\":null!=i.precision||isNaN(o=Lv(c))||(i.precision=o-2*(\"%\"===i.type))}return t.format(i)},Qv=function(t,n){t=t.slice();var e,r=0,i=t.length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},Kv=1e3,t_=60*Kv,n_=60*t_,e_=24*n_,r_=7*e_,i_=30*e_,o_=365*e_,u_=function(){return qr($d,Vd,Pd,Cd,Ad,kd,Td,yd,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},a_=function(){return qr(gv,_v,ev,tv,Qd,Gd,Td,yd,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},c_=function(t){return t.match(/.{6}/g).map(function(t){return\"#\"+t})},s_=c_(\"1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf\"),f_=c_(\"393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6\"),l_=c_(\"3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9\"),h_=c_(\"1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5\"),p_=qp(ln(300,.5,0),ln(-240,.5,1)),d_=qp(ln(-100,.75,.35),ln(80,1.5,.8)),v_=qp(ln(260,.75,.35),ln(80,1.5,.8)),__=ln(),y_=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return __.h=360*t-100,__.s=1.5-1.5*n,__.l=.8-.9*n,__+\"\"},g_=Lr(c_(\"44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725\")),m_=Lr(c_(\"00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf\")),x_=Lr(c_(\"00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4\")),b_=Lr(c_(\"0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921\")),w_=\"http://www.w3.org/1999/xhtml\",M_={svg:\"http://www.w3.org/2000/svg\",xhtml:w_,xlink:\"http://www.w3.org/1999/xlink\",xml:\"http://www.w3.org/XML/1998/namespace\",xmlns:\"http://www.w3.org/2000/xmlns/\"},T_=function(t){var n=t+=\"\",e=n.indexOf(\":\");return e>=0&&\"xmlns\"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),M_.hasOwnProperty(n)?{space:M_[n],local:t}:t},N_=function(t){var n=T_(t);return(n.local?Dr:Ur)(n)},k_=0;Fr.prototype=Or.prototype={constructor:Fr,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var S_=function(t){return function(){return this.matches(t)}};if(\"undefined\"!=typeof document){var A_=document.documentElement;if(!A_.matches){var E_=A_.webkitMatchesSelector||A_.msMatchesSelector||A_.mozMatchesSelector||A_.oMatchesSelector;S_=function(t){return function(){return E_.call(this,t)}}}}var C_=S_,z_={};if(t.event=null,\"undefined\"!=typeof document){var P_=document.documentElement;\"onmouseenter\"in P_||(z_={mouseenter:\"mouseover\",mouseleave:\"mouseout\"})}var q_=function(t,n,e){var r,i,o=Br(t+\"\"),u=o.length;{if(!(arguments.length<2)){for(a=n?Hr:jr,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},L_=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},R_=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},U_=function(t){var n=L_();return n.changedTouches&&(n=n.changedTouches[0]),R_(t,n)},D_=function(t){return null==t?Vr:function(){return this.querySelector(t)}},O_=function(t){\"function\"!=typeof t&&(t=D_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&(\"__data__\"in o&&(u.__data__=o.__data__),s[f]=u);return new zi(r,this._parents)},F_=function(t){return null==t?Wr:function(){return this.querySelectorAll(t)}},I_=function(t){\"function\"!=typeof t&&(t=F_(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new zi(r,i)},Y_=function(t){\"function\"!=typeof t&&(t=C_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new zi(r,this._parents)},B_=function(t){return new Array(t.length)},j_=function(){return new zi(this._enter||this._groups.map(B_),this._parents)};$r.prototype={constructor:$r,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var H_=function(t){return function(){return t}},X_=\"$\",V_=function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?Gr:Zr,r=this._parents,i=this._groups;\"function\"!=typeof t&&(t=H_(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d),y=c[s]=new Array(h);e(f,l,v,_,y,p,n);for(var g,m,x=0,b=0;x<d;++x)if(g=v[x]){for(x>=b&&(b=x+1);!(m=_[b])&&++b<d;);g._next=m||null}}return u=new zi(u,r),u._enter=a,u._exit=c,u},W_=function(){return new zi(this._exit||this._groups.map(B_),this._parents)},$_=function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new zi(u,this._parents)},Z_=function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},G_=function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=Jr);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var u,a=e[o],c=a.length,s=i[o]=new Array(c),f=0;f<c;++f)(u=a[f])&&(s[f]=u);s.sort(n)}return new zi(i,this._parents).order()},J_=function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},Q_=function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},K_=function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},ty=function(){var t=0;return this.each(function(){++t}),t},ny=function(){return!this.node()},ey=function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},ry=function(t,n){var e=T_(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?Kr:Qr:\"function\"==typeof n?e.local?ri:ei:e.local?ni:ti)(e,n))},iy=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView},oy=function(t,n,e){var r;return arguments.length>1?this.each((null==n?ii:\"function\"==typeof n?ui:oi)(t,n,null==e?\"\":e)):iy(r=this.node()).getComputedStyle(r,null).getPropertyValue(t)},uy=function(t,n){return arguments.length>1?this.each((null==n?ai:\"function\"==typeof n?si:ci)(t,n)):this.node()[t]};hi.prototype={add:function(t){var n=this._names.indexOf(t);n<0&&(this._names.push(t),this._node.setAttribute(\"class\",this._names.join(\" \")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute(\"class\",this._names.join(\" \")))},contains:function(t){return this._names.indexOf(t)>=0}};var ay=function(t,n){var e=fi(t+\"\");if(arguments.length<2){for(var r=li(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each((\"function\"==typeof n?yi:n?vi:_i)(e,n))},cy=function(t){return arguments.length?this.each(null==t?gi:(\"function\"==typeof t?xi:mi)(t)):this.node().textContent},sy=function(t){return arguments.length?this.each(null==t?bi:(\"function\"==typeof t?Mi:wi)(t)):this.node().innerHTML},fy=function(){return this.each(Ti)},ly=function(){return this.each(Ni)},hy=function(t){var n=\"function\"==typeof t?t:N_(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},py=function(t,n){var e=\"function\"==typeof t?t:N_(t),r=null==n?ki:\"function\"==typeof n?n:D_(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},dy=function(){return this.each(Si)},vy=function(t){return arguments.length?this.property(\"__data__\",t):this.node().__data__},_y=function(t,n){return this.each((\"function\"==typeof n?Ci:Ei)(t,n))},yy=[null];zi.prototype=Pi.prototype={constructor:zi,select:O_,selectAll:I_,filter:Y_,data:V_,enter:j_,exit:W_,merge:$_,order:Z_,sort:G_,call:J_,nodes:Q_,node:K_,size:ty,empty:ny,each:ey,attr:ry,style:oy,property:uy,classed:ay,text:cy,html:sy,raise:fy,lower:ly,append:hy,insert:py,remove:dy,datum:vy,on:q_,dispatch:_y};var gy=function(t){return\"string\"==typeof t?new zi([[document.querySelector(t)]],[document.documentElement]):new zi([[t]],yy)},my=function(t){return\"string\"==typeof t?new zi([document.querySelectorAll(t)],[document.documentElement]):new zi([null==t?[]:t],yy)},xy=function(t,n,e){arguments.length<3&&(e=n,n=L_().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return R_(t,r);return null},by=function(t,n){null==n&&(n=L_().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=R_(t,n[e]);return i},wy=Pn(\"start\",\"end\",\"interrupt\"),My=[],Ty=0,Ny=1,ky=2,Sy=3,Ay=4,Ey=5,Cy=6,zy=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Ui(t,e,{name:n,index:r,group:i,on:wy,tween:My,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:Ty})},Py=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+\"\";for(i in o)(e=o[i]).name===n?(r=e.state>ky&&e.state<Ey,e.state=Cy,e.timer.stop(),r&&e.on.call(\"interrupt\",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},qy=function(t){return this.each(function(){Py(this,t)})},Ly=function(t,n){var e=this._id;if(t+=\"\",arguments.length<2){for(var r,i=Ri(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Di:Oi)(e,t,n))},Ry=function(t,n){var e;return(\"number\"==typeof n?lp:n instanceof Bt?up:(e=Bt(n))?(n=e,up):vp)(t,n)},Uy=function(t,n){var e=T_(t),r=\"transform\"===e?wp:Ry;return this.attrTween(t,\"function\"==typeof n?(e.local?Xi:Hi)(e,r,Fi(this,\"attr.\"+t,n)):null==n?(e.local?Yi:Ii)(e):(e.local?ji:Bi)(e,r,n))},Dy=function(t,n){var e=\"attr.\"+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if(\"function\"!=typeof n)throw new Error;var r=T_(t);return this.tween(e,(r.local?Vi:Wi)(r,n))},Oy=function(t){var n=this._id;return arguments.length?this.each((\"function\"==typeof t?$i:Zi)(n,t)):Ri(this.node(),n).delay},Fy=function(t){var n=this._id;return arguments.length?this.each((\"function\"==typeof t?Gi:Ji)(n,t)):Ri(this.node(),n).duration},Iy=function(t){var n=this._id;return arguments.length?this.each(Qi(n,t)):Ri(this.node(),n).ease},Yy=function(t){\"function\"!=typeof t&&(t=C_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new so(r,this._parents,this._name,this._id)},By=function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new so(u,this._parents,this._name,this._id)},jy=function(t,n){var e=this._id;return arguments.length<2?Ri(this.node(),e).on.on(t):this.each(to(e,t,n))},Hy=function(){return this.on(\"end.remove\",no(this._id))},Xy=function(t){var n=this._name,e=this._id;\"function\"!=typeof t&&(t=D_(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&(\"__data__\"in a&&(c.__data__=a.__data__),l[h]=c,zy(l[h],n,e,h,l,Ri(a,e)));return new so(o,this._parents,n,e)},Vy=function(t){var n=this._name,e=this._id;\"function\"!=typeof t&&(t=F_(t));\nfor(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=Ri(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&zy(h,n,e,v,p,d);o.push(p),u.push(c)}return new so(o,u,n,e)},Wy=Pi.prototype.constructor,$y=function(){return new Wy(this._groups,this._parents)},Zy=function(t,n,e){var r=\"transform\"==(t+=\"\")?bp:Ry;return null==n?this.styleTween(t,eo(t,r)).on(\"end.style.\"+t,ro(t)):this.styleTween(t,\"function\"==typeof n?oo(t,r,Fi(this,\"style.\"+t,n)):io(t,r,n),e)},Gy=function(t,n,e){var r=\"style.\"+(t+=\"\");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if(\"function\"!=typeof n)throw new Error;return this.tween(r,uo(t,n,null==e?\"\":e))},Jy=function(t){return this.tween(\"text\",\"function\"==typeof t?co(Fi(this,\"text\",t)):ao(null==t?\"\":t+\"\"))},Qy=function(){for(var t=this._name,n=this._id,e=lo(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=Ri(u,n);zy(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new so(r,this._parents,t,e)},Ky=0,tg=Pi.prototype;so.prototype=fo.prototype={constructor:so,select:Xy,selectAll:Vy,filter:Yy,merge:By,selection:$y,transition:Qy,call:tg.call,nodes:tg.nodes,node:tg.node,size:tg.size,empty:tg.empty,each:tg.each,on:jy,attr:Uy,attrTween:Dy,style:Zy,styleTween:Gy,text:Jy,remove:Hy,tween:Ly,delay:Oy,duration:Fy,ease:Iy};var ng={time:null,delay:0,duration:250,ease:g},eg=function(t){var n,e;t instanceof so?(n=t._id,t=t._name):(n=lo(),(e=ng).time=jn(),t=null==t?null:t+\"\");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&zy(u,t,n,s,a,e||ho(u,n));return new so(r,this._parents,t,n)};Pi.prototype.interrupt=qy,Pi.prototype.transition=eg;var rg=[null],ig=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+\"\";for(r in i)if((e=i[r]).state>Ny&&e.name===n)return new so([[t]],rg,n,+r)}return null},og=Array.prototype.slice,ug=function(t){return t},ag=1,cg=2,sg=3,fg=4,lg=1e-6,hg=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=To(e),t.y=ko(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Ao(t),c=Eo(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Mo,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},pg=function(t){var n,e,r,i,o=this,u=[o];do for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r]);while(u.length);return this},dg=function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},vg=function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},_g=function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},yg=function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},gg=function(t){for(var n=this,e=Co(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},mg=function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},xg=function(){var t=[];return this.each(function(n){t.push(n)}),t},bg=function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},wg=function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n};Uo.prototype=zo.prototype={constructor:Uo,each:pg,eachAfter:vg,eachBefore:dg,sum:_g,sort:yg,path:gg,ancestors:mg,descendants:xg,leaves:bg,links:wg,copy:Po};var Mg=function(t){for(var n,e=(t=t.slice()).length,r=null,i=r;e;){var o=new Do(t[e-1]);i=i?i.next=o:r=o,t[n]=t[--e]}return{head:r,tail:i}},Tg=function(t){return Fo(Mg(t),[])},Ng=function(t){return Wo(t),t},kg=function(t){return function(){return t}},Sg=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(Qo(n)).eachAfter(Ko(i,.5)).eachBefore(tu(1)):t.eachBefore(Qo(Jo)).eachAfter(Ko(Go,1)).eachAfter(Ko(i,t.r/Math.min(e,r))).eachBefore(tu(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=Go;return t.radius=function(e){return arguments.length?(n=$o(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=\"function\"==typeof n?n:kg(+n),t):i},t},Ag=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Eg=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)o=u[a],o.y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Cg=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore(Ag),t}function n(t,n){return function(e){e.children&&Eg(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},zg=\"$\",Pg={depth:-1},qg={},Lg=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new Uo(r),null!=(c=n(r,i,t))&&(c+=\"\")&&(s=zg+(a.id=c),h[s]=s in h?qg:a);for(i=0;i<f;++i)if(a=l[i],c=e(t[i],i,t),null!=c&&(c+=\"\")){if(u=h[zg+c],!u)throw new Error(\"missing: \"+c);if(u===qg)throw new Error(\"ambiguous: \"+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error(\"multiple roots\");o=a}if(!o)throw new Error(\"no root\");if(o.parent=Pg,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(Ro),o.parent=null,f>0)throw new Error(\"cycle\");return o}var n=nu,e=eu;return t.id=function(e){return arguments.length?(n=Zo(e),t):n},t.parentId=function(n){return arguments.length?(e=Zo(n),t):e},t};su.prototype=Object.create(Uo.prototype);var Rg=function(){function t(t){var r=fu(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){au(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=ou(a),i=iu(i),a&&i;)c=iu(c),u=ou(u),u.a=t,r=a.z+l-i.z-s+o(a._,i._),r>0&&(uu(cu(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!ou(u)&&(u.t=a,u.m+=l-f),i&&!iu(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=ru,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},Ug=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)o=u[a],o.x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Dg=(1+Math.sqrt(5))/2,Og=function t(n){function e(t,e,r,i,o){lu(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Dg),Fg=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore(Ag),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Og,r=!1,i=1,o=1,u=[0],a=Go,c=Go,s=Go,f=Go,l=Go;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Zo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a=\"function\"==typeof n?n:kg(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c=\"function\"==typeof n?n:kg(+n),t):c},t.paddingRight=function(n){return arguments.length?(s=\"function\"==typeof n?n:kg(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f=\"function\"==typeof n?n:kg(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l=\"function\"==typeof n?n:kg(+n),t):l},t},Ig=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,s.y1=a,void 0}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}var _=f[p]-l,y=e-_;if(a-i>u-r){var g=(i*y+a*_)/e;o(t,p,_,r,i,u,g),o(p,n,y,r,g,u,a)}else{var m=(r*y+u*_)/e;o(t,p,_,r,i,m,a),o(p,n,y,m,i,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},Yg=function(t,n,e,r,i){(1&t.depth?Ug:Eg)(t,n,e,r,i)},Bg=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(a=u[l],c=a.children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Eg(a,e,r,i,r+=(o-r)*a.value/p):Ug(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=lu(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Dg),jg=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)i=r[e],u+=i.x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)i=r[e],i.x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},Hg=function(t){return function(){return t}},Xg=function(){return 1e-6*(Math.random()-.5)},Vg=function(t){function n(){function t(t,e,r,i,o){var a=t.data,p=t.r,d=l+p;{if(!a)return e>s+d||i<s-d||r>f+d||o<f-d;if(a.index>n){var v=s-a.x-a.vx,_=f-a.y-a.vy,y=v*v+_*_;y<d*d&&(0===v&&(v=Xg(),y+=v*v),0===_&&(_=Xg(),y+=_*_),y=(d-(y=Math.sqrt(y)))/y*u,c.vx+=(v*=y)*(d=(p*=p)/(h+p)),c.vy+=(_*=y)*d,a.vx-=v*(d=1-d),a.vy-=_*d)}}}for(var n,r,c,s,f,l,h,p=i.length,d=0;d<a;++d)for(r=I(i,hu,pu).visitAfter(e),n=0;n<p;++n)c=i[n],l=o[n],h=l*l,s=c.x+c.vx,f=c.y+c.vy,r.visit(t)}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e=i.length;for(o=new Array(e),n=0;n<e;++n)o[n]=+t(i[n],n,i)}}var i,o,u=1,a=1;return\"function\"!=typeof t&&(t=Hg(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t=\"function\"==typeof e?e:Hg(+e),r(),n):t},n},Wg=function(t){function n(t){return 1/Math.min(f[t.source.index],f[t.target.index])}function e(n){for(var e=0,r=t.length;e<v;++e)for(var i,o,u,s,f,h,p,d=0;d<r;++d)i=t[d],o=i.source,u=i.target,s=u.x+u.vx-o.x-o.vx||Xg(),f=u.y+u.vy-o.y-o.vy||Xg(),h=Math.sqrt(s*s+f*f),h=(h-c[d])/h*n*a[d],s*=h,f*=h,u.vx-=s*(p=l[d]),u.vy-=f*p,o.vx+=s*(p=1-p),o.vy+=f*p}function r(){if(s){var n,e,r=s.length,p=t.length,d=o(s,h);for(n=0,f=new Array(r);n<r;++n)f[n]=0;for(n=0;n<p;++n)e=t[n],e.index=n,\"object\"!=typeof e.source&&(e.source=vu(d,e.source)),\"object\"!=typeof e.target&&(e.target=vu(d,e.target)),++f[e.source.index],++f[e.target.index];for(n=0,l=new Array(p);n<p;++n)e=t[n],l[n]=f[e.source.index]/(f[e.source.index]+f[e.target.index]);a=new Array(p),i(),c=new Array(p),u()}}function i(){if(s)for(var n=0,e=t.length;n<e;++n)a[n]=+p(t[n],n,t)}function u(){if(s)for(var n=0,e=t.length;n<e;++n)c[n]=+d(t[n],n,t)}var a,c,s,f,l,h=du,p=n,d=Hg(30),v=1;return null==t&&(t=[]),e.initialize=function(t){s=t,r()},e.links=function(n){return arguments.length?(t=n,r(),e):t},e.id=function(t){return arguments.length?(h=t,e):h},e.iterations=function(t){return arguments.length?(v=+t,e):v},e.strength=function(t){return arguments.length?(p=\"function\"==typeof t?t:Hg(+t),i(),e):p},e.distance=function(t){return arguments.length?(d=\"function\"==typeof t?t:Hg(+t),u(),e):d},e},$g=10,Zg=Math.PI*(3-Math.sqrt(5)),Gg=function(t){function n(){e(),d.call(\"tick\",u),a<c&&(p.stop(),d.call(\"end\",u))}function e(){var n,e,r=t.length;for(a+=(f-a)*s,h.each(function(t){t(a)}),n=0;n<r;++n)e=t[n],null==e.fx?e.x+=e.vx*=l:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=l:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=$g*Math.sqrt(e),o=e*Zg;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var u,a=1,c=.001,s=1-Math.pow(c,1/300),f=0,l=.6,h=o(),p=Vn(n),d=Pn(\"tick\",\"end\");return null==t&&(t=[]),r(),u={tick:e,restart:function(){return p.restart(n),u},stop:function(){return p.stop(),u},nodes:function(n){return arguments.length?(t=n,r(),h.each(i),u):t},alpha:function(t){return arguments.length?(a=+t,u):a},alphaMin:function(t){return arguments.length?(c=+t,u):c},alphaDecay:function(t){return arguments.length?(s=+t,u):+s},alphaTarget:function(t){return arguments.length?(f=+t,u):f},velocityDecay:function(t){return arguments.length?(l=1-t,u):1-l},force:function(t,n){return arguments.length>1?(null==n?h.remove(t):h.set(t,i(n)),u):h.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)a=t[s],i=n-a.x,o=e-a.y,u=i*i+o*o,u<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),u):d.on(t)}}},Jg=function(){function t(t){var n,a=i.length,c=I(i,_u,yu).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n=i.length;for(a=new Array(n),t=0;t<n;++t)a[t]=+c(i[t],t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{n=t,n.x=n.data.x,n.y=n.data.y;do u+=a[n.data.index];while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=Xg(),p+=i*i),0===c&&(c=Xg(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=Xg(),p+=i*i),0===c&&(c=Xg(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h);while(t=t.next)}}var i,o,u,a,c=Hg(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c=\"function\"==typeof e?e:Hg(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},Qg=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Hg(.1);return\"function\"!=typeof t&&(t=Hg(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u=\"function\"==typeof t?t:Hg(+t),e(),n):u},n.x=function(r){return arguments.length?(t=\"function\"==typeof r?r:Hg(+r),e(),n):t},n},Kg=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)n=r[e],n.vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=Hg(.1);return\"function\"!=typeof t&&(t=Hg(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u=\"function\"==typeof t?t:Hg(+t),e(),n):u},n.y=function(r){return arguments.length?(t=\"function\"==typeof r?r:Hg(+r),e(),n):t},n},tm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},nm=function(t){var n=t.document.documentElement,e=gy(t).on(\"dragstart.drag\",tm,!0);\"onselectstart\"in n?e.on(\"selectstart.drag\",tm,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect=\"none\")},em=function(t){return function(){return t}};xu.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var rm=function(){function n(t){t.on(\"mousedown.drag\",e).on(\"touchstart.drag\",o).on(\"touchmove.drag\",u).on(\"touchend.drag touchcancel.drag\",a).style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\")}function e(){if(!f&&l.apply(this,arguments)){var n=c(\"mouse\",h.apply(this,arguments),U_,this,arguments);n&&(gy(t.event.view).on(\"mousemove.drag\",r,!0).on(\"mouseup.drag\",i,!0),nm(t.event.view),gu(),s=!1,n(\"start\"))}}function r(){tm(),s=!0,d.mouse(\"drag\")}function i(){gy(t.event.view).on(\"mousemove.drag mouseup.drag\",null),mu(t.event.view,s),tm(),d.mouse(\"end\")}function o(){if(l.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=h.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,xy,this,arguments))&&(gu(),e(\"start\"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=d[r[n].identifier])&&(tm(),e(\"drag\"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(f&&clearTimeout(f),f=setTimeout(function(){f=null},500),n=0;n<i;++n)(e=d[r[n].identifier])&&(gu(),e(\"end\"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=v.copy();if(Xr(new xu(n,\"beforestart\",a,e,_,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=p.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,v=f;switch(h){case\"start\":d[e]=t,p=_++;break;case\"end\":delete d[e],--_;case\"drag\":f=i(r,e),p=_}Xr(new xu(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-v[0],f[1]-v[1],l),l.apply,l,[h,o,u])}}var s,f,l=bu,h=wu,p=Mu,d={},v=Pn(\"start\",\"drag\",\"end\"),_=0;return n.filter=function(t){return arguments.length?(l=\"function\"==typeof t?t:em(!!t),n):l},n.container=function(t){return arguments.length?(h=\"function\"==typeof t?t:em(t),n):h},n.subject=function(t){return arguments.length?(p=\"function\"==typeof t?t:em(t),n):p},n.on=function(){var t=v.on.apply(v,arguments);return t===v?n:t},n},im=function(t){return function(){return t}};ku.prototype={constructor:ku,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Cu(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Au(this,e),t=e,e=t.U),e.C=!1,r.C=!0,Eu(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Eu(this,e),t=e,e=t.U),e.C=!1,r.C=!0,Au(this,r))),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Cu(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r){if(t&&t.C)return void(t.C=!1);do{if(t===this._)break;if(t===i.L){if(n=i.R,n.C&&(n.C=!1,i.C=!0,Au(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Eu(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Au(this,i),t=this._;break}}else if(n=i.L,n.C&&(n.C=!1,i.C=!0,Eu(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Au(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Eu(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var om,um,am,cm,sm,fm=[],lm=[],hm=1e-6,pm=1e-12;na.prototype={constructor:na,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Fu(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){for(var i,o=e.site,u=e.halfedges,a=-1,c=u.length,s=n[u[c-1]],f=s.left===o?s.right:s.left;++a<c;)i=f,s=n[u[a]],f=s.left===o?s.right:s.left,i&&f&&r<i.index&&r<f.index&&Ku(o,i,f)<0&&t.push([o.data,i.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){var r,i=this,o=i._found||0,u=i.cells[o]||i.cells[o=0],a=t-u.site[0],c=n-u.site[1],s=a*a+c*c;do u=i.cells[r=o],o=null,u.halfedges.forEach(function(e){var r=i.edges[e],a=r.left;if(a!==u.site&&a||(a=r.right)){var c=t-a[0],f=n-a[1],l=c*c+f*f;l<s&&(s=l,o=a.index)}});while(null!==o);return i._found=r,null==e||s<=e*e?u.site:null}};var dm=function(){function t(t){return new na(t.map(function(r,i){var o=[Math.round(n(r,i,t)/hm)*hm,Math.round(e(r,i,t)/hm)*hm];return o.index=i,o.data=r,o}),r)}var n=Tu,e=Nu,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n=\"function\"==typeof e?e:im(+e),t):n},t.y=function(n){return arguments.length?(e=\"function\"==typeof n?n:im(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},vm=function(t){return function(){return t}};ra.prototype={constructor:ra,scale:function(t){return 1===t?this:new ra(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ra(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return\"translate(\"+this.x+\",\"+this.y+\") scale(\"+this.k+\")\"}};var _m=new ra(1,0,0);ia.prototype=ra.prototype;var ym=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},gm=function(){function n(t){t.on(\"wheel.zoom\",s).on(\"mousedown.zoom\",f).on(\"dblclick.zoom\",l).on(\"touchstart.zoom\",h).on(\"touchmove.zoom\",p).on(\"touchend.zoom touchcancel.zoom\",d).style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\").property(\"__zoom\",ca)}function e(t,n){return n=Math.max(m,Math.min(x,n)),n===t.k?t:new ra(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ra(t.k,r,i)}function i(t,n){var e=Math.min(0,t.invertX(n[0][0])-b)||Math.max(0,t.invertX(n[1][0])-w),r=Math.min(0,t.invertY(n[0][1])-M)||Math.max(0,t.invertY(n[1][1])-T);return e||r?t.translate(e,r):t}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on(\"start.zoom\",function(){a(this,arguments).start()}).on(\"interrupt.zoom end.zoom\",function(){a(this,arguments).end()}).tween(\"zoom\",function(){var t=this,r=arguments,i=a(t,r),u=g.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l=\"function\"==typeof n?n.apply(t,r):n,h=Sp(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ra(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=k.length;r<i;++r)if((e=k[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=g.apply(t,n)}function s(){function n(){o.wheel=null,o.end()}if(y.apply(this,arguments)){var o=a(this,arguments),u=this.__zoom,c=Math.max(m,Math.min(x,u.k*Math.pow(2,-t.event.deltaY*(t.event.deltaMode?120:1)/500))),s=U_(this);if(o.wheel)o.mouse[0][0]===s[0]&&o.mouse[0][1]===s[1]||(o.mouse[1]=u.invert(o.mouse[0]=s)),clearTimeout(o.wheel);else{if(u.k===c)return;o.mouse=[s,u.invert(s)],Py(this),o.start()}ym(),o.wheel=setTimeout(n,E),o.zoom(\"mouse\",i(r(e(u,c),o.mouse[0],o.mouse[1]),o.extent))}}function f(){function n(){ym(),o.moved=!0,o.zoom(\"mouse\",i(r(o.that.__zoom,o.mouse[0]=U_(o.that),o.mouse[1]),o.extent))}function e(){u.on(\"mousemove.zoom mouseup.zoom\",null),mu(t.event.view,o.moved),ym(),o.end()}if(!_&&y.apply(this,arguments)){var o=a(this,arguments),u=gy(t.event.view).on(\"mousemove.zoom\",n,!0).on(\"mouseup.zoom\",e,!0),c=U_(this);nm(t.event.view),oa(),o.mouse=[c,this.__zoom.invert(c)],Py(this),o.start()}}function l(){if(y.apply(this,arguments)){var o=this.__zoom,a=U_(this),c=o.invert(a),s=o.k*(t.event.shiftKey?.5:2),f=i(r(e(o,s),a,c),g.apply(this,arguments));ym(),N>0?gy(this).transition().duration(N).call(u,f,a):gy(this).call(n.transform,f)}}function h(){if(y.apply(this,arguments)){var n,e,r,i=a(this,arguments),o=t.event.changedTouches,u=o.length;for(oa(),n=0;n<u;++n)e=o[n],r=xy(this,o,e.identifier),r=[r,this.__zoom.invert(r),e.identifier],i.touch0?i.touch1||(i.touch1=r):i.touch0=r;return v&&(v=clearTimeout(v),!i.touch1)?(i.end(),l.apply(this,arguments)):void(t.event.touches.length===u&&(v=setTimeout(function(){v=null},A),Py(this),i.start()))}}function p(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(ym(),v&&(v=clearTimeout(v)),n=0;n<l;++n)o=f[n],u=xy(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],_=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=_[0]-p[0])*g+(g=_[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+_[0])/2,(p[1]+_[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom(\"touch\",i(r(o,u,c),s.extent))}function d(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(oa(),_&&clearTimeout(_),_=setTimeout(function(){_=null},A),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0||r.end()}var v,_,y=ua,g=aa,m=0,x=1/0,b=-x,w=x,M=b,T=w,N=250,k=[],S=Pn(\"start\",\"zoom\",\"end\"),A=500,E=150;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property(\"__zoom\",ca),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,\"function\"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){var t=this.__zoom.k,n=\"function\"==typeof e?e.apply(this,arguments):e;return t*n})},n.scaleTo=function(t,u){n.transform(t,function(){var t=g.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a),s=\"function\"==typeof u?u.apply(this,arguments):u;return i(r(e(n,s),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate(\"function\"==typeof e?e.apply(this,arguments):e,\"function\"==typeof r?r.apply(this,arguments):r),g.apply(this,arguments))})},c.prototype={start:function(){return 1===++this.active&&(this.index=k.push(this)-1,this.emit(\"start\")),this},zoom:function(t,n){return this.mouse&&\"mouse\"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&\"touch\"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&\"touch\"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit(\"zoom\"),this},end:function(){return 0===--this.active&&(k.splice(this.index,1),this.index=-1,this.emit(\"end\")),this},emit:function(t){Xr(new ea(n,t,this.that.__zoom),S.apply,S,[t,this.that,this.args])}},n.filter=function(t){return arguments.length?(y=\"function\"==typeof t?t:vm(!!t),n):y},n.extent=function(t){return arguments.length?(g=\"function\"==typeof t?t:vm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):g},n.scaleExtent=function(t){return arguments.length?(m=+t[0],x=+t[1],n):[m,x]},n.translateExtent=function(t){return arguments.length?(b=+t[0][0],w=+t[1][0],M=+t[0][1],T=+t[1][1],n):[[b,M],[w,T]]},n.duration=function(t){return arguments.length?(N=+t,n):N},n.on=function(){var t=S.on.apply(S,arguments);return t===S?n:t},n},mm=function(t){return function(){return t}},xm=function(t,n,e){this.target=t,this.type=n,this.selection=e},bm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},wm={name:\"drag\"},Mm={name:\"space\"},Tm={name:\"handle\"},Nm={name:\"center\"},km={name:\"x\",handles:[\"e\",\"w\"].map(fa),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Sm={name:\"y\",handles:[\"n\",\"s\"].map(fa),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Am={name:\"xy\",handles:[\"n\",\"e\",\"s\",\"w\",\"nw\",\"ne\",\"se\",\"sw\"].map(fa),input:function(t){return t},output:function(t){return t}},Em={overlay:\"crosshair\",selection:\"move\",n:\"ns-resize\",e:\"ew-resize\",s:\"ns-resize\",w:\"ew-resize\",nw:\"nwse-resize\",ne:\"nesw-resize\",se:\"nwse-resize\",sw:\"nesw-resize\"},Cm={e:\"w\",w:\"e\",nw:\"ne\",ne:\"nw\",se:\"sw\",sw:\"se\"},zm={n:\"s\",s:\"n\",nw:\"sw\",ne:\"se\",se:\"ne\",sw:\"nw\"},Pm={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},qm={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Lm=function(){return ga(Am)},Rm=Math.cos,Um=Math.sin,Dm=Math.PI,Om=Dm/2,Fm=2*Dm,Im=Math.max,Ym=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Os(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Os(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),o=Im(0,Fm-n*l)/o,c=o?n:Fm/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Im(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=ma(n))._=n,t):i&&i._},t},Bm=Array.prototype.slice,jm=function(t){return function(){return t}},Hm=function(){function t(){var t,a=Bm.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Om,h=o.apply(this,a)-Om,p=f*Rm(l),d=f*Um(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Om,y=o.apply(this,a)-Om;if(u||(u=t=L()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rm(_),v*Um(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+\"\"||null}var n=xa,e=ba,r=wa,i=Ma,o=Ta,u=null;return t.radius=function(n){return arguments.length?(r=\"function\"==typeof n?n:jm(+n),t):r},t.startAngle=function(n){return arguments.length?(i=\"function\"==typeof n?n:jm(+n),t):i},t.endAngle=function(n){return arguments.length?(o=\"function\"==typeof n?n:jm(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},Xm=function(){return new Na};Na.prototype={constructor:Na,reset:function(){this.s=this.t=0},add:function(t){ka(Mx,t,this.t),ka(this,Mx.s,this.s),this.s?this.t+=Mx.t:this.s=Mx.t},valueOf:function(){return this.s}};var Vm,Wm,$m,Zm,Gm,Jm,Qm,Km,tx,nx,ex,rx,ix,ox,ux,ax,cx,sx,fx,lx,hx,px,dx,vx,_x,yx,gx,mx,xx,bx,wx,Mx=new Na,Tx=1e-6,Nx=1e-12,kx=Math.PI,Sx=kx/2,Ax=kx/4,Ex=2*kx,Cx=180/kx,zx=kx/180,Px=Math.abs,qx=Math.atan,Lx=Math.atan2,Rx=Math.cos,Ux=Math.ceil,Dx=Math.exp,Ox=Math.log,Fx=Math.pow,Ix=Math.sin,Yx=Math.sign||function(t){return t>0?1:t<0?-1:0;\n},Bx=Math.sqrt,jx=Math.tan,Hx={Feature:function(t,n){za(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)za(e[r].geometry,n)}},Xx={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){Pa(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Pa(e[r],n,0)},Polygon:function(t,n){qa(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)qa(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)za(e[r],n)}},Vx=function(t,n){t&&Hx.hasOwnProperty(t.type)?Hx[t.type](t,n):za(t,n)},Wx=Xm(),$x=Xm(),Zx={point:Ca,lineStart:Ca,lineEnd:Ca,polygonStart:function(){Wx.reset(),Zx.lineStart=La,Zx.lineEnd=Ra},polygonEnd:function(){var t=+Wx;$x.add(t<0?Ex+t:t),this.lineStart=this.lineEnd=this.point=Ca},sphere:function(){$x.add(Ex)}},Gx=function(t){return $x.reset(),Vx(t,Zx),2*$x},Jx=Xm(),Qx={point:Xa,lineStart:Wa,lineEnd:$a,polygonStart:function(){Qx.point=Za,Qx.lineStart=Ga,Qx.lineEnd=Ja,Jx.reset(),Zx.polygonStart()},polygonEnd:function(){Zx.polygonEnd(),Qx.point=Xa,Qx.lineStart=Wa,Qx.lineEnd=$a,Wx<0?(Jm=-(Km=180),Qm=-(tx=90)):Jx>Tx?tx=90:Jx<-Tx&&(Qm=-90),ux[0]=Jm,ux[1]=Km}},Kx=function(t){var n,e,r,i,o,u,a;if(tx=Km=-(Jm=Qm=1/0),ox=[],Vx(t,Qx),e=ox.length){for(ox.sort(Ka),n=1,r=ox[0],o=[r];n<e;++n)i=ox[n],tc(r,i[0])||tc(r,i[1])?(Qa(r[0],i[1])>Qa(r[0],r[1])&&(r[1]=i[1]),Qa(i[0],r[1])>Qa(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-(1/0),e=o.length-1,n=0,r=o[e];n<=e;r=i,++n)i=o[n],(a=Qa(r[1],i[0]))>u&&(u=a,Jm=i[0],Km=r[1])}return ox=ux=null,Jm===1/0||Qm===1/0?[[NaN,NaN],[NaN,NaN]]:[[Jm,Qm],[Km,tx]]},tb={sphere:Ca,point:nc,lineStart:rc,lineEnd:uc,polygonStart:function(){tb.lineStart=ac,tb.lineEnd=cc},polygonEnd:function(){tb.lineStart=rc,tb.lineEnd=uc}},nb=function(t){ax=cx=sx=fx=lx=hx=px=dx=vx=_x=yx=0,Vx(t,tb);var n=vx,e=_x,r=yx,i=n*n+e*e+r*r;return i<Nx&&(n=hx,e=px,r=dx,cx<Tx&&(n=sx,e=fx,r=lx),i=n*n+e*e+r*r,i<Nx)?[NaN,NaN]:[Lx(e,n)*Cx,Aa(r/Bx(i))*Cx]},eb=function(t){return function(){return t}},rb=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return e=n.invert(e,r),e&&t.invert(e[0],e[1])}),e};lc.invert=lc;var ib,ob,ub,ab,cb,sb,fb,lb,hb,pb,db,vb=function(t){function n(n){return n=t(n[0]*zx,n[1]*zx),n[0]*=Cx,n[1]*=Cx,n}return t=hc(t[0]*zx,t[1]*zx,t.length>2?t[2]*zx:0),n.invert=function(n){return n=t.invert(n[0]*zx,n[1]*zx),n[0]*=Cx,n[1]*=Cx,n},n},_b=function(){function t(t,n){e.push(t=r(t,n)),t[0]*=Cx,t[1]*=Cx}function n(){var t=i.apply(this,arguments),n=o.apply(this,arguments)*zx,c=u.apply(this,arguments)*zx;return e=[],r=hc(-t[0]*zx,-t[1]*zx,0).invert,_c(a,n,c,1),t={type:\"Polygon\",coordinates:[e]},e=r=null,t}var e,r,i=eb([0,0]),o=eb(90),u=eb(6),a={point:t};return n.center=function(t){return arguments.length?(i=\"function\"==typeof t?t:eb([+t[0],+t[1]]),n):i},n.radius=function(t){return arguments.length?(o=\"function\"==typeof t?t:eb(+t),n):o},n.precision=function(t){return arguments.length?(u=\"function\"==typeof t?t:eb(+t),n):u},n},yb=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Ca,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},gb=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=n[0],f=n[1],l=0,h=1,p=s-a,d=f-c;if(u=e-a,p||!(u>0)){if(u/=p,p<0){if(u<l)return;u<h&&(h=u)}else if(p>0){if(u>h)return;u>l&&(l=u)}if(u=i-a,p||!(u<0)){if(u/=p,p<0){if(u>h)return;u>l&&(l=u)}else if(p>0){if(u<l)return;u<h&&(h=u)}if(u=r-c,d||!(u>0)){if(u/=d,d<0){if(u<l)return;u<h&&(h=u)}else if(d>0){if(u>h)return;u>l&&(l=u)}if(u=o-c,d||!(u<0)){if(u/=d,d<0){if(u>h)return;u>l&&(l=u)}else if(d>0){if(u<l)return;u<h&&(h=u)}return l>0&&(t[0]=a+l*p,t[1]=c+l*d),h<1&&(n[0]=a+h*p,n[1]=c+h*d),!0}}}}},mb=function(t,n){return Px(t[0]-n[0])<Tx&&Px(t[1]-n[1])<Tx},xb=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if(mb(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a.push(e=new gc(r,t,null,!0)),c.push(e.o=new gc(r,null,e,!1)),a.push(e=new gc(u,t,null,!1)),c.push(e.o=new gc(u,null,e,!0))}}),a.length){for(c.sort(n),mc(a),mc(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}h=h.o,s=h.z,p=!p}while(!h.v);i.lineEnd()}}},bb=1e9,wb=-bb,Mb=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=xc(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},Tb=Xm(),Nb={sphere:Ca,point:Ca,lineStart:bc,lineEnd:Ca,polygonStart:Ca,polygonEnd:Ca},kb=function(t){return Tb.reset(),Vx(t,Nb),+Tb},Sb=[null,null],Ab={type:\"LineString\",coordinates:Sb},Eb=function(t,n){return Sb[0]=t,Sb[1]=n,kb(Ab)},Cb=function(t,n){var e=t[0]*zx,r=t[1]*zx,i=n[0]*zx,o=n[1]*zx,u=Rx(r),a=Ix(r),c=Rx(o),s=Ix(o),f=u*Rx(e),l=u*Ix(e),h=c*Rx(i),p=c*Ix(i),d=2*Aa(Bx(Ea(o-r)+u*c*Ea(i-e))),v=Ix(d),_=d?function(t){var n=Ix(t*=d)/v,e=Ix(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[Lx(i,r)*Cx,Lx(o,Bx(r*r+i*i))*Cx]}:function(){return[e*Cx,r*Cx]};return _.distance=d,_},zb=function(t){return t},Pb=Xm(),qb=Xm(),Lb={point:Ca,lineStart:Ca,lineEnd:Ca,polygonStart:function(){Lb.lineStart=Ec,Lb.lineEnd=Pc},polygonEnd:function(){Lb.lineStart=Lb.lineEnd=Lb.point=Ca,Pb.add(Px(qb)),qb.reset()},result:function(){var t=Pb/2;return Pb.reset(),t}},Rb=1/0,Ub=Rb,Db=-Rb,Ob=Db,Fb={point:qc,lineStart:Ca,lineEnd:Ca,polygonStart:Ca,polygonEnd:Ca,result:function(){var t=[[Rb,Ub],[Db,Ob]];return Db=Ob=-(Ub=Rb=1/0),t}},Ib=0,Yb=0,Bb=0,jb=0,Hb=0,Xb=0,Vb=0,Wb=0,$b=0,Zb={point:Lc,lineStart:Rc,lineEnd:Oc,polygonStart:function(){Zb.lineStart=Fc,Zb.lineEnd=Ic},polygonEnd:function(){Zb.point=Lc,Zb.lineStart=Rc,Zb.lineEnd=Oc},result:function(){var t=$b?[Vb/$b,Wb/$b]:Xb?[jb/Xb,Hb/Xb]:Bb?[Ib/Bb,Yb/Bb]:[NaN,NaN];return Ib=Yb=Bb=jb=Hb=Xb=Vb=Wb=$b=0,t}};jc.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Ex)}},result:Ca},Hc.prototype={_circle:Xc(4.5),pointRadius:function(t){return this._circle=Xc(t),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push(\"Z\"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push(\"M\",t,\",\",n),this._point=1;break;case 1:this._string.push(\"L\",t,\",\",n);break;default:this._string.push(\"M\",t,\",\",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join(\"\");return this._string=[],t}}};var Gb=function(t,n){function e(t){return t&&(\"function\"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Vx(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Vx(t,r(Lb)),Lb.result()},e.bounds=function(t){return Vx(t,r(Fb)),Fb.result()},e.centroid=function(t){return Vx(t,r(Zb)),Zb.result()},e.projection=function(n){return arguments.length?(r=null==(t=n)?zb:n.stream,e):t},e.context=function(t){return arguments.length?(i=null==(n=t)?new Hc:new jc(t),\"function\"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o=\"function\"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},Jb=Xm(),Qb=function(t,n){var e=n[0],r=n[1],i=[Ix(e),-Rx(e),0],o=0,u=0;Jb.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+Ax,d=Ix(p),v=Rx(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+Ax,x=Ix(m),b=Rx(m),w=g-h,M=w>=0?1:-1,T=M*w,N=T>kx,k=d*x;if(Jb.add(Lx(k*M*Ix(T),v*b+k*Rx(T))),o+=N?w+M*Ex:w,N^h>=e^g>=e){var S=Ya(Fa(l),Fa(y));Ha(S);var A=Ya(i,S);Ha(A);var E=(N^w>=0?-1:1)*Aa(A[2]);(r>E||r===E&&(S[0]||S[1]))&&(u+=N^w>=0?1:-1)}}return(o<-Tx||o<Tx&&Jb<-Tx)^1&u},Kb=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(Vc))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=yb(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Js(d);var t=Qb(p,y);d.length?(x||(o.polygonStart(),x=!0),xb(d,Wc,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},tw=Kb(function(){return!0},$c,Gc,[-kx,-Sx]),nw=function(t,n){function e(e,r,i,o){_c(o,t,n,i,e,r)}function r(t,n){return Rx(t)*Rx(n)>a}function i(t){var n,e,i,a,f;return{lineStart:function(){a=i=!1,f=1},point:function(l,h){var p,d=[l,h],v=r(l,h),_=c?v?0:u(l,h):v?u(l+(l<0?kx:-kx),h):0;if(!n&&(a=i=v)&&t.lineStart(),v!==i&&(p=o(n,d),(mb(n,p)||mb(d,p))&&(d[0]+=Tx,d[1]+=Tx,v=r(d[0],d[1]))),v!==i)f=0,v?(t.lineStart(),p=o(d,n),t.point(p[0],p[1])):(p=o(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(s&&n&&c^v){var y;_&e||!(y=o(d,n,!0))||(f=0,c?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&mb(n,d)||t.point(d[0],d[1]),n=d,i=v,e=_},lineEnd:function(){i&&t.lineEnd(),n=null},clean:function(){return f|(a&&i)<<1}}}function o(t,n,e){var r=Fa(t),i=Fa(n),o=[1,0,0],u=Ya(r,i),c=Ia(u,u),s=u[0],f=c-s*s;if(!f)return!e&&t;var l=a*c/f,h=-a*s/f,p=Ya(o,u),d=ja(o,l),v=ja(u,h);Ba(d,v);var _=p,y=Ia(d,_),g=Ia(_,_),m=y*y-g*(Ia(d,d)-1);if(!(m<0)){var x=Bx(m),b=ja(_,(-y-x)/g);if(Ba(b,d),b=Oa(b),!e)return b;var w,M=t[0],T=n[0],N=t[1],k=n[1];T<M&&(w=M,M=T,T=w);var S=T-M,A=Px(S-kx)<Tx,E=A||S<Tx;if(!A&&k<N&&(w=N,N=k,k=w),E?A?N+k>0^b[1]<(Px(b[0]-M)<Tx?N:k):N<=b[1]&&b[1]<=k:S>kx^(M<=b[0]&&b[0]<=T)){var C=ja(_,(-y+x)/g);return Ba(C,d),[b,Oa(C)]}}}function u(n,e){var r=c?t:kx-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var a=Rx(t),c=a>0,s=Px(a)>Tx;return Kb(r,i,e,c?[0,-t]:[-kx,t-kx])},ew=function(t){return{stream:Jc(t)}};Qc.prototype={constructor:Qc,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var rw=16,iw=Rx(30*zx),ow=function(t,n){return+n?es(t,n):ns(t)},uw=Jc({point:function(t,n){this.stream.point(t*zx,n*zx)}}),aw=function(){return os(as).scale(155.424).center([0,33.6442])},cw=function(){return aw().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},sw=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=cw(),s=aw().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=aw().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=cs([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+Tx,a+.12*e+Tx],[r-.214*e-Tx,a+.234*e-Tx]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+Tx,a+.166*e+Tx],[r-.115*e-Tx,a+.234*e-Tx]]).stream(l),n()},t.fitExtent=function(n,e){return Kc(t,n,e)},t.fitSize=function(n,e){return ts(t,n,e)},t.scale(1070)},fw=ss(function(t){return Bx(2/(1+t))});fw.invert=fs(function(t){return 2*Aa(t/2)});var lw=function(){return rs(fw).scale(124.75).clipAngle(179.999)},hw=ss(function(t){return(t=Sa(t))&&t/Ix(t)});hw.invert=fs(function(t){return t});var pw=function(){return rs(hw).scale(79.4188).clipAngle(179.999)};ls.invert=function(t,n){return[t,2*qx(Dx(n))-Sx]};var dw=function(){return hs(ls).scale(961/Ex)},vw=function(){return os(ds).scale(109.5).parallels([30,30])};vs.invert=vs;var _w=function(){return rs(vs).scale(152.63)},yw=function(){return os(_s).scale(131.154).center([0,13.9389])};ys.invert=fs(qx);var gw=function(){return rs(ys).scale(144.049).clipAngle(60)},mw=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=zb,l=null,h=zb;return u={stream:function(t){return i&&o===t?i:i=f(h(o=t))},clipExtent:function(i){return arguments.length?(h=null==i?(l=n=e=r=null,zb):xc(l=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==l?null:[[l,n],[e,r]]},scale:function(n){return arguments.length?(f=gs(a=+n,c,s),t()):a},translate:function(n){return arguments.length?(f=gs(a,c=+n[0],s=+n[1]),t()):[c,s]},fitExtent:function(t,n){return Kc(u,t,n)},fitSize:function(t,n){return ts(u,t,n)}}};ms.invert=fs(Aa);var xw=function(){return rs(ms).scale(249.5).clipAngle(90+Tx)};xs.invert=fs(function(t){return 2*qx(t)});var bw=function(){return rs(xs).scale(250).clipAngle(142)};bs.invert=function(t,n){return[-n,2*qx(Dx(t))-Sx]};var ww=function(){var t=hs(bs),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)};t.version=ws,t.bisect=ks,t.bisectRight=ks,t.bisectLeft=Ss,t.ascending=Ms,t.bisector=Ts,t.descending=As,t.deviation=zs,t.extent=Ps,t.histogram=Hs,t.thresholdFreedmanDiaconis=Vs,t.thresholdScott=Ws,t.thresholdSturges=js,t.max=$s,t.mean=Zs,t.median=Gs,t.merge=Js,t.min=Qs,t.pairs=Ks,t.permute=tf,t.quantile=Xs,t.range=Os,t.scan=nf,t.shuffle=ef,t.sum=rf,t.ticks=Bs,t.tickStep=e,t.transpose=of,t.variance=Cs,t.zip=uf,t.entries=hf,t.keys=ff,t.values=lf,t.map=o,t.set=l,t.nest=cf,t.randomUniform=pf,t.randomNormal=df,t.randomLogNormal=vf,t.randomBates=yf,t.randomIrwinHall=_f,t.randomExponential=gf,t.easeLinear=h,t.easeQuad=v,t.easeQuadIn=p,t.easeQuadOut=d,t.easeQuadInOut=v,t.easeCubic=g,t.easeCubicIn=_,t.easeCubicOut=y,t.easeCubicInOut=g,t.easePoly=wf,t.easePolyIn=xf,t.easePolyOut=bf,t.easePolyInOut=wf,t.easeSin=b,t.easeSinIn=m,t.easeSinOut=x,t.easeSinInOut=b,t.easeExp=T,t.easeExpIn=w,t.easeExpOut=M,t.easeExpInOut=T,t.easeCircle=S,t.easeCircleIn=N,t.easeCircleOut=k,t.easeCircleInOut=S,t.easeBounce=E,t.easeBounceIn=A,t.easeBounceOut=E,t.easeBounceInOut=C,t.easeBack=Of,t.easeBackIn=Uf,t.easeBackOut=Df,t.easeBackInOut=Of,t.easeElastic=jf,t.easeElasticIn=Bf,t.easeElasticOut=jf,t.easeElasticInOut=Hf,t.polygonArea=Xf,t.polygonCentroid=Vf,t.polygonHull=$f,t.polygonContains=Zf,t.polygonLength=Gf,t.path=L,t.quadtree=I,t.queue=Z,t.arc=wl,t.area=Nl,t.line=Tl,t.pie=Al,t.radialArea=zl,t.radialLine=Cl,t.symbol=Jl,t.symbols=Gl,t.symbolCircle=Pl,t.symbolCross=ql,t.symbolDiamond=Ul,t.symbolSquare=Bl,t.symbolStar=Yl,t.symbolTriangle=Hl,t.symbolWye=Zl,t.curveBasisClosed=th,t.curveBasisOpen=nh,t.curveBasis=Kl,t.curveBundle=eh,t.curveCardinalClosed=ih,t.curveCardinalOpen=oh,t.curveCardinal=rh,t.curveCatmullRomClosed=ah,t.curveCatmullRomOpen=ch,t.curveCatmullRom=uh,t.curveLinearClosed=sh,t.curveLinear=Ml,t.curveMonotoneX=zt,t.curveMonotoneY=Pt,t.curveNatural=fh,t.curveStep=lh,t.curveStepAfter=Dt,t.curveStepBefore=Ut,t.stack=vh,t.stackOffsetExpand=_h,t.stackOffsetNone=ph,t.stackOffsetSilhouette=yh,t.stackOffsetWiggle=gh,t.stackOrderAscending=mh,t.stackOrderDescending=xh,t.stackOrderInsideOut=bh,t.stackOrderNone=dh,t.stackOrderReverse=wh,t.color=Bt,t.rgb=Vt,t.hsl=Gt,t.lab=tn,t.hcl=cn,t.cubehelix=ln,t.interpolate=_p,t.interpolateArray=sp,t.interpolateDate=fp,t.interpolateNumber=lp,t.interpolateObject=hp,t.interpolateRound=yp,t.interpolateString=vp,t.interpolateTransformCss=bp,t.interpolateTransformSvg=wp,t.interpolateZoom=Sp,t.interpolateRgb=up,t.interpolateRgbBasis=ap,t.interpolateRgbBasisClosed=cp,t.interpolateHsl=Ap,t.interpolateHslLong=Ep,t.interpolateLab=En,t.interpolateHcl=Cp,t.interpolateHclLong=zp,t.interpolateCubehelix=Pp,t.interpolateCubehelixLong=qp,t.interpolateBasis=rp,t.interpolateBasisClosed=ip,t.quantize=Lp,t.dispatch=Pn,t.dsvFormat=Op,t.csvParse=Ip,t.csvParseRows=Yp,t.csvFormat=Bp,t.csvFormatRows=jp,t.tsvParse=Xp,t.tsvParseRows=Vp,t.tsvFormat=Wp,t.tsvFormatRows=$p,t.request=Zp,t.html=Jp,t.json=Qp,t.text=Kp,t.xml=td,t.csv=ed,t.tsv=rd,t.now=jn,t.timer=Vn,t.timerFlush=Wn,t.timeout=pd,t.interval=dd,t.timeInterval=Qn,t.timeMillisecond=yd,t.timeMilliseconds=gd,t.timeSecond=Td,t.timeSeconds=Nd,t.timeMinute=kd,t.timeMinutes=Sd,t.timeHour=Ad,t.timeHours=Ed,t.timeDay=Cd,t.timeDays=zd,t.timeWeek=Pd,t.timeWeeks=Fd,t.timeSunday=Pd,t.timeSundays=Fd,t.timeMonday=qd,t.timeMondays=Id,t.timeTuesday=Ld,t.timeTuesdays=Yd;t.timeWednesday=Rd;t.timeWednesdays=Bd,t.timeThursday=Ud,t.timeThursdays=jd,t.timeFriday=Dd,t.timeFridays=Hd,t.timeSaturday=Od,t.timeSaturdays=Xd,t.timeMonth=Vd,t.timeMonths=Wd,t.timeYear=$d,t.timeYears=Zd,t.utcMillisecond=yd,t.utcMilliseconds=gd,t.utcSecond=Td,t.utcSeconds=Nd,t.utcMinute=Gd,t.utcMinutes=Jd,t.utcHour=Qd,t.utcHours=Kd,t.utcDay=tv,t.utcDays=nv,t.utcWeek=ev,t.utcWeeks=sv,t.utcSunday=ev,t.utcSundays=sv,t.utcMonday=rv,t.utcMondays=fv,t.utcTuesday=iv,t.utcTuesdays=lv,t.utcWednesday=ov,t.utcWednesdays=hv,t.utcThursday=uv,t.utcThursdays=pv,t.utcFriday=av,t.utcFridays=dv,t.utcSaturday=cv,t.utcSaturdays=vv,t.utcMonth=_v,t.utcMonths=yv,t.utcYear=gv,t.utcYears=xv,t.formatLocale=Pv,t.formatDefaultLocale=re,t.formatSpecifier=Ev,t.precisionFixed=Lv,t.precisionPrefix=Rv,t.precisionRound=Uv,t.isoFormat=Bv,t.isoParse=jv,t.timeFormatLocale=ae,t.timeFormatDefaultLocale=nr,t.scaleBand=or,t.scalePoint=ar,t.scaleIdentity=yr,t.scaleLinear=_r,t.scaleLog=Tr,t.scaleOrdinal=ir,t.scaleImplicit=Wv,t.scalePow=kr,t.scaleSqrt=Sr,t.scaleQuantile=Ar,t.scaleQuantize=Er,t.scaleThreshold=Cr,t.scaleTime=u_,t.scaleUtc=a_,t.schemeCategory10=s_,t.schemeCategory20b=f_,t.schemeCategory20c=l_,t.schemeCategory20=h_,t.scaleSequential=Rr,t.interpolateCubehelixDefault=p_,t.interpolateRainbow=y_,t.interpolateWarm=d_,t.interpolateCool=v_,t.interpolateViridis=g_,t.interpolateMagma=m_,t.interpolateInferno=x_,t.interpolatePlasma=b_,t.creator=N_,t.customEvent=Xr,t.local=Or,t.matcher=C_,t.mouse=U_,t.namespace=T_,t.namespaces=M_,t.select=gy,t.selectAll=my,t.selection=Pi,t.selector=D_,t.selectorAll=F_,t.touch=xy,t.touches=by,t.window=iy,t.active=ig,t.interrupt=Py,t.transition=fo,t.axisTop=mo,t.axisRight=xo,t.axisBottom=bo,t.axisLeft=wo,t.cluster=hg,t.hierarchy=zo,t.pack=Sg,t.packSiblings=Ng,t.packEnclose=Tg,t.partition=Cg,t.stratify=Lg,t.tree=Rg,t.treemap=Fg,t.treemapBinary=Ig,t.treemapDice=Eg,t.treemapSlice=Ug,t.treemapSliceDice=Yg,t.treemapSquarify=Og,t.treemapResquarify=Bg,t.forceCenter=jg,t.forceCollide=Vg,t.forceLink=Wg,t.forceManyBody=Jg,t.forceSimulation=Gg,t.forceX=Qg,t.forceY=Kg,t.drag=rm,t.dragDisable=nm,t.dragEnable=mu,t.voronoi=dm,t.zoom=gm,t.zoomIdentity=_m,t.zoomTransform=ia,t.brush=Lm,t.brushX=_a,t.brushY=ya,t.brushSelection=va,t.chord=Ym,t.ribbon=Hm,t.geoAlbers=cw,t.geoAlbersUsa=sw,t.geoArea=Gx,t.geoAzimuthalEqualArea=lw,t.geoAzimuthalEqualAreaRaw=fw,t.geoAzimuthalEquidistant=pw,t.geoAzimuthalEquidistantRaw=hw,t.geoBounds=Kx,t.geoCentroid=nb,t.geoCircle=_b,t.geoClipExtent=Mb,t.geoConicConformal=vw,t.geoConicConformalRaw=ds,t.geoConicEqualArea=aw,t.geoConicEqualAreaRaw=as,t.geoConicEquidistant=yw,t.geoConicEquidistantRaw=_s,t.geoDistance=Eb,t.geoEquirectangular=_w,t.geoEquirectangularRaw=vs,t.geoGnomonic=gw,t.geoGnomonicRaw=ys,t.geoGraticule=Sc,t.geoGraticule10=Ac,t.geoIdentity=mw,t.geoInterpolate=Cb,t.geoLength=kb,t.geoMercator=dw,t.geoMercatorRaw=ls,t.geoOrthographic=xw,t.geoOrthographicRaw=ms,t.geoPath=Gb,t.geoProjection=rs,t.geoProjectionMutator=is,t.geoRotation=vb,t.geoStereographic=bw,t.geoStereographicRaw=xs,t.geoStream=Vx,t.geoTransform=ew,t.geoTransverseMercator=ww,t.geoTransverseMercatorRaw=bs,Object.defineProperty(t,\"__esModule\",{value:!0})});"
  },
  {
    "path": "web/vue/public/vendor/humanize-duration.js",
    "content": "// HumanizeDuration.js - http://git.io/j0HgmQ\n\n;(function () {\n  var languages = {\n    en: {\n      y: function (c) { return 'year' + (c !== 1 ? 's' : '') },\n      mo: function (c) { return 'month' + (c !== 1 ? 's' : '') },\n      w: function (c) { return 'week' + (c !== 1 ? 's' : '') },\n      d: function (c) { return 'day' + (c !== 1 ? 's' : '') },\n      h: function (c) { return 'hour' + (c !== 1 ? 's' : '') },\n      m: function (c) { return 'minute' + (c !== 1 ? 's' : '') },\n      s: function (c) { return 'second' + (c !== 1 ? 's' : '') },\n      ms: function (c) { return 'millisecond' + (c !== 1 ? 's' : '') },\n      decimal: '.'\n    }\n  }\n\n  // You can create a humanizer, which returns a function with default\n  // parameters.\n  function humanizer (passedOptions) {\n    var result = function humanizer (ms, humanizerOptions) {\n      var options = extend({}, result, humanizerOptions || {})\n      return doHumanization(ms, options)\n    }\n\n    return extend(result, {\n      language: 'en',\n      delimiter: ', ',\n      spacer: ' ',\n      conjunction: '',\n      serialComma: true,\n      units: ['y', 'mo', 'w', 'd', 'h', 'm', 's'],\n      languages: {},\n      round: false,\n      unitMeasures: {\n        y: 31557600000,\n        mo: 2629800000,\n        w: 604800000,\n        d: 86400000,\n        h: 3600000,\n        m: 60000,\n        s: 1000,\n        ms: 1\n      }\n    }, passedOptions)\n  }\n\n  // The main function is just a wrapper around a default humanizer.\n  var humanizeDuration = humanizer({})\n\n  // doHumanization does the bulk of the work.\n  function doHumanization (ms, options) {\n    var i, len, piece\n\n    // Make sure we have a positive number.\n    // Has the nice sideffect of turning Number objects into primitives.\n    ms = Math.abs(ms)\n\n    var dictionary = options.languages[options.language] || languages[options.language]\n    if (!dictionary) {\n      throw new Error('No language ' + dictionary + '.')\n    }\n\n    var pieces = []\n\n    // Start at the top and keep removing units, bit by bit.\n    var unitName, unitMS, unitCount\n    for (i = 0, len = options.units.length; i < len; i++) {\n      unitName = options.units[i]\n      unitMS = options.unitMeasures[unitName]\n\n      // What's the number of full units we can fit?\n      if (i + 1 === len) {\n        unitCount = ms / unitMS\n      } else {\n        unitCount = Math.floor(ms / unitMS)\n      }\n\n      // Add the string.\n      pieces.push({\n        unitCount: unitCount,\n        unitName: unitName\n      })\n\n      // Remove what we just figured out.\n      ms -= unitCount * unitMS\n    }\n\n    var firstOccupiedUnitIndex = 0\n    for (i = 0; i < pieces.length; i++) {\n      if (pieces[i].unitCount) {\n        firstOccupiedUnitIndex = i\n        break\n      }\n    }\n\n    if (options.round) {\n      var ratioToLargerUnit, previousPiece\n      for (i = pieces.length - 1; i >= 0; i--) {\n        piece = pieces[i]\n        piece.unitCount = Math.round(piece.unitCount)\n\n        if (i === 0) { break }\n\n        previousPiece = pieces[i - 1]\n\n        ratioToLargerUnit = options.unitMeasures[previousPiece.unitName] / options.unitMeasures[piece.unitName]\n        if ((piece.unitCount % ratioToLargerUnit) === 0 || (options.largest && ((options.largest - 1) < (i - firstOccupiedUnitIndex)))) {\n          previousPiece.unitCount += piece.unitCount / ratioToLargerUnit\n          piece.unitCount = 0\n        }\n      }\n    }\n\n    var result = []\n    for (i = 0, pieces.length; i < len; i++) {\n      piece = pieces[i]\n      if (piece.unitCount) {\n        result.push(render(piece.unitCount, piece.unitName, dictionary, options))\n      }\n\n      if (result.length === options.largest) { break }\n    }\n\n    if (result.length) {\n      if (!options.conjunction || result.length === 1) {\n        return result.join(options.delimiter)\n      } else if (result.length === 2) {\n        return result.join(options.conjunction)\n      } else if (result.length > 2) {\n        return result.slice(0, -1).join(options.delimiter) + (options.serialComma ? ',' : '') + options.conjunction + result.slice(-1)\n      }\n    } else {\n      return render(0, options.units[options.units.length - 1], dictionary, options)\n    }\n  }\n\n  function render (count, type, dictionary, options) {\n    var decimal\n    if (options.decimal === void 0) {\n      decimal = dictionary.decimal\n    } else {\n      decimal = options.decimal\n    }\n\n    var countStr = count.toString().replace('.', decimal)\n\n    var dictionaryValue = dictionary[type]\n    var word\n    if (typeof dictionaryValue === 'function') {\n      word = dictionaryValue(count)\n    } else {\n      word = dictionaryValue\n    }\n\n    return countStr + options.spacer + word\n  }\n\n  function extend (destination) {\n    var source\n    for (var i = 1; i < arguments.length; i++) {\n      source = arguments[i]\n      for (var prop in source) {\n        if (source.hasOwnProperty(prop)) {\n          destination[prop] = source[prop]\n        }\n      }\n    }\n    return destination\n  }\n\n  humanizeDuration.getSupportedLanguages = function getSupportedLanguages () {\n    var result = []\n    for (var language in languages) {\n      if (languages.hasOwnProperty(language)) {\n        result.push(language)\n      }\n    }\n    return result\n  }\n\n  humanizeDuration.humanizer = humanizer\n\n  if (typeof define === 'function' && define.amd) {\n    define(function () {\n      return humanizeDuration\n    })\n  } else if (typeof module !== 'undefined' && module.exports) {\n    module.exports = humanizeDuration\n  } else {\n    this.humanizeDuration = humanizeDuration\n  }\n})();  // eslint-disable-line semi"
  },
  {
    "path": "web/vue/public/vendor/moment.js",
    "content": "//! moment.js\n//! version : 2.15.2\n//! authors : Tim Wood, Iskren Chernev, Moment.js contributors\n//! license : MIT\n//! momentjs.com\n!function(a,b){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=b():\"function\"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){\"use strict\";function a(){return md.apply(null,arguments)}\n// This is done to register the method called with moment()\n// without creating circular dependencies.\nfunction b(a){md=a}function c(a){return a instanceof Array||\"[object Array]\"===Object.prototype.toString.call(a)}function d(a){\n// IE8 will treat undefined and null as object if it wasn't for\n// input != null\nreturn null!=a&&\"[object Object]\"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)\n// even if its not own property I'd still call it non-empty\nreturn!1;return!0}function f(a){return a instanceof Date||\"[object Date]\"===Object.prototype.toString.call(a)}function g(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function h(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function i(a,b){for(var c in b)h(b,c)&&(a[c]=b[c]);return h(b,\"toString\")&&(a.toString=b.toString),h(b,\"valueOf\")&&(a.valueOf=b.valueOf),a}function j(a,b,c,d){return qb(a,b,c,d,!0).utc()}function k(){\n// We need to deep clone this object.\nreturn{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function l(a){return null==a._pf&&(a._pf=k()),a._pf}function m(a){if(null==a._isValid){var b=l(a),c=nd.call(b.parsedDateParts,function(a){return null!=a}),d=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c);if(a._strict&&(d=d&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour),null!=Object.isFrozen&&Object.isFrozen(a))return d;a._isValid=d}return a._isValid}function n(a){var b=j(NaN);return null!=a?i(l(b),a):l(b).userInvalidated=!0,b}function o(a){return void 0===a}function p(a,b){var c,d,e;if(o(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),o(b._i)||(a._i=b._i),o(b._f)||(a._f=b._f),o(b._l)||(a._l=b._l),o(b._strict)||(a._strict=b._strict),o(b._tzm)||(a._tzm=b._tzm),o(b._isUTC)||(a._isUTC=b._isUTC),o(b._offset)||(a._offset=b._offset),o(b._pf)||(a._pf=l(b)),o(b._locale)||(a._locale=b._locale),od.length>0)for(c in od)d=od[c],e=b[d],o(e)||(a[d]=e);return a}\n// Moment prototype object\nfunction q(b){p(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),\n// Prevent infinite loop in case updateOffset creates new moment\n// objects.\npd===!1&&(pd=!0,a.updateOffset(this),pd=!1)}function r(a){return a instanceof q||null!=a&&null!=a._isAMomentObject}function s(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function t(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=s(b)),c}\n// compare two arrays, return the number of differences\nfunction u(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d<e;d++)(c&&a[d]!==b[d]||!c&&t(a[d])!==t(b[d]))&&g++;return g+f}function v(b){a.suppressDeprecationWarnings===!1&&\"undefined\"!=typeof console&&console.warn&&console.warn(\"Deprecation warning: \"+b)}function w(b,c){var d=!0;return i(function(){if(null!=a.deprecationHandler&&a.deprecationHandler(null,b),d){for(var e,f=[],g=0;g<arguments.length;g++){if(e=\"\",\"object\"==typeof arguments[g]){e+=\"\\n[\"+g+\"] \";for(var h in arguments[0])e+=h+\": \"+arguments[0][h]+\", \";e=e.slice(0,-2)}else e=arguments[g];f.push(e)}v(b+\"\\nArguments: \"+Array.prototype.slice.call(f).join(\"\")+\"\\n\"+(new Error).stack),d=!1}return c.apply(this,arguments)},c)}function x(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),qd[b]||(v(c),qd[b]=!0)}function y(a){return a instanceof Function||\"[object Function]\"===Object.prototype.toString.call(a)}function z(a){var b,c;for(c in a)b=a[c],y(b)?this[c]=b:this[\"_\"+c]=b;this._config=a,\n// Lenient ordinal parsing accepts just a number in addition to\n// number + (possibly) stuff coming from _ordinalParseLenient.\nthis._ordinalParseLenient=new RegExp(this._ordinalParse.source+\"|\"+/\\d{1,2}/.source)}function A(a,b){var c,e=i({},a);for(c in b)h(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},i(e[c],a[c]),i(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)h(a,c)&&!h(b,c)&&d(a[c])&&(\n// make sure changes to properties don't modify parent config\ne[c]=i({},e[c]));return e}function B(a){null!=a&&this.set(a)}function C(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return y(d)?d.call(b,c):d}function D(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function E(){return this._invalidDate}function F(a){return this._ordinal.replace(\"%d\",a)}function G(a,b,c,d){var e=this._relativeTime[c];return y(e)?e(a,b,c,d):e.replace(/%d/i,a)}function H(a,b){var c=this._relativeTime[a>0?\"future\":\"past\"];return y(c)?c(b):c.replace(/%s/i,b)}function I(a,b){var c=a.toLowerCase();zd[c]=zd[c+\"s\"]=zd[b]=a}function J(a){return\"string\"==typeof a?zd[a]||zd[a.toLowerCase()]:void 0}function K(a){var b,c,d={};for(c in a)h(a,c)&&(b=J(c),b&&(d[b]=a[c]));return d}function L(a,b){Ad[a]=b}function M(a){var b=[];for(var c in a)b.push({unit:c,priority:Ad[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function N(b,c){return function(d){return null!=d?(P(this,b,d),a.updateOffset(this,c),this):O(this,b)}}function O(a,b){return a.isValid()?a._d[\"get\"+(a._isUTC?\"UTC\":\"\")+b]():NaN}function P(a,b,c){a.isValid()&&a._d[\"set\"+(a._isUTC?\"UTC\":\"\")+b](c)}\n// MOMENTS\nfunction Q(a){return a=J(a),y(this[a])?this[a]():this}function R(a,b){if(\"object\"==typeof a){a=K(a);for(var c=M(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=J(a),y(this[a]))return this[a](b);return this}function S(a,b,c){var d=\"\"+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?\"+\":\"\":\"-\")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}\n// token:    'M'\n// padded:   ['MM', 2]\n// ordinal:  'Mo'\n// callback: function () { this.month() + 1 }\nfunction T(a,b,c,d){var e=d;\"string\"==typeof d&&(e=function(){return this[d]()}),a&&(Ed[a]=e),b&&(Ed[b[0]]=function(){return S(e.apply(this,arguments),b[1],b[2])}),c&&(Ed[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function U(a){return a.match(/\\[[\\s\\S]/)?a.replace(/^\\[|\\]$/g,\"\"):a.replace(/\\\\/g,\"\")}function V(a){var b,c,d=a.match(Bd);for(b=0,c=d.length;b<c;b++)Ed[d[b]]?d[b]=Ed[d[b]]:d[b]=U(d[b]);return function(b){var e,f=\"\";for(e=0;e<c;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}\n// format date using native date object\nfunction W(a,b){return a.isValid()?(b=X(b,a.localeData()),Dd[b]=Dd[b]||V(b),Dd[b](a)):a.localeData().invalidDate()}function X(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Cd.lastIndex=0;d>=0&&Cd.test(a);)a=a.replace(Cd,c),Cd.lastIndex=0,d-=1;return a}function Y(a,b,c){Wd[a]=y(b)?b:function(a,d){return a&&c?c:b}}function Z(a,b){return h(Wd,a)?Wd[a](b._strict,b._locale):new RegExp($(a))}\n// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript\nfunction $(a){return _(a.replace(\"\\\\\",\"\").replace(/\\\\(\\[)|\\\\(\\])|\\[([^\\]\\[]*)\\]|\\\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function _(a){return a.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g,\"\\\\$&\")}function aa(a,b){var c,d=b;for(\"string\"==typeof a&&(a=[a]),\"number\"==typeof b&&(d=function(a,c){c[b]=t(a)}),c=0;c<a.length;c++)Xd[a[c]]=d}function ba(a,b){aa(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function ca(a,b,c){null!=b&&h(Xd,a)&&Xd[a](b,c._a,c,a)}function da(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function ea(a,b){return a?c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||fe).test(b)?\"format\":\"standalone\"][a.month()]:this._months}function fa(a,b){return a?c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[fe.test(b)?\"format\":\"standalone\"][a.month()]:this._monthsShort}function ga(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(\n// this is not used\nthis._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;d<12;++d)f=j([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,\"\").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,\"\").toLocaleLowerCase();return c?\"MMM\"===b?(e=sd.call(this._shortMonthsParse,g),e!==-1?e:null):(e=sd.call(this._longMonthsParse,g),e!==-1?e:null):\"MMM\"===b?(e=sd.call(this._shortMonthsParse,g),e!==-1?e:(e=sd.call(this._longMonthsParse,g),e!==-1?e:null)):(e=sd.call(this._longMonthsParse,g),e!==-1?e:(e=sd.call(this._shortMonthsParse,g),e!==-1?e:null))}function ha(a,b,c){var d,e,f;if(this._monthsParseExact)return ga.call(this,a,b,c);\n// TODO: add sorting\n// Sorting makes sure if one month (or abbr) is a prefix of another\n// see sorting in computeMonthsParse\nfor(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;d<12;d++){\n// test the regex\nif(\n// make the regex if we don't have it already\ne=j([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp(\"^\"+this.months(e,\"\").replace(\".\",\"\")+\"$\",\"i\"),this._shortMonthsParse[d]=new RegExp(\"^\"+this.monthsShort(e,\"\").replace(\".\",\"\")+\"$\",\"i\")),c||this._monthsParse[d]||(f=\"^\"+this.months(e,\"\")+\"|^\"+this.monthsShort(e,\"\"),this._monthsParse[d]=new RegExp(f.replace(\".\",\"\"),\"i\")),c&&\"MMMM\"===b&&this._longMonthsParse[d].test(a))return d;if(c&&\"MMM\"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}\n// MOMENTS\nfunction ia(a,b){var c;if(!a.isValid())\n// No op\nreturn a;if(\"string\"==typeof b)if(/^\\d+$/.test(b))b=t(b);else\n// TODO: Another silent failure?\nif(b=a.localeData().monthsParse(b),\"number\"!=typeof b)return a;return c=Math.min(a.date(),da(a.year(),b)),a._d[\"set\"+(a._isUTC?\"UTC\":\"\")+\"Month\"](b,c),a}function ja(b){return null!=b?(ia(this,b),a.updateOffset(this,!0),this):O(this,\"Month\")}function ka(){return da(this.year(),this.month())}function la(a){return this._monthsParseExact?(h(this,\"_monthsRegex\")||na.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(h(this,\"_monthsShortRegex\")||(this._monthsShortRegex=ie),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function ma(a){return this._monthsParseExact?(h(this,\"_monthsRegex\")||na.call(this),a?this._monthsStrictRegex:this._monthsRegex):(h(this,\"_monthsRegex\")||(this._monthsRegex=je),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function na(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;b<12;b++)\n// make the regex if we don't have it already\nc=j([2e3,b]),d.push(this.monthsShort(c,\"\")),e.push(this.months(c,\"\")),f.push(this.months(c,\"\")),f.push(this.monthsShort(c,\"\"));for(\n// Sorting makes sure if one month (or abbr) is a prefix of another it\n// will match the longer piece.\nd.sort(a),e.sort(a),f.sort(a),b=0;b<12;b++)d[b]=_(d[b]),e[b]=_(e[b]);for(b=0;b<24;b++)f[b]=_(f[b]);this._monthsRegex=new RegExp(\"^(\"+f.join(\"|\")+\")\",\"i\"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp(\"^(\"+e.join(\"|\")+\")\",\"i\"),this._monthsShortStrictRegex=new RegExp(\"^(\"+d.join(\"|\")+\")\",\"i\")}\n// HELPERS\nfunction oa(a){return pa(a)?366:365}function pa(a){return a%4===0&&a%100!==0||a%400===0}function qa(){return pa(this.year())}function ra(a,b,c,d,e,f,g){\n//can't just apply() to create a date:\n//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply\nvar h=new Date(a,b,c,d,e,f,g);\n//the date constructor remaps years 0-99 to 1900-1999\nreturn a<100&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function sa(a){var b=new Date(Date.UTC.apply(null,arguments));\n//the Date.UTC function remaps years 0-99 to 1900-1999\nreturn a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}\n// start-of-first-week - start-of-year\nfunction ta(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)\nd=7+b-c,\n// first-week day local weekday -- which local weekday is fwd\ne=(7+sa(a,0,d).getUTCDay()-b)%7;return-e+d-1}\n//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday\nfunction ua(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ta(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=oa(f)+j):j>oa(a)?(f=a+1,g=j-oa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function va(a,b,c){var d,e,f=ta(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+wa(e,b,c)):g>wa(a.year(),b,c)?(d=g-wa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function wa(a,b,c){var d=ta(a,b,c),e=ta(a+1,b,c);return(oa(a)-d+e)/7}\n// HELPERS\n// LOCALES\nfunction xa(a){return va(a,this._week.dow,this._week.doy).week}function ya(){return this._week.dow}function za(){return this._week.doy}\n// MOMENTS\nfunction Aa(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),\"d\")}function Ba(a){var b=va(this,1,4).week;return null==a?b:this.add(7*(a-b),\"d\")}\n// HELPERS\nfunction Ca(a,b){return\"string\"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),\"number\"==typeof a?a:null):parseInt(a,10)}function Da(a,b){return\"string\"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Ea(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?\"format\":\"standalone\"][a.day()]:this._weekdays}function Fa(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ga(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=j([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,\"\").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,\"\").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,\"\").toLocaleLowerCase();return c?\"dddd\"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:null):\"ddd\"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null):\"dddd\"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):\"ddd\"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ia(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ha.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){\n// test the regex\nif(\n// make the regex if we don't have it already\ne=j([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp(\"^\"+this.weekdays(e,\"\").replace(\".\",\".?\")+\"$\",\"i\"),this._shortWeekdaysParse[d]=new RegExp(\"^\"+this.weekdaysShort(e,\"\").replace(\".\",\".?\")+\"$\",\"i\"),this._minWeekdaysParse[d]=new RegExp(\"^\"+this.weekdaysMin(e,\"\").replace(\".\",\".?\")+\"$\",\"i\")),this._weekdaysParse[d]||(f=\"^\"+this.weekdays(e,\"\")+\"|^\"+this.weekdaysShort(e,\"\")+\"|^\"+this.weekdaysMin(e,\"\"),this._weekdaysParse[d]=new RegExp(f.replace(\".\",\"\"),\"i\")),c&&\"dddd\"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&\"ddd\"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&\"dd\"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}\n// MOMENTS\nfunction Ja(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Ca(a,this.localeData()),this.add(a-b,\"d\")):b}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,\"d\")}function La(a){if(!this.isValid())return null!=a?this:NaN;\n// behaves the same as moment#day except\n// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)\n// as a setter, sunday should belong to the previous week.\nif(null!=a){var b=Da(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Ma(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(h(this,\"_weekdaysRegex\")||(this._weekdaysRegex=pe),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Na(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(h(this,\"_weekdaysShortRegex\")||(this._weekdaysShortRegex=qe),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Oa(a){return this._weekdaysParseExact?(h(this,\"_weekdaysRegex\")||Pa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(h(this,\"_weekdaysMinRegex\")||(this._weekdaysMinRegex=re),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Pa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],k=[];for(b=0;b<7;b++)\n// make the regex if we don't have it already\nc=j([2e3,1]).day(b),d=this.weekdaysMin(c,\"\"),e=this.weekdaysShort(c,\"\"),f=this.weekdays(c,\"\"),g.push(d),h.push(e),i.push(f),k.push(d),k.push(e),k.push(f);for(\n// Sorting makes sure if one weekday (or abbr) is a prefix of another it\n// will match the longer piece.\ng.sort(a),h.sort(a),i.sort(a),k.sort(a),b=0;b<7;b++)h[b]=_(h[b]),i[b]=_(i[b]),k[b]=_(k[b]);this._weekdaysRegex=new RegExp(\"^(\"+k.join(\"|\")+\")\",\"i\"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp(\"^(\"+i.join(\"|\")+\")\",\"i\"),this._weekdaysShortStrictRegex=new RegExp(\"^(\"+h.join(\"|\")+\")\",\"i\"),this._weekdaysMinStrictRegex=new RegExp(\"^(\"+g.join(\"|\")+\")\",\"i\")}\n// FORMATTING\nfunction Qa(){return this.hours()%12||12}function Ra(){return this.hours()||24}function Sa(a,b){T(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}\n// PARSING\nfunction Ta(a,b){return b._meridiemParse}\n// LOCALES\nfunction Ua(a){\n// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays\n// Using charAt should be more compatible.\nreturn\"p\"===(a+\"\").toLowerCase().charAt(0)}function Va(a,b,c){return a>11?c?\"pm\":\"PM\":c?\"am\":\"AM\"}function Wa(a){return a?a.toLowerCase().replace(\"_\",\"-\"):a}\n// pick the locale from the array\n// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each\n// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root\nfunction Xa(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Wa(a[f]).split(\"-\"),b=e.length,c=Wa(a[f+1]),c=c?c.split(\"-\"):null;b>0;){if(d=Ya(e.slice(0,b).join(\"-\")))return d;if(c&&c.length>=b&&u(e,c,!0)>=b-1)\n//the next array item is better than a shallower substring of this one\nbreak;b--}f++}return null}function Ya(a){var b=null;\n// TODO: Find a better way to register and load all the locales in Node\nif(!we[a]&&\"undefined\"!=typeof module&&module&&module.exports)try{b=se._abbr,require(\"./locale/\"+a),\n// because defineLocale currently also sets the global locale, we\n// want to undo that for lazy loaded locales\nZa(b)}catch(a){}return we[a]}\n// This function will load locale and then set the global locale.  If\n// no arguments are passed in, it will simply return the current global\n// locale key.\nfunction Za(a,b){var c;\n// moment.duration._locale = moment._locale = data;\nreturn a&&(c=o(b)?ab(a):$a(a,b),c&&(se=c)),se._abbr}function $a(a,b){if(null!==b){var c=ve;\n// treat as if there is no base config\n// backwards compat for now: also set the locale\nreturn b.abbr=a,null!=we[a]?(x(\"defineLocaleOverride\",\"use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info.\"),c=we[a]._config):null!=b.parentLocale&&(null!=we[b.parentLocale]?c=we[b.parentLocale]._config:x(\"parentLocaleUndefined\",\"specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/\")),we[a]=new B(A(c,b)),Za(a),we[a]}\n// useful for testing\nreturn delete we[a],null}function _a(a,b){if(null!=b){var c,d=ve;\n// MERGE\nnull!=we[a]&&(d=we[a]._config),b=A(d,b),c=new B(b),c.parentLocale=we[a],we[a]=c,\n// backwards compat for now: also set the locale\nZa(a)}else\n// pass null for config to unupdate, useful for tests\nnull!=we[a]&&(null!=we[a].parentLocale?we[a]=we[a].parentLocale:null!=we[a]&&delete we[a]);return we[a]}\n// returns locale data\nfunction ab(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return se;if(!c(a)){if(\n//short-circuit everything else\nb=Ya(a))return b;a=[a]}return Xa(a)}function bb(){return rd(we)}function cb(a){var b,c=a._a;return c&&l(a).overflow===-2&&(b=c[Zd]<0||c[Zd]>11?Zd:c[$d]<1||c[$d]>da(c[Yd],c[Zd])?$d:c[_d]<0||c[_d]>24||24===c[_d]&&(0!==c[ae]||0!==c[be]||0!==c[ce])?_d:c[ae]<0||c[ae]>59?ae:c[be]<0||c[be]>59?be:c[ce]<0||c[ce]>999?ce:-1,l(a)._overflowDayOfYear&&(b<Yd||b>$d)&&(b=$d),l(a)._overflowWeeks&&b===-1&&(b=de),l(a)._overflowWeekday&&b===-1&&(b=ee),l(a).overflow=b),a}\n// date from iso format\nfunction db(a){var b,c,d,e,f,g,h=a._i,i=xe.exec(h)||ye.exec(h);if(i){for(l(a).iso=!0,b=0,c=Ae.length;b<c;b++)if(Ae[b][1].exec(i[1])){e=Ae[b][0],d=Ae[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Be.length;b<c;b++)if(Be[b][1].exec(i[3])){\n// match[2] should be 'T' or space\nf=(i[2]||\" \")+Be[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!ze.exec(i[4]))return void(a._isValid=!1);g=\"Z\"}a._f=e+(f||\"\")+(g||\"\"),jb(a)}else a._isValid=!1}\n// date from iso format or fallback\nfunction eb(b){var c=Ce.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(db(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}\n// Pick the first defined of two or three arguments.\nfunction fb(a,b,c){return null!=a?a:null!=b?b:c}function gb(b){\n// hooks is actually the exported moment object\nvar c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}\n// convert an array to a date.\n// the array should mirror the parameters below\n// note: all values past the year are optional and will default to the lowest possible value.\n// [year, month, day , hour, minute, second, millisecond]\nfunction hb(a){var b,c,d,e,f=[];if(!a._d){\n// Default to current date.\n// * if no year, month, day of month are given, default to today\n// * if day of month is given, default month and year\n// * if month is given, default only year\n// * if year is given, don't default anything\nfor(d=gb(a),\n//compute day of the year from weeks and weekdays\na._w&&null==a._a[$d]&&null==a._a[Zd]&&ib(a),\n//if the day of the year is set, figure out what it is\na._dayOfYear&&(e=fb(a._a[Yd],d[Yd]),a._dayOfYear>oa(e)&&(l(a)._overflowDayOfYear=!0),c=sa(e,0,a._dayOfYear),a._a[Zd]=c.getUTCMonth(),a._a[$d]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b];\n// Zero out whatever was not defaulted, including time\nfor(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];\n// Check for 24:00:00.000\n24===a._a[_d]&&0===a._a[ae]&&0===a._a[be]&&0===a._a[ce]&&(a._nextDay=!0,a._a[_d]=0),a._d=(a._useUTC?sa:ra).apply(null,f),\n// Apply timezone offset from input. The actual utcOffset can be changed\n// with parseZone.\nnull!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[_d]=24)}}function ib(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,\n// TODO: We need to take the current isoWeekYear, but that depends on\n// how we interpret now (local, utc, fixed offset). So create\n// a now version of current config (take local/utc/offset flags, and\n// create now).\nc=fb(b.GG,a._a[Yd],va(rb(),1,4).year),d=fb(b.W,1),e=fb(b.E,1),(e<1||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=fb(b.gg,a._a[Yd],va(rb(),f,g).year),d=fb(b.w,1),null!=b.d?(\n// weekday -- low day numbers are considered next week\ne=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?(\n// local weekday -- counting starts from begining of week\ne=b.e+f,(b.e<0||b.e>6)&&(i=!0)):\n// default to begining of week\ne=f),d<1||d>wa(c,f,g)?l(a)._overflowWeeks=!0:null!=i?l(a)._overflowWeekday=!0:(h=ua(c,d,e,f,g),a._a[Yd]=h.year,a._dayOfYear=h.dayOfYear)}\n// date from string and format string\nfunction jb(b){\n// TODO: Move this to another part of the creation flow to prevent circular deps\nif(b._f===a.ISO_8601)return void db(b);b._a=[],l(b).empty=!0;\n// This array is used to make a Date, either with `new Date` or `Date.UTC`\nvar c,d,e,f,g,h=\"\"+b._i,i=h.length,j=0;for(e=X(b._f,b._locale).match(Bd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(Z(f,b))||[])[0],\n// console.log('token', token, 'parsedInput', parsedInput,\n//         'regex', getParseRegexForToken(token, config));\nd&&(g=h.substr(0,h.indexOf(d)),g.length>0&&l(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),\n// don't parse if it's not a known token\nEd[f]?(d?l(b).empty=!1:l(b).unusedTokens.push(f),ca(f,d,b)):b._strict&&!d&&l(b).unusedTokens.push(f);\n// add remaining unparsed input length to the string\nl(b).charsLeftOver=i-j,h.length>0&&l(b).unusedInput.push(h),\n// clear _12h flag if hour is <= 12\nb._a[_d]<=12&&l(b).bigHour===!0&&b._a[_d]>0&&(l(b).bigHour=void 0),l(b).parsedDateParts=b._a.slice(0),l(b).meridiem=b._meridiem,\n// handle meridiem\nb._a[_d]=kb(b._locale,b._a[_d],b._meridiem),hb(b),cb(b)}function kb(a,b,c){var d;\n// Fallback\nreturn null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b}\n// date from string and array of format strings\nfunction lb(a){var b,c,d,e,f;if(0===a._f.length)return l(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=p({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],jb(b),m(b)&&(\n// if there is any input that was not parsed add a penalty for that format\nf+=l(b).charsLeftOver,\n//or tokens\nf+=10*l(b).unusedTokens.length,l(b).score=f,(null==d||f<d)&&(d=f,c=b));i(a,c||b)}function mb(a){if(!a._d){var b=K(a._i);a._a=g([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),hb(a)}}function nb(a){var b=new q(cb(ob(a)));\n// Adding is smart enough around DST\nreturn b._nextDay&&(b.add(1,\"d\"),b._nextDay=void 0),b}function ob(a){var b=a._i,d=a._f;return a._locale=a._locale||ab(a._l),null===b||void 0===d&&\"\"===b?n({nullInput:!0}):(\"string\"==typeof b&&(a._i=b=a._locale.preparse(b)),r(b)?new q(cb(b)):(c(d)?lb(a):f(b)?a._d=b:d?jb(a):pb(a),m(a)||(a._d=null),a))}function pb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):f(d)?b._d=new Date(d.valueOf()):\"string\"==typeof d?eb(b):c(d)?(b._a=g(d.slice(0),function(a){return parseInt(a,10)}),hb(b)):\"object\"==typeof d?mb(b):\"number\"==typeof d?\n// from milliseconds\nb._d=new Date(d):a.createFromInputFallback(b)}function qb(a,b,f,g,h){var i={};\n// object construction must be done this way.\n// https://github.com/moment/moment/issues/1423\nreturn\"boolean\"==typeof f&&(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,nb(i)}function rb(a,b,c,d){return qb(a,b,c,d,!1)}\n// Pick a moment m from moments so that m[fn](other) is true for all\n// other. This relies on the function fn to be transitive.\n//\n// moments should either be an array of moment objects or an array, whose\n// first element is an array of moment objects.\nfunction sb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return rb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}\n// TODO: Use [].sort instead?\nfunction tb(){var a=[].slice.call(arguments,0);return sb(\"isBefore\",a)}function ub(){var a=[].slice.call(arguments,0);return sb(\"isAfter\",a)}function vb(a){var b=K(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;\n// representation for dateAddRemove\nthis._milliseconds=+k+1e3*j+// 1000\n6e4*i+// 1000 * 60\n1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978\n// Because of dateAddRemove treats 24 hours as different from a\n// day when working around DST, we need to store them separately\nthis._days=+g+7*f,\n// It is impossible translate months into days without knowing\n// which months you are are talking about, so we have to store\n// it separately.\nthis._months=+e+3*d+12*c,this._data={},this._locale=ab(),this._bubble()}function wb(a){return a instanceof vb}function xb(a){return a<0?Math.round(-1*a)*-1:Math.round(a)}\n// FORMATTING\nfunction yb(a,b){T(a,0,0,function(){var a=this.utcOffset(),c=\"+\";return a<0&&(a=-a,c=\"-\"),c+S(~~(a/60),2)+b+S(~~a%60,2)})}function zb(a,b){var c=(b||\"\").match(a)||[],d=c[c.length-1]||[],e=(d+\"\").match(Ge)||[\"-\",0,0],f=+(60*e[1])+t(e[2]);return\"+\"===e[0]?f:-f}\n// Return a moment from input, that is local/utc/zone equivalent to model.\nfunction Ab(b,c){var d,e;\n// Use low-level api, because this fn is low-level api.\nreturn c._isUTC?(d=c.clone(),e=(r(b)||f(b)?b.valueOf():rb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):rb(b).local()}function Bb(a){\n// On Firefox.24 Date#getTimezoneOffset returns a floating point.\n// https://github.com/moment/moment/pull/1871\nreturn 15*-Math.round(a._d.getTimezoneOffset()/15)}\n// MOMENTS\n// keepLocalTime = true means only change the timezone, without\n// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->\n// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset\n// +0200, so we adjust the time as needed, to be valid.\n//\n// Keeping the time actually adds/subtracts (one hour)\n// from the actual represented time. That is why we call updateOffset\n// a second time. In case it wants us to change the offset again\n// _changeInProgress == true case, then we have to adjust, because\n// there is no such time in the given timezone.\nfunction Cb(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?(\"string\"==typeof b?b=zb(Td,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Bb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,\"m\"),e!==b&&(!c||this._changeInProgress?Sb(this,Nb(b-e,\"m\"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Bb(this):null!=b?this:NaN}function Db(a,b){return null!=a?(\"string\"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Eb(a){return this.utcOffset(0,a)}function Fb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Bb(this),\"m\")),this}function Gb(){if(this._tzm)this.utcOffset(this._tzm);else if(\"string\"==typeof this._i){var a=zb(Sd,this._i);0===a?this.utcOffset(0,!0):this.utcOffset(zb(Sd,this._i))}return this}function Hb(a){return!!this.isValid()&&(a=a?rb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Ib(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Jb(){if(!o(this._isDSTShifted))return this._isDSTShifted;var a={};if(p(a,this),a=ob(a),a._a){var b=a._isUTC?j(a._a):rb(a._a);this._isDSTShifted=this.isValid()&&u(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Kb(){return!!this.isValid()&&!this._isUTC}function Lb(){return!!this.isValid()&&this._isUTC}function Mb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Nb(a,b){var c,d,e,f=a,\n// matching against regexp is expensive, do it on demand\ng=null;// checks for null or undefined\nreturn wb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:\"number\"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(g=He.exec(a))?(c=\"-\"===g[1]?-1:1,f={y:0,d:t(g[$d])*c,h:t(g[_d])*c,m:t(g[ae])*c,s:t(g[be])*c,ms:t(xb(1e3*g[ce]))*c}):(g=Ie.exec(a))?(c=\"-\"===g[1]?-1:1,f={y:Ob(g[2],c),M:Ob(g[3],c),w:Ob(g[4],c),d:Ob(g[5],c),h:Ob(g[6],c),m:Ob(g[7],c),s:Ob(g[8],c)}):null==f?f={}:\"object\"==typeof f&&(\"from\"in f||\"to\"in f)&&(e=Qb(rb(f.from),rb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new vb(f),wb(a)&&h(a,\"_locale\")&&(d._locale=a._locale),d}function Ob(a,b){\n// We'd normally use ~~inp for this, but unfortunately it also\n// converts floats to ints.\n// inp may be undefined, so careful calling replace on it.\nvar c=a&&parseFloat(a.replace(\",\",\".\"));\n// apply sign while we're at it\nreturn(isNaN(c)?0:c)*b}function Pb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,\"M\").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,\"M\"),c}function Qb(a,b){var c;return a.isValid()&&b.isValid()?(b=Ab(b,a),a.isBefore(b)?c=Pb(a,b):(c=Pb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}\n// TODO: remove 'name' arg after deprecation is removed\nfunction Rb(a,b){return function(c,d){var e,f;\n//invert the arguments, but complain about it\nreturn null===d||isNaN(+d)||(x(b,\"moment().\"+b+\"(period, number) is deprecated. Please use moment().\"+b+\"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.\"),f=c,c=d,d=f),c=\"string\"==typeof c?+c:c,e=Nb(c,d),Sb(this,e,a),this}}function Sb(b,c,d,e){var f=c._milliseconds,g=xb(c._days),h=xb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&P(b,\"Date\",O(b,\"Date\")+g*d),h&&ia(b,O(b,\"Month\")+h*d),e&&a.updateOffset(b,g||h))}function Tb(a,b){var c=a.diff(b,\"days\",!0);return c<-6?\"sameElse\":c<-1?\"lastWeek\":c<0?\"lastDay\":c<1?\"sameDay\":c<2?\"nextDay\":c<7?\"nextWeek\":\"sameElse\"}function Ub(b,c){\n// We want to compare the start of today, vs this.\n// Getting start-of-today depends on whether we're local/utc/offset or not.\nvar d=b||rb(),e=Ab(d,this).startOf(\"day\"),f=a.calendarFormat(this,e)||\"sameElse\",g=c&&(y(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,rb(d)))}function Vb(){return new q(this)}function Wb(a,b){var c=r(a)?a:rb(a);return!(!this.isValid()||!c.isValid())&&(b=J(o(b)?\"millisecond\":b),\"millisecond\"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf())}function Xb(a,b){var c=r(a)?a:rb(a);return!(!this.isValid()||!c.isValid())&&(b=J(o(b)?\"millisecond\":b),\"millisecond\"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf())}function Yb(a,b,c,d){return d=d||\"()\",(\"(\"===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(\")\"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function Zb(a,b){var c,d=r(a)?a:rb(a);return!(!this.isValid()||!d.isValid())&&(b=J(b||\"millisecond\"),\"millisecond\"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf()))}function $b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function _b(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function ac(a,b,c){var d,e,f,g;// 1000\n// 1000 * 60\n// 1000 * 60 * 60\n// 1000 * 60 * 60 * 24, negate dst\n// 1000 * 60 * 60 * 24 * 7, negate dst\nreturn this.isValid()?(d=Ab(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=J(b),\"year\"===b||\"month\"===b||\"quarter\"===b?(g=bc(this,d),\"quarter\"===b?g/=3:\"year\"===b&&(g/=12)):(f=this-d,g=\"second\"===b?f/1e3:\"minute\"===b?f/6e4:\"hour\"===b?f/36e5:\"day\"===b?(f-e)/864e5:\"week\"===b?(f-e)/6048e5:f),c?g:s(g)):NaN):NaN}function bc(a,b){\n// difference in months\nvar c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),\n// b is in (anchor - 1 month, anchor + 1 month)\nf=a.clone().add(e,\"months\");\n//check for negative zero, return zero if negative zero\n// linear across the month\n// linear across the month\nreturn b-f<0?(c=a.clone().add(e-1,\"months\"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,\"months\"),d=(b-f)/(c-f)),-(e+d)||0}function cc(){return this.clone().locale(\"en\").format(\"ddd MMM DD YYYY HH:mm:ss [GMT]ZZ\")}function dc(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?y(Date.prototype.toISOString)?this.toDate().toISOString():W(a,\"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]\"):W(a,\"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]\")}function ec(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=W(this,b);return this.localeData().postformat(c)}function fc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Nb({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function gc(a){return this.from(rb(),a)}function hc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Nb({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.to(rb(),a)}\n// If passed a locale key, it will set the locale for this\n// instance.  Otherwise, it will return the locale configuration\n// variables for this instance.\nfunction jc(a){var b;return void 0===a?this._locale._abbr:(b=ab(a),null!=b&&(this._locale=b),this)}function kc(){return this._locale}function lc(a){\n// the following switch intentionally omits break keywords\n// to utilize falling through the cases.\nswitch(a=J(a)){case\"year\":this.month(0);/* falls through */\ncase\"quarter\":case\"month\":this.date(1);/* falls through */\ncase\"week\":case\"isoWeek\":case\"day\":case\"date\":this.hours(0);/* falls through */\ncase\"hour\":this.minutes(0);/* falls through */\ncase\"minute\":this.seconds(0);/* falls through */\ncase\"second\":this.milliseconds(0)}\n// weeks are a special case\n// quarters are also special\nreturn\"week\"===a&&this.weekday(0),\"isoWeek\"===a&&this.isoWeekday(1),\"quarter\"===a&&this.month(3*Math.floor(this.month()/3)),this}function mc(a){\n// 'date' is an alias for 'day', so it should be considered as such.\nreturn a=J(a),void 0===a||\"millisecond\"===a?this:(\"date\"===a&&(a=\"day\"),this.startOf(a).add(1,\"isoWeek\"===a?\"week\":a).subtract(1,\"ms\"))}function nc(){return this._d.valueOf()-6e4*(this._offset||0)}function oc(){return Math.floor(this.valueOf()/1e3)}function pc(){return new Date(this.valueOf())}function qc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function rc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function sc(){\n// new Date(NaN).toJSON() === null\nreturn this.isValid()?this.toISOString():null}function tc(){return m(this)}function uc(){return i({},l(this))}function vc(){return l(this).overflow}function wc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function xc(a,b){T(0,[a,a.length],0,b)}\n// MOMENTS\nfunction yc(a){return Cc.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function zc(a){return Cc.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Ac(){return wa(this.year(),1,4)}function Bc(){var a=this.localeData()._week;return wa(this.year(),a.dow,a.doy)}function Cc(a,b,c,d,e){var f;return null==a?va(this,d,e).year:(f=wa(a,d,e),b>f&&(b=f),Dc.call(this,a,b,c,d,e))}function Dc(a,b,c,d,e){var f=ua(a,b,c,d,e),g=sa(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}\n// MOMENTS\nfunction Ec(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}\n// HELPERS\n// MOMENTS\nfunction Fc(a){var b=Math.round((this.clone().startOf(\"day\")-this.clone().startOf(\"year\"))/864e5)+1;return null==a?b:this.add(a-b,\"d\")}function Gc(a,b){b[ce]=t(1e3*(\"0.\"+a))}\n// MOMENTS\nfunction Hc(){return this._isUTC?\"UTC\":\"\"}function Ic(){return this._isUTC?\"Coordinated Universal Time\":\"\"}function Jc(a){return rb(1e3*a)}function Kc(){return rb.apply(null,arguments).parseZone()}function Lc(a){return a}function Mc(a,b,c,d){var e=ab(),f=j().set(d,b);return e[c](f,a)}function Nc(a,b,c){if(\"number\"==typeof a&&(b=a,a=void 0),a=a||\"\",null!=b)return Mc(a,b,c,\"month\");var d,e=[];for(d=0;d<12;d++)e[d]=Mc(a,d,c,\"month\");return e}\n// ()\n// (5)\n// (fmt, 5)\n// (fmt)\n// (true)\n// (true, 5)\n// (true, fmt, 5)\n// (true, fmt)\nfunction Oc(a,b,c,d){\"boolean\"==typeof a?(\"number\"==typeof b&&(c=b,b=void 0),b=b||\"\"):(b=a,c=b,a=!1,\"number\"==typeof b&&(c=b,b=void 0),b=b||\"\");var e=ab(),f=a?e._week.dow:0;if(null!=c)return Mc(b,(c+f)%7,d,\"day\");var g,h=[];for(g=0;g<7;g++)h[g]=Mc(b,(g+f)%7,d,\"day\");return h}function Pc(a,b){return Nc(a,b,\"months\")}function Qc(a,b){return Nc(a,b,\"monthsShort\")}function Rc(a,b,c){return Oc(a,b,c,\"weekdays\")}function Sc(a,b,c){return Oc(a,b,c,\"weekdaysShort\")}function Tc(a,b,c){return Oc(a,b,c,\"weekdaysMin\")}function Uc(){var a=this._data;return this._milliseconds=Ue(this._milliseconds),this._days=Ue(this._days),this._months=Ue(this._months),a.milliseconds=Ue(a.milliseconds),a.seconds=Ue(a.seconds),a.minutes=Ue(a.minutes),a.hours=Ue(a.hours),a.months=Ue(a.months),a.years=Ue(a.years),this}function Vc(a,b,c,d){var e=Nb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}\n// supports only 2.0-style add(1, 's') or add(duration)\nfunction Wc(a,b){return Vc(this,a,b,1)}\n// supports only 2.0-style subtract(1, 's') or subtract(duration)\nfunction Xc(a,b){return Vc(this,a,b,-1)}function Yc(a){return a<0?Math.floor(a):Math.ceil(a)}function Zc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;\n// if we have a mix of positive and negative values, bubble down first\n// check: https://github.com/moment/moment/issues/2166\n// The following code bubbles up values, see the tests for\n// examples of what that means.\n// convert days to months\n// 12 months -> 1 year\nreturn f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*Yc(_c(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=s(f/1e3),i.seconds=a%60,b=s(a/60),i.minutes=b%60,c=s(b/60),i.hours=c%24,g+=s(c/24),e=s($c(g)),h+=e,g-=Yc(_c(e)),d=s(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function $c(a){\n// 400 years have 146097 days (taking into account leap year rules)\n// 400 years have 12 months === 4800\nreturn 4800*a/146097}function _c(a){\n// the reverse of daysToMonths\nreturn 146097*a/4800}function ad(a){var b,c,d=this._milliseconds;if(a=J(a),\"month\"===a||\"year\"===a)return b=this._days+d/864e5,c=this._months+$c(b),\"month\"===a?c:c/12;switch(\n// handle milliseconds separately because of floating point math errors (issue #1867)\nb=this._days+Math.round(_c(this._months)),a){case\"week\":return b/7+d/6048e5;case\"day\":return b+d/864e5;case\"hour\":return 24*b+d/36e5;case\"minute\":return 1440*b+d/6e4;case\"second\":return 86400*b+d/1e3;\n// Math.floor prevents floating point math errors here\ncase\"millisecond\":return Math.floor(864e5*b)+d;default:throw new Error(\"Unknown unit \"+a)}}\n// TODO: Use this.as('ms')?\nfunction bd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*t(this._months/12)}function cd(a){return function(){return this.as(a)}}function dd(a){return a=J(a),this[a+\"s\"]()}function ed(a){return function(){return this._data[a]}}function fd(){return s(this.days()/7)}\n// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize\nfunction gd(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function hd(a,b,c){var d=Nb(a).abs(),e=jf(d.as(\"s\")),f=jf(d.as(\"m\")),g=jf(d.as(\"h\")),h=jf(d.as(\"d\")),i=jf(d.as(\"M\")),j=jf(d.as(\"y\")),k=e<kf.s&&[\"s\",e]||f<=1&&[\"m\"]||f<kf.m&&[\"mm\",f]||g<=1&&[\"h\"]||g<kf.h&&[\"hh\",g]||h<=1&&[\"d\"]||h<kf.d&&[\"dd\",h]||i<=1&&[\"M\"]||i<kf.M&&[\"MM\",i]||j<=1&&[\"y\"]||[\"yy\",j];return k[2]=b,k[3]=+a>0,k[4]=c,gd.apply(null,k)}\n// This function allows you to set the rounding function for relative time strings\nfunction id(a){return void 0===a?jf:\"function\"==typeof a&&(jf=a,!0)}\n// This function allows you to set a threshold for relative time strings\nfunction jd(a,b){return void 0!==kf[a]&&(void 0===b?kf[a]:(kf[a]=b,!0))}function kd(a){var b=this.localeData(),c=hd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function ld(){\n// for ISO strings we do not use the normal bubbling rules:\n//  * milliseconds bubble up until they become hours\n//  * days do not bubble at all\n//  * months bubble up until they become years\n// This is because there is no context-free conversion between hours and days\n// (think of clock changes)\n// and also not between days and months (28-31 days per month)\nvar a,b,c,d=lf(this._milliseconds)/1e3,e=lf(this._days),f=lf(this._months);\n// 3600 seconds -> 60 minutes -> 1 hour\na=s(d/60),b=s(a/60),d%=60,a%=60,\n// 12 months -> 1 year\nc=s(f/12),f%=12;\n// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js\nvar g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?\"-\":\"\")+\"P\"+(g?g+\"Y\":\"\")+(h?h+\"M\":\"\")+(i?i+\"D\":\"\")+(j||k||l?\"T\":\"\")+(j?j+\"H\":\"\")+(k?k+\"M\":\"\")+(l?l+\"S\":\"\"):\"P0D\"}var md,nd;nd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d<c;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};\n// Plugins that add properties should also add the key here (null value),\n// so we can properly clone ourselves.\nvar od=a.momentProperties=[],pd=!1,qd={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var rd;rd=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)h(a,b)&&c.push(b);return c};var sd,td={sameDay:\"[Today at] LT\",nextDay:\"[Tomorrow at] LT\",nextWeek:\"dddd [at] LT\",lastDay:\"[Yesterday at] LT\",lastWeek:\"[Last] dddd [at] LT\",sameElse:\"L\"},ud={LTS:\"h:mm:ss A\",LT:\"h:mm A\",L:\"MM/DD/YYYY\",LL:\"MMMM D, YYYY\",LLL:\"MMMM D, YYYY h:mm A\",LLLL:\"dddd, MMMM D, YYYY h:mm A\"},vd=\"Invalid date\",wd=\"%d\",xd=/\\d{1,2}/,yd={future:\"in %s\",past:\"%s ago\",s:\"a few seconds\",m:\"a minute\",mm:\"%d minutes\",h:\"an hour\",hh:\"%d hours\",d:\"a day\",dd:\"%d days\",M:\"a month\",MM:\"%d months\",y:\"a year\",yy:\"%d years\"},zd={},Ad={},Bd=/(\\[[^\\[]*\\])|(\\\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Cd=/(\\[[^\\[]*\\])|(\\\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Dd={},Ed={},Fd=/\\d/,Gd=/\\d\\d/,Hd=/\\d{3}/,Id=/\\d{4}/,Jd=/[+-]?\\d{6}/,Kd=/\\d\\d?/,Ld=/\\d\\d\\d\\d?/,Md=/\\d\\d\\d\\d\\d\\d?/,Nd=/\\d{1,3}/,Od=/\\d{1,4}/,Pd=/[+-]?\\d{1,6}/,Qd=/\\d+/,Rd=/[+-]?\\d+/,Sd=/Z|[+-]\\d\\d:?\\d\\d/gi,Td=/Z|[+-]\\d\\d(?::?\\d\\d)?/gi,Ud=/[+-]?\\d+(\\.\\d{1,3})?/,Vd=/[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i,Wd={},Xd={},Yd=0,Zd=1,$d=2,_d=3,ae=4,be=5,ce=6,de=7,ee=8;sd=Array.prototype.indexOf?Array.prototype.indexOf:function(a){\n// I know\nvar b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1},\n// FORMATTING\nT(\"M\",[\"MM\",2],\"Mo\",function(){return this.month()+1}),T(\"MMM\",0,0,function(a){return this.localeData().monthsShort(this,a)}),T(\"MMMM\",0,0,function(a){return this.localeData().months(this,a)}),\n// ALIASES\nI(\"month\",\"M\"),\n// PRIORITY\nL(\"month\",8),\n// PARSING\nY(\"M\",Kd),Y(\"MM\",Kd,Gd),Y(\"MMM\",function(a,b){return b.monthsShortRegex(a)}),Y(\"MMMM\",function(a,b){return b.monthsRegex(a)}),aa([\"M\",\"MM\"],function(a,b){b[Zd]=t(a)-1}),aa([\"MMM\",\"MMMM\"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);\n// if we didn't find a month name, mark the date as invalid.\nnull!=e?b[Zd]=e:l(c).invalidMonth=a});\n// LOCALES\nvar fe=/D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?/,ge=\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),he=\"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec\".split(\"_\"),ie=Vd,je=Vd;\n// FORMATTING\nT(\"Y\",0,0,function(){var a=this.year();return a<=9999?\"\"+a:\"+\"+a}),T(0,[\"YY\",2],0,function(){return this.year()%100}),T(0,[\"YYYY\",4],0,\"year\"),T(0,[\"YYYYY\",5],0,\"year\"),T(0,[\"YYYYYY\",6,!0],0,\"year\"),\n// ALIASES\nI(\"year\",\"y\"),\n// PRIORITIES\nL(\"year\",1),\n// PARSING\nY(\"Y\",Rd),Y(\"YY\",Kd,Gd),Y(\"YYYY\",Od,Id),Y(\"YYYYY\",Pd,Jd),Y(\"YYYYYY\",Pd,Jd),aa([\"YYYYY\",\"YYYYYY\"],Yd),aa(\"YYYY\",function(b,c){c[Yd]=2===b.length?a.parseTwoDigitYear(b):t(b)}),aa(\"YY\",function(b,c){c[Yd]=a.parseTwoDigitYear(b)}),aa(\"Y\",function(a,b){b[Yd]=parseInt(a,10)}),\n// HOOKS\na.parseTwoDigitYear=function(a){return t(a)+(t(a)>68?1900:2e3)};\n// MOMENTS\nvar ke=N(\"FullYear\",!0);\n// FORMATTING\nT(\"w\",[\"ww\",2],\"wo\",\"week\"),T(\"W\",[\"WW\",2],\"Wo\",\"isoWeek\"),\n// ALIASES\nI(\"week\",\"w\"),I(\"isoWeek\",\"W\"),\n// PRIORITIES\nL(\"week\",5),L(\"isoWeek\",5),\n// PARSING\nY(\"w\",Kd),Y(\"ww\",Kd,Gd),Y(\"W\",Kd),Y(\"WW\",Kd,Gd),ba([\"w\",\"ww\",\"W\",\"WW\"],function(a,b,c,d){b[d.substr(0,1)]=t(a)});var le={dow:0,// Sunday is the first day of the week.\ndoy:6};\n// FORMATTING\nT(\"d\",0,\"do\",\"day\"),T(\"dd\",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),T(\"ddd\",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),T(\"dddd\",0,0,function(a){return this.localeData().weekdays(this,a)}),T(\"e\",0,0,\"weekday\"),T(\"E\",0,0,\"isoWeekday\"),\n// ALIASES\nI(\"day\",\"d\"),I(\"weekday\",\"e\"),I(\"isoWeekday\",\"E\"),\n// PRIORITY\nL(\"day\",11),L(\"weekday\",11),L(\"isoWeekday\",11),\n// PARSING\nY(\"d\",Kd),Y(\"e\",Kd),Y(\"E\",Kd),Y(\"dd\",function(a,b){return b.weekdaysMinRegex(a)}),Y(\"ddd\",function(a,b){return b.weekdaysShortRegex(a)}),Y(\"dddd\",function(a,b){return b.weekdaysRegex(a)}),ba([\"dd\",\"ddd\",\"dddd\"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);\n// if we didn't get a weekday name, mark the date as invalid\nnull!=e?b.d=e:l(c).invalidWeekday=a}),ba([\"d\",\"e\",\"E\"],function(a,b,c,d){b[d]=t(a)});\n// LOCALES\nvar me=\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),ne=\"Sun_Mon_Tue_Wed_Thu_Fri_Sat\".split(\"_\"),oe=\"Su_Mo_Tu_We_Th_Fr_Sa\".split(\"_\"),pe=Vd,qe=Vd,re=Vd;T(\"H\",[\"HH\",2],0,\"hour\"),T(\"h\",[\"hh\",2],0,Qa),T(\"k\",[\"kk\",2],0,Ra),T(\"hmm\",0,0,function(){return\"\"+Qa.apply(this)+S(this.minutes(),2)}),T(\"hmmss\",0,0,function(){return\"\"+Qa.apply(this)+S(this.minutes(),2)+S(this.seconds(),2)}),T(\"Hmm\",0,0,function(){return\"\"+this.hours()+S(this.minutes(),2)}),T(\"Hmmss\",0,0,function(){return\"\"+this.hours()+S(this.minutes(),2)+S(this.seconds(),2)}),Sa(\"a\",!0),Sa(\"A\",!1),\n// ALIASES\nI(\"hour\",\"h\"),\n// PRIORITY\nL(\"hour\",13),Y(\"a\",Ta),Y(\"A\",Ta),Y(\"H\",Kd),Y(\"h\",Kd),Y(\"HH\",Kd,Gd),Y(\"hh\",Kd,Gd),Y(\"hmm\",Ld),Y(\"hmmss\",Md),Y(\"Hmm\",Ld),Y(\"Hmmss\",Md),aa([\"H\",\"HH\"],_d),aa([\"a\",\"A\"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),aa([\"h\",\"hh\"],function(a,b,c){b[_d]=t(a),l(c).bigHour=!0}),aa(\"hmm\",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d)),l(c).bigHour=!0}),aa(\"hmmss\",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e)),l(c).bigHour=!0}),aa(\"Hmm\",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d))}),aa(\"Hmmss\",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e))});var se,te=/[ap]\\.?m?\\.?/i,ue=N(\"Hours\",!0),ve={calendar:td,longDateFormat:ud,invalidDate:vd,ordinal:wd,ordinalParse:xd,relativeTime:yd,months:ge,monthsShort:he,week:le,weekdays:me,weekdaysMin:oe,weekdaysShort:ne,meridiemParse:te},we={},xe=/^\\s*((?:[+-]\\d{6}|\\d{4})-(?:\\d\\d-\\d\\d|W\\d\\d-\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?::\\d\\d(?::\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?/,ye=/^\\s*((?:[+-]\\d{6}|\\d{4})(?:\\d\\d\\d\\d|W\\d\\d\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?:\\d\\d(?:\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?/,ze=/Z|[+-]\\d\\d(?::?\\d\\d)?/,Ae=[[\"YYYYYY-MM-DD\",/[+-]\\d{6}-\\d\\d-\\d\\d/],[\"YYYY-MM-DD\",/\\d{4}-\\d\\d-\\d\\d/],[\"GGGG-[W]WW-E\",/\\d{4}-W\\d\\d-\\d/],[\"GGGG-[W]WW\",/\\d{4}-W\\d\\d/,!1],[\"YYYY-DDD\",/\\d{4}-\\d{3}/],[\"YYYY-MM\",/\\d{4}-\\d\\d/,!1],[\"YYYYYYMMDD\",/[+-]\\d{10}/],[\"YYYYMMDD\",/\\d{8}/],\n// YYYYMM is NOT allowed by the standard\n[\"GGGG[W]WWE\",/\\d{4}W\\d{3}/],[\"GGGG[W]WW\",/\\d{4}W\\d{2}/,!1],[\"YYYYDDD\",/\\d{7}/]],Be=[[\"HH:mm:ss.SSSS\",/\\d\\d:\\d\\d:\\d\\d\\.\\d+/],[\"HH:mm:ss,SSSS\",/\\d\\d:\\d\\d:\\d\\d,\\d+/],[\"HH:mm:ss\",/\\d\\d:\\d\\d:\\d\\d/],[\"HH:mm\",/\\d\\d:\\d\\d/],[\"HHmmss.SSSS\",/\\d\\d\\d\\d\\d\\d\\.\\d+/],[\"HHmmss,SSSS\",/\\d\\d\\d\\d\\d\\d,\\d+/],[\"HHmmss\",/\\d\\d\\d\\d\\d\\d/],[\"HHmm\",/\\d\\d\\d\\d/],[\"HH\",/\\d\\d/]],Ce=/^\\/?Date\\((\\-?\\d+)/i;a.createFromInputFallback=w(\"value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.\",function(a){a._d=new Date(a._i+(a._useUTC?\" UTC\":\"\"))}),\n// constant that refers to the ISO standard\na.ISO_8601=function(){};var De=w(\"moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?a<this?this:a:n()}),Ee=w(\"moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:n()}),Fe=function(){return Date.now?Date.now():+new Date};yb(\"Z\",\":\"),yb(\"ZZ\",\"\"),\n// PARSING\nY(\"Z\",Td),Y(\"ZZ\",Td),aa([\"Z\",\"ZZ\"],function(a,b,c){c._useUTC=!0,c._tzm=zb(Td,a)});\n// HELPERS\n// timezone chunker\n// '+10:00' > ['10',  '00']\n// '-1530'  > ['-15', '30']\nvar Ge=/([\\+\\-]|\\d\\d)/gi;\n// HOOKS\n// This function will be called whenever a moment is mutated.\n// It is intended to keep the offset in sync with the timezone.\na.updateOffset=function(){};\n// ASP.NET json date format regex\nvar He=/^(\\-)?(?:(\\d*)[. ])?(\\d+)\\:(\\d+)(?:\\:(\\d+)(\\.\\d*)?)?$/,Ie=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Nb.fn=vb.prototype;var Je=Rb(1,\"add\"),Ke=Rb(-1,\"subtract\");a.defaultFormat=\"YYYY-MM-DDTHH:mm:ssZ\",a.defaultFormatUtc=\"YYYY-MM-DDTHH:mm:ss[Z]\";var Le=w(\"moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.\",function(a){return void 0===a?this.localeData():this.locale(a)});\n// FORMATTING\nT(0,[\"gg\",2],0,function(){return this.weekYear()%100}),T(0,[\"GG\",2],0,function(){return this.isoWeekYear()%100}),xc(\"gggg\",\"weekYear\"),xc(\"ggggg\",\"weekYear\"),xc(\"GGGG\",\"isoWeekYear\"),xc(\"GGGGG\",\"isoWeekYear\"),\n// ALIASES\nI(\"weekYear\",\"gg\"),I(\"isoWeekYear\",\"GG\"),\n// PRIORITY\nL(\"weekYear\",1),L(\"isoWeekYear\",1),\n// PARSING\nY(\"G\",Rd),Y(\"g\",Rd),Y(\"GG\",Kd,Gd),Y(\"gg\",Kd,Gd),Y(\"GGGG\",Od,Id),Y(\"gggg\",Od,Id),Y(\"GGGGG\",Pd,Jd),Y(\"ggggg\",Pd,Jd),ba([\"gggg\",\"ggggg\",\"GGGG\",\"GGGGG\"],function(a,b,c,d){b[d.substr(0,2)]=t(a)}),ba([\"gg\",\"GG\"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),\n// FORMATTING\nT(\"Q\",0,\"Qo\",\"quarter\"),\n// ALIASES\nI(\"quarter\",\"Q\"),\n// PRIORITY\nL(\"quarter\",7),\n// PARSING\nY(\"Q\",Fd),aa(\"Q\",function(a,b){b[Zd]=3*(t(a)-1)}),\n// FORMATTING\nT(\"D\",[\"DD\",2],\"Do\",\"date\"),\n// ALIASES\nI(\"date\",\"D\"),\n// PRIOROITY\nL(\"date\",9),\n// PARSING\nY(\"D\",Kd),Y(\"DD\",Kd,Gd),Y(\"Do\",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),aa([\"D\",\"DD\"],$d),aa(\"Do\",function(a,b){b[$d]=t(a.match(Kd)[0],10)});\n// MOMENTS\nvar Me=N(\"Date\",!0);\n// FORMATTING\nT(\"DDD\",[\"DDDD\",3],\"DDDo\",\"dayOfYear\"),\n// ALIASES\nI(\"dayOfYear\",\"DDD\"),\n// PRIORITY\nL(\"dayOfYear\",4),\n// PARSING\nY(\"DDD\",Nd),Y(\"DDDD\",Hd),aa([\"DDD\",\"DDDD\"],function(a,b,c){c._dayOfYear=t(a)}),\n// FORMATTING\nT(\"m\",[\"mm\",2],0,\"minute\"),\n// ALIASES\nI(\"minute\",\"m\"),\n// PRIORITY\nL(\"minute\",14),\n// PARSING\nY(\"m\",Kd),Y(\"mm\",Kd,Gd),aa([\"m\",\"mm\"],ae);\n// MOMENTS\nvar Ne=N(\"Minutes\",!1);\n// FORMATTING\nT(\"s\",[\"ss\",2],0,\"second\"),\n// ALIASES\nI(\"second\",\"s\"),\n// PRIORITY\nL(\"second\",15),\n// PARSING\nY(\"s\",Kd),Y(\"ss\",Kd,Gd),aa([\"s\",\"ss\"],be);\n// MOMENTS\nvar Oe=N(\"Seconds\",!1);\n// FORMATTING\nT(\"S\",0,0,function(){return~~(this.millisecond()/100)}),T(0,[\"SS\",2],0,function(){return~~(this.millisecond()/10)}),T(0,[\"SSS\",3],0,\"millisecond\"),T(0,[\"SSSS\",4],0,function(){return 10*this.millisecond()}),T(0,[\"SSSSS\",5],0,function(){return 100*this.millisecond()}),T(0,[\"SSSSSS\",6],0,function(){return 1e3*this.millisecond()}),T(0,[\"SSSSSSS\",7],0,function(){return 1e4*this.millisecond()}),T(0,[\"SSSSSSSS\",8],0,function(){return 1e5*this.millisecond()}),T(0,[\"SSSSSSSSS\",9],0,function(){return 1e6*this.millisecond()}),\n// ALIASES\nI(\"millisecond\",\"ms\"),\n// PRIORITY\nL(\"millisecond\",16),\n// PARSING\nY(\"S\",Nd,Fd),Y(\"SS\",Nd,Gd),Y(\"SSS\",Nd,Hd);var Pe;for(Pe=\"SSSS\";Pe.length<=9;Pe+=\"S\")Y(Pe,Qd);for(Pe=\"S\";Pe.length<=9;Pe+=\"S\")aa(Pe,Gc);\n// MOMENTS\nvar Qe=N(\"Milliseconds\",!1);\n// FORMATTING\nT(\"z\",0,0,\"zoneAbbr\"),T(\"zz\",0,0,\"zoneName\");var Re=q.prototype;Re.add=Je,Re.calendar=Ub,Re.clone=Vb,Re.diff=ac,Re.endOf=mc,Re.format=ec,Re.from=fc,Re.fromNow=gc,Re.to=hc,Re.toNow=ic,Re.get=Q,Re.invalidAt=vc,Re.isAfter=Wb,Re.isBefore=Xb,Re.isBetween=Yb,Re.isSame=Zb,Re.isSameOrAfter=$b,Re.isSameOrBefore=_b,Re.isValid=tc,Re.lang=Le,Re.locale=jc,Re.localeData=kc,Re.max=Ee,Re.min=De,Re.parsingFlags=uc,Re.set=R,Re.startOf=lc,Re.subtract=Ke,Re.toArray=qc,Re.toObject=rc,Re.toDate=pc,Re.toISOString=dc,Re.toJSON=sc,Re.toString=cc,Re.unix=oc,Re.valueOf=nc,Re.creationData=wc,\n// Year\nRe.year=ke,Re.isLeapYear=qa,\n// Week Year\nRe.weekYear=yc,Re.isoWeekYear=zc,\n// Quarter\nRe.quarter=Re.quarters=Ec,\n// Month\nRe.month=ja,Re.daysInMonth=ka,\n// Week\nRe.week=Re.weeks=Aa,Re.isoWeek=Re.isoWeeks=Ba,Re.weeksInYear=Bc,Re.isoWeeksInYear=Ac,\n// Day\nRe.date=Me,Re.day=Re.days=Ja,Re.weekday=Ka,Re.isoWeekday=La,Re.dayOfYear=Fc,\n// Hour\nRe.hour=Re.hours=ue,\n// Minute\nRe.minute=Re.minutes=Ne,\n// Second\nRe.second=Re.seconds=Oe,\n// Millisecond\nRe.millisecond=Re.milliseconds=Qe,\n// Offset\nRe.utcOffset=Cb,Re.utc=Eb,Re.local=Fb,Re.parseZone=Gb,Re.hasAlignedHourOffset=Hb,Re.isDST=Ib,Re.isLocal=Kb,Re.isUtcOffset=Lb,Re.isUtc=Mb,Re.isUTC=Mb,\n// Timezone\nRe.zoneAbbr=Hc,Re.zoneName=Ic,\n// Deprecations\nRe.dates=w(\"dates accessor is deprecated. Use date instead.\",Me),Re.months=w(\"months accessor is deprecated. Use month instead\",ja),Re.years=w(\"years accessor is deprecated. Use year instead\",ke),Re.zone=w(\"moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/\",Db),Re.isDSTShifted=w(\"isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information\",Jb);var Se=Re,Te=B.prototype;Te.calendar=C,Te.longDateFormat=D,Te.invalidDate=E,Te.ordinal=F,Te.preparse=Lc,Te.postformat=Lc,Te.relativeTime=G,Te.pastFuture=H,Te.set=z,\n// Month\nTe.months=ea,Te.monthsShort=fa,Te.monthsParse=ha,Te.monthsRegex=ma,Te.monthsShortRegex=la,\n// Week\nTe.week=xa,Te.firstDayOfYear=za,Te.firstDayOfWeek=ya,\n// Day of Week\nTe.weekdays=Ea,Te.weekdaysMin=Ga,Te.weekdaysShort=Fa,Te.weekdaysParse=Ia,Te.weekdaysRegex=Ma,Te.weekdaysShortRegex=Na,Te.weekdaysMinRegex=Oa,\n// Hours\nTe.isPM=Ua,Te.meridiem=Va,Za(\"en\",{ordinalParse:/\\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===t(a%100/10)?\"th\":1===b?\"st\":2===b?\"nd\":3===b?\"rd\":\"th\";return a+c}}),\n// Side effect imports\na.lang=w(\"moment.lang is deprecated. Use moment.locale instead.\",Za),a.langData=w(\"moment.langData is deprecated. Use moment.localeData instead.\",ab);var Ue=Math.abs,Ve=cd(\"ms\"),We=cd(\"s\"),Xe=cd(\"m\"),Ye=cd(\"h\"),Ze=cd(\"d\"),$e=cd(\"w\"),_e=cd(\"M\"),af=cd(\"y\"),bf=ed(\"milliseconds\"),cf=ed(\"seconds\"),df=ed(\"minutes\"),ef=ed(\"hours\"),ff=ed(\"days\"),gf=ed(\"months\"),hf=ed(\"years\"),jf=Math.round,kf={s:45,// seconds to minute\nm:45,// minutes to hour\nh:22,// hours to day\nd:26,// days to month\nM:11},lf=Math.abs,mf=vb.prototype;mf.abs=Uc,mf.add=Wc,mf.subtract=Xc,mf.as=ad,mf.asMilliseconds=Ve,mf.asSeconds=We,mf.asMinutes=Xe,mf.asHours=Ye,mf.asDays=Ze,mf.asWeeks=$e,mf.asMonths=_e,mf.asYears=af,mf.valueOf=bd,mf._bubble=Zc,mf.get=dd,mf.milliseconds=bf,mf.seconds=cf,mf.minutes=df,mf.hours=ef,mf.days=ff,mf.weeks=fd,mf.months=gf,mf.years=hf,mf.humanize=kd,mf.toISOString=ld,mf.toString=ld,mf.toJSON=ld,mf.locale=jc,mf.localeData=kc,\n// Deprecations\nmf.toIsoString=w(\"toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)\",ld),mf.lang=Le,\n// Side effect imports\n// FORMATTING\nT(\"X\",0,0,\"unix\"),T(\"x\",0,0,\"valueOf\"),\n// PARSING\nY(\"x\",Rd),Y(\"X\",Ud),aa(\"X\",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa(\"x\",function(a,b,c){c._d=new Date(t(a))}),\n// Side effect imports\na.version=\"2.15.2\",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Nb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf});"
  },
  {
    "path": "web/vue/public/vendor/toml.js",
    "content": "// https://github.com/jakwings/toml-j0.4\n!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var r;r=\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:this,r.toml=e()}}(function(){return function e(r,t,n){function i(u,a){if(!t[u]){if(!r[u]){var c=\"function\"==typeof require&&require;if(!a&&c)return c(u,!0);if(o)return o(u,!0);var s=new Error(\"Cannot find module '\"+u+\"'\");throw s.code=\"MODULE_NOT_FOUND\",s}var l=t[u]={exports:{}};r[u][0].call(l.exports,function(e){var t=r[u][1][e];return i(t?t:e)},l,l.exports,e,r,t,n)}return t[u].exports}for(var o=\"function\"==typeof require&&require,u=0;u<n.length;u++)i(n[u]);return i}({1:[function(e,r,t){r.exports=function(){function e(e,r){function t(){this.constructor=e}t.prototype=r.prototype,e.prototype=new t}function r(e,r,t,n,i,o){this.message=e,this.expected=r,this.found=t,this.offset=n,this.line=i,this.column=o,this.name=\"SyntaxError\"}function t(e){function t(){return e.substring(Ot,Dt)}function n(e){throw u(e,null,Ot)}function i(r){function t(r,t,n){var i,o;for(i=t;n>i;i++)o=e.charAt(i),\"\\n\"===o?(r.seenCR||r.line++,r.column=1,r.seenCR=!1):\"\\r\"===o||\"\\u2028\"===o||\"\\u2029\"===o?(r.line++,r.column=1,r.seenCR=!0):(r.column++,r.seenCR=!1)}return Tt!==r&&(Tt>r&&(Tt=0,jt={line:1,column:1,seenCR:!1}),t(jt,Tt,r),Tt=r),jt}function o(e){Nt>Dt||(Dt>Nt&&(Nt=Dt,Ut=[]),Ut.push(e))}function u(t,n,o){function u(e){var r=1;for(e.sort(function(e,r){return e.description<r.description?-1:e.description>r.description?1:0});r<e.length;)e[r-1]===e[r]?e.splice(r,1):r++}function a(e,r){function t(e){function r(e){return e.charCodeAt(0).toString(16).toUpperCase()}return e.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\x08/g,\"\\\\b\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\f/g,\"\\\\f\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g,function(e){return\"\\\\x0\"+r(e)}).replace(/[\\x10-\\x1F\\x80-\\xFF]/g,function(e){return\"\\\\x\"+r(e)}).replace(/[\\u0180-\\u0FFF]/g,function(e){return\"\\\\u0\"+r(e)}).replace(/[\\u1080-\\uFFFF]/g,function(e){return\"\\\\u\"+r(e)})}var n,i,o,u=new Array(e.length);for(o=0;o<e.length;o++)u[o]=e[o].description;return n=e.length>1?u.slice(0,-1).join(\", \")+\" or \"+u[e.length-1]:u[0],i=r?'\"'+t(r)+'\"':\"end of input\",\"Expected \"+n+\" but \"+i+\" found.\"}var c=i(o),s=o<e.length?e.charAt(o):null;return null!==n&&u(n),new r(null!==t?t:a(n,s),n,s,o,c.line,c.column)}function a(){var e,r,t,n,i,o,u,p;for(e=Dt,r=[],t=l(),t===ye&&(t=s(),t===ye&&(t=f()));t!==ye;)r.push(t),t=l(),t===ye&&(t=s(),t===ye&&(t=f()));if(r!==ye){if(t=Dt,n=c(),n!==ye){for(i=[],o=l(),o===ye&&(o=f());o!==ye;)i.push(o),o=l(),o===ye&&(o=f());i!==ye?(o=Dt,u=s(),u!==ye?(p=a(),p!==ye?(u=[u,p],o=u):(Dt=o,o=Ce)):(Dt=o,o=Ce),o===ye&&(o=be),o!==ye?(n=[n,i,o],t=n):(Dt=t,t=Ce)):(Dt=t,t=Ce)}else Dt=t,t=Ce;t===ye&&(t=be),t!==ye?(Ot=e,r=xe(),e=r):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function c(){var e,r;return e=Dt,r=pe(),r!==ye&&(Ot=e,r=me(r)),e=r,e===ye&&(e=Dt,r=he(),r!==ye&&(Ot=e,r=Fe(r)),e=r,e===ye&&(e=Dt,r=p(),r!==ye&&(Ot=e,r=Se(r)),e=r)),e}function s(){var r,t;return Zt++,10===e.charCodeAt(Dt)?(r=Ee,Dt++):(r=ye,0===Zt&&o(Re)),r===ye&&(e.substr(Dt,2)===_e?(r=_e,Dt+=2):(r=ye,0===Zt&&o(De))),Zt--,r===ye&&(t=ye,0===Zt&&o(we)),r}function l(){var r,t;return Zt++,Te.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(je)),Zt--,r===ye&&(t=ye,0===Zt&&o(Oe)),r}function f(){var r,t,n,i,u,a;if(Zt++,r=Dt,35===e.charCodeAt(Dt)?(t=Ue,Dt++):(t=ye,0===Zt&&o(Ze)),t!==ye){for(n=[],i=Dt,u=Dt,Zt++,a=s(),Zt--,a===ye?u=He:(Dt=u,u=Ce),u!==ye?(e.length>Dt?(a=e.charAt(Dt),Dt++):(a=ye,0===Zt&&o(Me)),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);i!==ye;)n.push(i),i=Dt,u=Dt,Zt++,a=s(),Zt--,a===ye?u=He:(Dt=u,u=Ce),u!==ye?(e.length>Dt?(a=e.charAt(Dt),Dt++):(a=ye,0===Zt&&o(Me)),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return Zt--,r===ye&&(t=ye,0===Zt&&o(Ne)),r}function p(){var r,t,n,i,u,a;if(r=Dt,t=h(),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye)if(61===e.charCodeAt(Dt)?(i=Ie,Dt++):(i=ye,0===Zt&&o(qe)),i!==ye){for(u=[],a=l();a!==ye;)u.push(a),a=l();u!==ye?(a=x(),a!==ye?(Ot=r,t=ze(t,a),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce;else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function h(){var e;return e=d(),e===ye&&(e=y()),e}function d(){var e,r,t;if(e=Dt,r=[],t=v(),t!==ye)for(;t!==ye;)r.push(t),t=v();else r=Ce;return r!==ye&&(Ot=e,r=Be()),e=r}function v(){var r,t;return Zt++,Ye.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(Je)),Zt--,r===ye&&(t=ye,0===Zt&&o(Qe)),r}function y(){var e,r,t,n;if(e=Dt,r=g(),r!==ye){if(t=[],n=S(),n!==ye)for(;n!==ye;)t.push(n),n=S();else t=Ce;t!==ye?(n=g(),n!==ye?(Ot=e,r=Pe(t),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function g(){var r,t;return Zt++,34===e.charCodeAt(Dt)?(r=Le,Dt++):(r=ye,0===Zt&&o(Ve)),Zt--,r===ye&&(t=ye,0===Zt&&o(ke)),r}function A(){var r,t;return Zt++,39===e.charCodeAt(Dt)?(r=Ge,Dt++):(r=ye,0===Zt&&o(Ke)),Zt--,r===ye&&(t=ye,0===Zt&&o(We)),r}function C(){var r,t;return Zt++,e.substr(Dt,3)===$e?(r=$e,Dt+=3):(r=ye,0===Zt&&o(er)),Zt--,r===ye&&(t=ye,0===Zt&&o(Xe)),r}function b(){var r,t;return Zt++,e.substr(Dt,3)===tr?(r=tr,Dt+=3):(r=ye,0===Zt&&o(nr)),Zt--,r===ye&&(t=ye,0===Zt&&o(rr)),r}function x(){var e;return e=m(),e===ye&&(e=B(),e===ye&&(e=G(),e===ye&&(e=Q(),e===ye&&(e=P(),e===ye&&(e=ce(),e===ye&&(e=fe())))))),e}function m(){var e;return e=U(),e===ye&&(e=F(),e===ye&&(e=I(),e===ye&&(e=j()))),e}function F(){var e,r,t,n;if(e=Dt,r=g(),r!==ye){for(t=[],n=S();n!==ye;)t.push(n),n=S();t!==ye?(n=g(),n!==ye?(Ot=e,r=ir(t),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function S(){var e;return e=w(),e===ye&&(e=E()),e}function w(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(ur.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(ar)),n!==ye?(Ot=r,t=Be(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function E(){var r,t,n,i,u;return r=Dt,t=_(),t!==ye?(n=R(),n===ye&&(n=g(),n===ye&&(n=_(),n===ye&&(n=Dt,117===e.charCodeAt(Dt)?(i=cr,Dt++):(i=ye,0===Zt&&o(sr)),i!==ye?(u=D(),u!==ye?(i=[i,u],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce),n===ye&&(n=Dt,85===e.charCodeAt(Dt)?(i=lr,Dt++):(i=ye,0===Zt&&o(fr)),i!==ye?(u=O(),u!==ye?(i=[i,u],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce))))),n!==ye?(Ot=r,t=pr(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function R(){var r,t;return Zt++,dr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(vr)),Zt--,r===ye&&(t=ye,0===Zt&&o(hr)),r}function _(){var r,t;return Zt++,92===e.charCodeAt(Dt)?(r=gr,Dt++):(r=ye,0===Zt&&o(Ar)),Zt--,r===ye&&(t=ye,0===Zt&&o(yr)),r}function D(){var e,r,t,n,i;return Zt++,e=Dt,r=T(),r!==ye?(t=T(),t!==ye?(n=T(),n!==ye?(i=T(),i!==ye?(r=[r,t,n,i],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(Cr)),e}function O(){var e,r,t,n,i,u,a,c,s;return Zt++,e=Dt,r=T(),r!==ye?(t=T(),t!==ye?(n=T(),n!==ye?(i=T(),i!==ye?(u=T(),u!==ye?(a=T(),a!==ye?(c=T(),c!==ye?(s=T(),s!==ye?(r=[r,t,n,i,u,a,c,s],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(br)),e}function T(){var r;return xr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(mr)),r}function j(){var e,r,t,n;if(e=Dt,r=A(),r!==ye){for(t=[],n=N();n!==ye;)t.push(n),n=N();t!==ye?(n=A(),n!==ye?(Ot=e,r=Fr(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;return e}function N(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Sr.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(wr)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function U(){var e,r,t,n,i;if(e=Dt,r=C(),r!==ye)if(t=s(),t===ye&&(t=be),t!==ye){for(n=[],i=Z();i!==ye;)n.push(i),i=Z();n!==ye?(i=C(),i!==ye?(Ot=e,r=Er(n),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;else Dt=e,e=Ce;return e}function Z(){var e,r,t;return e=H(),e===ye&&(e=Dt,r=_(),r!==ye?(t=s(),t!==ye?(Ot=e,r=Be(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e===ye&&(e=s())),e}function H(){var e,r,t;return e=Dt,r=Dt,Zt++,t=C(),Zt--,t===ye?r=He:(Dt=r,r=Ce),r!==ye?(t=M(),t!==ye?(Ot=e,r=Be(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e===ye&&(e=E()),e}function M(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Rr.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(_r)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(or)),r}function I(){var e,r,t,n,i;if(e=Dt,r=b(),r!==ye)if(t=s(),t===ye&&(t=be),t!==ye){for(n=[],i=q();i!==ye;)n.push(i),i=q();n!==ye?(i=b(),i!==ye?(Ot=e,r=ir(n),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)}else Dt=e,e=Ce;else Dt=e,e=Ce;return e}function q(){var r,t,n;return r=Dt,t=Dt,Zt++,e.substr(Dt,3)===tr?(n=tr,Dt+=3):(n=ye,0===Zt&&o(nr)),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(n=z(),n!==ye?(Ot=r,t=Be(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r===ye&&(r=s()),r}function z(){var r,t,n;return Zt++,r=Dt,t=Dt,Zt++,n=s(),Zt--,n===ye?t=He:(Dt=t,t=Ce),t!==ye?(Or.test(e.charAt(Dt))?(n=e.charAt(Dt),Dt++):(n=ye,0===Zt&&o(Tr)),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(Dr)),r}function B(){var r,t;return r=Dt,e.substr(Dt,4)===jr?(t=jr,Dt+=4):(t=ye,0===Zt&&o(Nr)),t!==ye&&(Ot=r,t=Ur()),r=t,r===ye&&(r=Dt,e.substr(Dt,5)===Zr?(t=Zr,Dt+=5):(t=ye,0===Zt&&o(Hr)),t!==ye&&(Ot=r,t=Mr()),r=t),r}function Q(){var e,r,t,n,i;return e=Dt,r=P(),r!==ye?(t=Dt,n=Y(),n!==ye?(i=J(),i===ye&&(i=be),i!==ye?(n=[n,i],t=n):(Dt=t,t=Ce)):(Dt=t,t=Ce),t===ye&&(t=J()),t!==ye?(Ot=e,r=Ir(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function Y(){var r,t,n,i,u,a,c;if(r=Dt,46===e.charCodeAt(Dt)?(t=qr,Dt++):(t=ye,0===Zt&&o(zr)),t!==ye)if(n=W(),n!==ye){for(i=[],u=Dt,95===e.charCodeAt(Dt)?(a=Br,Dt++):(a=ye,0===Zt&&o(Qr)),a===ye&&(a=be),a!==ye?(c=W(),c!==ye?(a=[a,c],u=a):(Dt=u,u=Ce)):(Dt=u,u=Ce);u!==ye;)i.push(u),u=Dt,95===e.charCodeAt(Dt)?(a=Br,Dt++):(a=ye,0===Zt&&o(Qr)),a===ye&&(a=be),a!==ye?(c=W(),c!==ye?(a=[a,c],u=a):(Dt=u,u=Ce)):(Dt=u,u=Ce);i!==ye?(t=[t,n,i],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;else Dt=r,r=Ce;return r}function J(){var r,t,n;return r=Dt,101===e.charCodeAt(Dt)?(t=Yr,Dt++):(t=ye,0===Zt&&o(Jr)),t===ye&&(69===e.charCodeAt(Dt)?(t=Pr,Dt++):(t=ye,0===Zt&&o(kr))),t!==ye?(n=P(),n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function P(){var e,r,t;return e=Dt,r=k(),r===ye&&(r=be),r!==ye?(t=L(),t!==ye?(Ot=e,r=Lr(),e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function k(){var r;return 43===e.charCodeAt(Dt)?(r=Vr,Dt++):(r=ye,0===Zt&&o(Wr)),r===ye&&(45===e.charCodeAt(Dt)?(r=Gr,Dt++):(r=ye,0===Zt&&o(Kr))),r}function L(){var r,t,n,i,u,a;if(r=Dt,t=V(),t!==ye){if(n=[],i=Dt,95===e.charCodeAt(Dt)?(u=Br,Dt++):(u=ye,0===Zt&&o(Qr)),u===ye&&(u=be),u!==ye?(a=W(),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce),i!==ye)for(;i!==ye;)n.push(i),i=Dt,95===e.charCodeAt(Dt)?(u=Br,Dt++):(u=ye,0===Zt&&o(Qr)),u===ye&&(u=be),u!==ye?(a=W(),a!==ye?(u=[u,a],i=u):(Dt=i,i=Ce)):(Dt=i,i=Ce);else n=Ce;n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r===ye&&(r=W()),r}function V(){var r;return Xr.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o($r)),r}function W(){var r;return et.test(e.charAt(Dt))?(r=e.charAt(Dt),Dt++):(r=ye,0===Zt&&o(rt)),r}function G(){var r,t,n,i;return r=Dt,t=K(),t!==ye?(84===e.charCodeAt(Dt)?(n=tt,Dt++):(n=ye,0===Zt&&o(nt)),n!==ye?(i=re(),i!==ye?(Ot=r,t=it(),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function K(){var r,t,n,i,u,a;return Zt++,r=Dt,t=X(),t!==ye?(45===e.charCodeAt(Dt)?(n=Gr,Dt++):(n=ye,0===Zt&&o(Kr)),n!==ye?(i=$(),i!==ye?(45===e.charCodeAt(Dt)?(u=Gr,Dt++):(u=ye,0===Zt&&o(Kr)),u!==ye?(a=ee(),a!==ye?(t=[t,n,i,u,a],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),Zt--,r===ye&&(t=ye,0===Zt&&o(ot)),r}function X(){var e,r,t,n,i;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(n=W(),n!==ye?(i=W(),i!==ye?(r=[r,t,n,i],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function $(){var e,r,t;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function ee(){var e,r,t;return e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function re(){var e,r,t;return e=Dt,r=te(),r!==ye?(t=ae(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),e}function te(){var r,t,n,i,u,a,c;return r=Dt,t=ne(),t!==ye?(58===e.charCodeAt(Dt)?(n=ut,Dt++):(n=ye,0===Zt&&o(at)),n!==ye?(i=ie(),i!==ye?(58===e.charCodeAt(Dt)?(u=ut,Dt++):(u=ye,0===Zt&&o(at)),u!==ye?(a=oe(),a!==ye?(c=ue(),c===ye&&(c=be),c!==ye?(t=[t,n,i,u,a,c],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function ne(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(ct)),e}function ie(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(st)),e}function oe(){var e,r,t;return Zt++,e=Dt,r=W(),r!==ye?(t=W(),t!==ye?(r=[r,t],e=r):(Dt=e,e=Ce)):(Dt=e,e=Ce),Zt--,e===ye&&(r=ye,0===Zt&&o(lt)),e}function ue(){var r,t,n,i;if(r=Dt,46===e.charCodeAt(Dt)?(t=qr,Dt++):(t=ye,0===Zt&&o(zr)),t!==ye){if(n=[],i=W(),i!==ye)for(;i!==ye;)n.push(i),i=W();else n=Ce;n!==ye?(t=[t,n],r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r}function ae(){var r,t,n,i,u;return Zt++,90===e.charCodeAt(Dt)?(r=pt,Dt++):(r=ye,0===Zt&&o(ht)),r===ye&&(r=Dt,t=k(),t!==ye?(n=ne(),n!==ye?(58===e.charCodeAt(Dt)?(i=ut,Dt++):(i=ye,0===Zt&&o(at)),i!==ye?(u=ie(),u!==ye?(t=[t,n,i,u],r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce)),Zt--,r===ye&&(t=ye,0===Zt&&o(ft)),r}function ce(){var r,t,n,i,u,a,c,s,l,f;if(r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye){for(n=[],i=le();i!==ye;)n.push(i),i=le();if(n!==ye){if(i=Dt,u=se(),u!==ye){for(a=[],c=le();c!==ye;)a.push(c),c=le();if(a!==ye){if(c=Dt,44===e.charCodeAt(Dt)?(s=yt,Dt++):(s=ye,0===Zt&&o(gt)),s!==ye){for(l=[],f=le();f!==ye;)l.push(f),f=le();l!==ye?(s=[s,l],c=s):(Dt=c,c=Ce)}else Dt=c,c=Ce;c===ye&&(c=be),c!==ye?(u=[u,a,c],i=u):(Dt=i,i=Ce)}else Dt=i,i=Ce}else Dt=i,i=Ce;i===ye&&(i=be),i!==ye?(93===e.charCodeAt(Dt)?(u=At,Dt++):(u=ye,0===Zt&&o(Ct)),u!==ye?(Ot=r,t=bt(i),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function se(){var r,t,n,i,u,a,c;if(r=Dt,t=x(),t!==ye){for(n=Dt,i=[],u=le();u!==ye;)i.push(u),u=le();if(i!==ye)if(44===e.charCodeAt(Dt)?(u=yt,Dt++):(u=ye,0===Zt&&o(gt)),u!==ye){for(a=[],c=le();c!==ye;)a.push(c),c=le();a!==ye?(c=se(),c!==ye?(i=[i,u,a,c],n=i):(Dt=n,n=Ce)):(Dt=n,n=Ce)}else Dt=n,n=Ce;else Dt=n,n=Ce;n===ye&&(n=be),n!==ye?(Ot=r,t=xt(t,n),r=t):(Dt=r,r=Ce)}else Dt=r,r=Ce;return r}function le(){var e;return e=l(),e===ye&&(e=s(),e===ye&&(e=f())),e}function fe(){var r,t,n,i,u,a,c,s,f,h,d;if(r=Dt,123===e.charCodeAt(Dt)?(t=mt,Dt++):(t=ye,0===Zt&&o(Ft)),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye){if(i=Dt,u=p(),u!==ye){for(a=[],c=Dt,s=[],f=l();f!==ye;)s.push(f),f=l();if(s!==ye)if(44===e.charCodeAt(Dt)?(f=yt,Dt++):(f=ye,0===Zt&&o(gt)),f!==ye){for(h=[],d=l();d!==ye;)h.push(d),d=l();h!==ye?(d=p(),d!==ye?(s=[s,f,h,d],c=s):(Dt=c,c=Ce)):(Dt=c,c=Ce)}else Dt=c,c=Ce;else Dt=c,c=Ce;for(;c!==ye;){for(a.push(c),c=Dt,s=[],f=l();f!==ye;)s.push(f),f=l();if(s!==ye)if(44===e.charCodeAt(Dt)?(f=yt,Dt++):(f=ye,0===Zt&&o(gt)),f!==ye){for(h=[],d=l();d!==ye;)h.push(d),d=l();h!==ye?(d=p(),d!==ye?(s=[s,f,h,d],c=s):(Dt=c,c=Ce)):(Dt=c,c=Ce)}else Dt=c,c=Ce;else Dt=c,c=Ce}if(a!==ye){for(c=[],s=l();s!==ye;)c.push(s),s=l();c!==ye?(u=[u,a,c],i=u):(Dt=i,i=Ce)}else Dt=i,i=Ce}else Dt=i,i=Ce;i===ye&&(i=be),i!==ye?(125===e.charCodeAt(Dt)?(u=St,Dt++):(u=ye,0===Zt&&o(wt)),u!==ye?(Ot=r,t=Et(i),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;return r}function pe(){var r,t,n,i;return r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye?(n=he(),n!==ye?(93===e.charCodeAt(Dt)?(i=At,Dt++):(i=ye,0===Zt&&o(Ct)),i!==ye?(Ot=r,t=Rt(n),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)):(Dt=r,r=Ce),r}function he(){var r,t,n,i,u,a,c,s,f,p;if(r=Dt,91===e.charCodeAt(Dt)?(t=dt,Dt++):(t=ye,0===Zt&&o(vt)),t!==ye){for(n=[],i=l();i!==ye;)n.push(i),i=l();if(n!==ye)if(i=h(),i!==ye){for(u=[],a=Dt,c=[],s=l();s!==ye;)c.push(s),s=l();if(c!==ye)if(46===e.charCodeAt(Dt)?(s=qr,Dt++):(s=ye,0===Zt&&o(zr)),s!==ye){for(f=[],p=l();p!==ye;)f.push(p),p=l();f!==ye?(p=h(),p!==ye?(c=[c,s,f,p],a=c):(Dt=a,a=Ce)):(Dt=a,a=Ce)}else Dt=a,a=Ce;else Dt=a,a=Ce;for(;a!==ye;){for(u.push(a),a=Dt,c=[],s=l();s!==ye;)c.push(s),s=l();if(c!==ye)if(46===e.charCodeAt(Dt)?(s=qr,Dt++):(s=ye,0===Zt&&o(zr)),s!==ye){for(f=[],p=l();p!==ye;)f.push(p),p=l();f!==ye?(p=h(),p!==ye?(c=[c,s,f,p],a=c):(Dt=a,a=Ce)):(Dt=a,a=Ce)}else Dt=a,a=Ce;else Dt=a,a=Ce}if(u!==ye){for(a=[],c=l();c!==ye;)a.push(c),c=l();a!==ye?(93===e.charCodeAt(Dt)?(c=At,Dt++):(c=ye,0===Zt&&o(Ct)),c!==ye?(Ot=r,t=_t(i,u),r=t):(Dt=r,r=Ce)):(Dt=r,r=Ce)}else Dt=r,r=Ce}else Dt=r,r=Ce;else Dt=r,r=Ce}else Dt=r,r=Ce;return r}var de,ve=arguments.length>1?arguments[1]:{},ye={},ge={Expressions:a},Ae=a,Ce=ye,be=null,xe=function(){return Pt},me=function(e){kt=Jt(Pt,!0,e)},Fe=function(e){kt=Jt(Pt,!1,e)},Se=function(e){Yt(kt.table,e[0]),kt.table[e[0]]=e[1]},we={type:\"other\",description:\"Newline\"},Ee=\"\\n\",Re={type:\"literal\",value:\"\\n\",description:'\"\\\\n\"'},_e=\"\\r\\n\",De={type:\"literal\",value:\"\\r\\n\",description:'\"\\\\r\\\\n\"'},Oe={type:\"other\",description:\"Whitespace\"},Te=/^[ \\t]/,je={type:\"class\",value:\"[ \\\\t]\",description:\"[ \\\\t]\"},Ne={type:\"other\",description:\"Comment\"},Ue=\"#\",Ze={type:\"literal\",value:\"#\",description:'\"#\"'},He=void 0,Me={type:\"any\",description:\"any character\"},Ie=\"=\",qe={type:\"literal\",value:\"=\",description:'\"=\"'},ze=function(e,r){return[e,r.value]},Be=function(){return t()},Qe={type:\"other\",description:'[a-z], [A-Z], [0-9], \"-\", \"_\"'},Ye=/^[a-zA-Z0-9\\-_]/,Je={type:\"class\",value:\"[a-zA-Z0-9\\\\-_]\",description:\"[a-zA-Z0-9\\\\-_]\"},Pe=function(e){return e.join(\"\")},ke={type:\"other\",description:\"DoubleQuote\"},Le='\"',Ve={type:\"literal\",value:'\"',description:'\"\\\\\"\"'},We={type:\"other\",description:\"SingleQuote\"},Ge=\"'\",Ke={type:\"literal\",value:\"'\",description:'\"\\'\"'},Xe={type:\"other\",description:\"ThreeDoubleQuotes\"},$e='\"\"\"',er={type:\"literal\",value:'\"\"\"',description:'\"\\\\\"\\\\\"\\\\\"\"'},rr={type:\"other\",description:\"ThreeSingleQuotes\"},tr=\"'''\",nr={type:\"literal\",value:\"'''\",description:\"\\\"'''\\\"\"},ir=function(e){return{type:\"String\",value:e.join(\"\")}},or={type:\"other\",description:\"NormalCharacter\"},ur=/^[^\\0-\\x1F\"\\\\]/,ar={type:\"class\",value:'[^\\\\0-\\\\x1F\"\\\\\\\\]',description:'[^\\\\0-\\\\x1F\"\\\\\\\\]'},cr=\"u\",sr={type:\"literal\",value:\"u\",description:'\"u\"'},lr=\"U\",fr={type:\"literal\",value:\"U\",description:'\"U\"'},pr=function(){var e=t();return e.length<=2?Bt(e[1]):Qt(parseInt(e.substr(2),16))},hr={type:\"other\",description:'\"b\", \"f\", \"n\", \"r\", \"t\"'},dr=/^[bfnrt]/,vr={type:\"class\",value:\"[bfnrt]\",description:\"[bfnrt]\"},yr={type:\"other\",description:\"Backslash\"},gr=\"\\\\\",Ar={type:\"literal\",value:\"\\\\\",description:'\"\\\\\\\\\"'},Cr={type:\"other\",description:\"FourHexadecimalDigits\"},br={type:\"other\",description:\"EightHexadecimalDigits\"},xr=/^[0-9A-Fa-f]/,mr={type:\"class\",value:\"[0-9A-Fa-f]\",description:\"[0-9A-Fa-f]\"},Fr=function(){var e=t();return{type:\"String\",value:e.substr(1,e.length-2)}},Sr=/^[^\\0-\\x08\\n-\\x1F']/,wr={type:\"class\",value:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F']\",description:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F']\"},Er=function(e){return{type:\"String\",value:e.join(\"\").replace(/\\\\\\r?\\n(?:\\r?\\n|[ \\t])*/g,\"\")}},Rr=/^[^\\0-\\x1F\\\\]/,_r={type:\"class\",value:\"[^\\\\0-\\\\x1F\\\\\\\\]\",description:\"[^\\\\0-\\\\x1F\\\\\\\\]\"},Dr={type:\"other\",description:\"AnyCharacter\"},Or=/^[^\\0-\\x08\\n-\\x1F]/,Tr={type:\"class\",value:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F]\",description:\"[^\\\\0-\\\\x08\\\\n-\\\\x1F]\"},jr=\"true\",Nr={type:\"literal\",value:\"true\",description:'\"true\"'},Ur=function(){return{type:\"Boolean\",value:!0}},Zr=\"false\",Hr={type:\"literal\",value:\"false\",description:'\"false\"'},Mr=function(){return{type:\"Boolean\",value:!1}},Ir=function(){var e=t(),r=parseFloat(e.replace(/_/g,\"\"));return Mt(r)||n(e+\"is not a 64-bit floating-point number.\"),{type:\"Float\",value:r}},qr=\".\",zr={type:\"literal\",value:\".\",description:'\".\"'},Br=\"_\",Qr={type:\"literal\",value:\"_\",description:'\"_\"'},Yr=\"e\",Jr={type:\"literal\",value:\"e\",description:'\"e\"'},Pr=\"E\",kr={type:\"literal\",value:\"E\",description:'\"E\"'},Lr=function(){var e=t(),r=e.replace(/_/g,\"\"),i=!1;if(\"-\"===r[0]){var o=\"-9223372036854775808\";(r.length>o.length||r.length===o.length&&r>o)&&(i=!0)}else{\"+\"===r[0]&&(r=r.substr(1));var u=\"9223372036854775807\";(r.length>u.length||r.length===u.length&&r>u)&&(i=!0)}return i&&n(e+\" is not a 64-bit signed integer.\"),r=parseInt(r,10),Mt(r)||n(e+\" is not a 64-bit signed integer.\"),{type:\"Integer\",value:r}},Vr=\"+\",Wr={type:\"literal\",value:\"+\",description:'\"+\"'},Gr=\"-\",Kr={type:\"literal\",value:\"-\",description:'\"-\"'},Xr=/^[1-9]/,$r={type:\"class\",value:\"[1-9]\",description:\"[1-9]\"},et=/^[0-9]/,rt={type:\"class\",value:\"[0-9]\",description:\"[0-9]\"},tt=\"T\",nt={type:\"literal\",value:\"T\",description:'\"T\"'},it=function(){var e=t(),r=new Date(e);return Mt(r.getTime())||n(\"Date-time \"+e+\" is invalid. It does not conform to RFC 3339 or this is a browser-specific problem.\"),{type:\"DateTime\",value:r}},ot={type:\"other\",description:\"FullDate (YYYY-mm-dd)\"},ut=\":\",at={type:\"literal\",value:\":\",description:'\":\"'},ct={type:\"other\",description:\"Hour (HH)\"},st={type:\"other\",description:\"Minute (MM)\"},lt={type:\"other\",description:\"Second (SS)\"},ft={type:\"other\",description:\"TimeOffset (Z or +/-HH:MM)\"},pt=\"Z\",ht={type:\"literal\",value:\"Z\",description:'\"Z\"'},dt=\"[\",vt={type:\"literal\",value:\"[\",description:'\"[\"'},yt=\",\",gt={type:\"literal\",value:\",\",description:'\",\"'},At=\"]\",Ct={type:\"literal\",value:\"]\",description:'\"]\"'},bt=function(e){for(var r={type:\"Array\",value:e?e[0]:[]},t=0,n=r.value,i=n.length;i>t;t++)n[t]=n[t].value;return r},xt=function(e,r){var t=[e];if(r)for(var i=e.type,o=0,u=r[3],a=u.length;a>o;o++)i!==u[o].type&&n(zt(u[o].value)+' should be of type \"'+i+'\".'),t.push(u[o]);return t},mt=\"{\",Ft={type:\"literal\",value:\"{\",description:'\"{\"'},St=\"}\",wt={type:\"literal\",value:\"}\",description:'\"}\"'},Et=function(e){var r={};if(e){r[e[0][0]]=e[0][1];for(var t=0,n=e[1],i=n.length;i>t;t++){var o=n[t][3];Yt(r,o[0]),r[o[0]]=o[1]}}return{type:\"InlineTable\",value:r}},Rt=function(e){return e},_t=function(e,r){for(var t=[e],n=0,i=r.length;i>n;n++)t.push(r[n][3]);return t},Dt=0,Ot=0,Tt=0,jt={line:1,column:1,seenCR:!1},Nt=0,Ut=[],Zt=0;if(\"startRule\"in ve){if(!(ve.startRule in ge))throw new Error(\"Can't start parsing from rule \\\"\"+ve.startRule+'\".');Ae=ge[ve.startRule]}var Ht,Mt,It,qt,zt,Bt,Qt,Yt,Jt;Ht=function(e){return\"Value for \"+e+\" should not be redefined in the same table.\"},Mt=Number.isFinite||function(e){return\"number\"==typeof e&&isFinite(e)},It=Array.isArray||function(e){return\"[object Array]\"===Object.prototype.toString.call(e)},qt=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},zt=\"object\"==typeof JSON&&JSON?JSON.stringify:function(e){return'\"'+String(e).replace(/[\\x00-\\x1F\"\\\\]/g,function(e){switch(e){case'\"':case\"\\\\\":return\"\\\\\"+e;case\"  \":return\"\\\\t\";case\"\\n\":return\"\\\\n\";case\"\\r\":return\"\\\\r\";case\"\\b\":return\"\\\\b\";case\"\\f\":return\"\\\\f\";default:var r=e.charCodeAt(0).toString(16);return\"\\\\u\"+\"0000\".substr(r.length)+r}})+'\"'},Bt=function(e){switch(e){case'\"':case\"\\\\\":return e;case\"t\":return\" \";case\"n\":return\"\\n\";case\"r\":return\"\\r\";case\"b\":return\"\\b\";case\"f\":return\"\\f\";default:n(zt(e)+\" cannot be escaped.\")}},Qt=function(e){if((!Mt(e)||0>e||e>1114111)&&n(\"U+\"+e.toString(16)+\" is not a valid Unicode code point.\"),String.fromCodePoint)return String.fromCodePoint(e);var r=\"\";return e>65535&&(e-=65536,r+=String.fromCharCode(e>>>10&1023|55296),e=56320|1023&e),r+=String.fromCharCode(e)},Yt=function(e,r){qt(e,r)&&n(Ht(zt(r)))},Jt=function(e,r,t){for(var i=\"\",o=0,u=t.length;u>o;o++){var a=t[o];if(i+=(i?\".\":\"\")+zt(a),qt(e,a))if(r)if(It(e[a]))if(Wt[i]||n(Ht(i)),o+1===u){var c={};e[a].push(c),e=c}else i+=\".\"+zt(e[a].length-1),e=e[a][e[a].length-1];else Lt[i]||n(Ht(i)),e=e[a];else It(e[a])?(Wt[i]&&o+1!==u||n(Ht(i)),i+=\".\"+zt(e[a].length-1),e=e[a][e[a].length-1]):(Lt[i]||n(Ht(i)),e=e[a]);else if(r&&o+1===u){var c={};e[a]=[c],e=c,Wt[i]=!0}else e=e[a]={},Lt[i]=!0}return r?Wt[i]||n(Ht(i)):((Vt[i]||Wt[i])&&n(Ht(i)),Vt[i]=!0),{table:e,path:t}};var Pt={},kt={table:Pt,path:[]},Lt={},Vt={},Wt={};if(de=Ae(),de!==ye&&Dt===e.length)return de;throw de!==ye&&Dt<e.length&&o({type:\"end\",description:\"end of input\"}),u(null,Ut,Nt)}return e(r,Error),{SyntaxError:r,parse:t}}()},{}],2:[function(e,r,t){\"use strict\";var n=e(\"./lib/parser\"),i={parse:function(e){return n.parse(e)},SyntaxError:n.SyntaxError};r.exports=i},{\"./lib/parser\":1}]},{},[2])(2)});"
  },
  {
    "path": "web/vue/src/App.vue",
    "content": "<script>\n\nimport top from './components/layout/header.vue'\nimport bottom from './components/layout/footer.vue'\nimport modal from './components/layout/modal.vue'\n\nexport default {\n  name: 'app',\n  components: {\n    top,\n    bottom,\n    modal\n  }\n}\n</script>\n\n<template lang='pug'>\n  #app\n    top\n    .fill\n      router-view.view\n    bottom\n    modal\n</template>\n\n<style>\n\n#app {\n  display: flex;\n  min-height: 100vh;\n  flex-direction: column;\n}\n\n.fill {\n  flex: 1;\n}\n\n.text {\n  max-width: 500px;\n}\n\ninput {\n  background: none;\n  margin-top: 0.5em;\n}\n\n.params {\n  min-height: 235px;\n  line-height: 1.3em;\n}\n\n.hr {\n  margin-top: 2rem;\n  margin-bottom: 2rem;\n  height: 10px;\n  background-color: rgba(250,250,250,.99);\n}\n\n.contain {\n  width: 900px;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.btn--primary {\n  display: inline-block;\n  margin-right: 12px;\n  margin-bottom: 12px;\n  height: 40px;\n  padding: 0 18px;\n  border-radius: 4px;\n  background-color: #3498db;\n  text-shadow: 0 1px 3px rgba(36,180,126,.4);\n  box-shadow: 0 4px 6px rgba(50,50,93,.11), 0 1px 3px rgba(0,0,0,.08);\n  color: #fff;\n  text-decoration: none;\n  line-height: 40px;\n  transition: transform 250ms;\n}\n\n.btn--primary:hover {\n  transform: translateY(-1px);\n  box-shadow: 0 7px 14px rgba(50,50,93,.1), 0 3px 6px rgba(0,0,0,.08);\n  background-color: #3498db;\n  color: #fff;\n  text-decoration: none;\n}\n\n.btn--primary:active,\n.btn--primary:focus {\n  background-color: #3498db;\n  color: #fff;\n  text-decoration: none;\n}\n\n.btn--primary:active {\n  transform: translateY(1px);\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/backtester/backtestConfigBuilder.vue",
    "content": "<template lang='pug'>\n  div\n    dataset-picker.my2(v-on:dataset='updateDataset').contain\n    .hr\n    strat-picker.my2(v-on:stratConfig='updateStrat').contain\n    .hr\n    paper-trader(v-on:settings='updatePaperTrader').contain\n    .hr\n</template>\n\n<script>\n\nimport datasetPicker from '../global/configbuilder/datasetpicker.vue'\nimport stratPicker from '../global/configbuilder/stratpicker.vue'\nimport paperTrader from '../global/configbuilder/papertrader.vue'\nimport _ from 'lodash'\nimport { get } from '../../tools/ajax'\n\nexport default {\n  created: function() {\n    get('configPart/performanceAnalyzer', (error, response) => {\n      this.performanceAnalyzer = toml.parse(response.part);\n      this.performanceAnalyzer.enabled = true;\n    });\n  },\n  data: () => {\n    return {\n      dataset: {},\n      strat: {},\n      paperTrader: {},\n      performanceAnalyzer: {}\n    }\n  },\n  components: {\n    stratPicker,\n    datasetPicker,\n    paperTrader\n  },\n  computed: {\n    market: function() {\n      if(!this.dataset.exchange)\n        return {};\n\n      return {\n        exchange: this.dataset.exchange,\n        currency: this.dataset.currency,\n        asset: this.dataset.asset\n      }\n    },\n    range: function() {\n      if(!this.dataset.exchange)\n        return {};\n\n      return {\n        from: this.dataset.from,\n        to: this.dataset.to\n      }\n    },\n    config: function() {\n      let config = {};\n      Object.assign(\n        config,\n        { watch: this.market },\n        { paperTrader: this.paperTrader },\n        this.strat,\n        {\n          backtest: {\n            daterange: this.range\n          },\n          backtestResultExporter: {\n            enabled: true,\n            writeToDisk: false,\n            data: {\n              stratUpdates: false,\n              roundtrips: true,\n              stratCandles: true,\n              stratCandleProps: ['open'],\n              trades: true\n            }\n          }\n        },\n        { performanceAnalyzer: this.performanceAnalyzer },\n      );\n\n      config.valid = this.validConfig(config);\n      config.backtestResultExporter.enabled = true;\n\n      return config;\n    }\n  },\n  methods: {\n    validConfig: function(config) {\n      if(!config.backtest)\n        return false;\n\n      if(!config.backtest.daterange)\n        return false;\n\n      if(_.isEmpty(config.backtest.daterange))\n        return false;\n\n      if(!config.watch)\n        return false;\n\n      if(!config.tradingAdvisor)\n        return false;\n\n      let strat = config.tradingAdvisor.method;\n      if(_.isEmpty(config[ strat ]))\n        return false;\n\n      if(config.tradingAdvisor) {\n        if(_.isNaN(config.tradingAdvisor.candleSize))\n          return false;\n        else if(config.tradingAdvisor.candleSize == 0)\n          return false;\n      }\n\n      return true;\n    },\n    updateDataset: function(set) {\n      this.dataset = set;\n      this.$emit('config', this.config);\n    },\n    updateStrat: function(sc) {\n      this.strat = sc;\n      this.$emit('config', this.config);\n    },\n    updatePaperTrader: function(pt) {\n      this.paperTrader = pt;\n      this.paperTrader.enabled = true;\n      this.$emit('config', this.config);\n    },\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/backtester/backtester.vue",
    "content": "<template lang='pug'>\n  div\n    h2.contain Backtest\n    .hr\n    config-builder(v-on:config='check')\n    div(v-if='backtestable')\n      .txt--center\n        a.w100--s.my1.btn--primary(href='#', v-if='backtestState !== \"fetching\"', v-on:click.prevent='run') Backtest\n        div(v-if='backtestState === \"fetching\"').scan-btn\n          p Running backtest..\n          spinner\n    result(v-if='backtestResult && backtestState === \"fetched\"', :result='backtestResult')\n</template>\n\n<script>\nimport configBuilder from './backtestConfigBuilder.vue'\nimport result from './result/result.vue'\nimport { post } from '../../tools/ajax'\nimport spinner from '../global/blockSpinner.vue'\n\nexport default {\n  data: () => {\n    return {\n      backtestable: false,\n      backtestState: 'idle',\n      backtestResult: false,\n      config: false,\n    }\n  },\n  methods: {\n    check: function(config) {\n      // console.log('CHECK', config);\n      this.config = config;\n\n      if(!config.valid)\n        return this.backtestable = false;\n\n      this.backtestable = true;\n    },\n    run: function() {\n      this.backtestState = 'fetching';\n\n      post('backtest', this.config, (error, response) => {\n        this.backtestState = 'fetched';\n        this.backtestResult = response;\n      });\n    }\n  },\n  components: {\n    configBuilder,\n    result,\n    spinner\n  }\n}\n</script>\n"
  },
  {
    "path": "web/vue/src/components/backtester/result/chartWrapper.vue",
    "content": "<template lang='pug'>\n#chartWrapper(v-bind:class='{ clickable: !isClicked }')\n  .shield(v-on:click.prevent='click')\n  svg#chart(width='960', :height='height')\n</template>\n\n<script>\n\nimport chart from '../../../d3/chart4'\nimport { draw as drawMessage, clear as clearMessage } from '../../../d3/message'\n\nconst MIN_CANDLES = 4;\n\nexport default {\n  props: ['data', 'height'],\n\n  data: function() {\n    return {\n      isClicked: false\n    }\n  },\n\n  watch: {\n    data: function() { this.render() },\n  },\n\n  created: function() { setTimeout( this.render, 100) },\n  beforeDestroy: function() {\n    this.remove();\n  },\n\n  methods: {\n    click: function() {\n      this.isClicked = true;\n    },\n    render: function() {\n      this.remove();\n\n\n      if(_.size(this.data.candles) < MIN_CANDLES) {\n        drawMessage('Not enough data to spawn chart');\n      } else {\n        chart(this.data.candles, this.data.trades, this.height);\n      }\n    },\n    remove: function() {\n      d3.select('#chart').html('');\n    }\n  }\n}\n</script>\n\n<style>\n\n#chartWrapper.clickable {\n  position: relative;\n}\n\n#chartWrapper.clickable .shield {\n  cursor: zoom-in;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  background: grey;\n  opacity: 0.1;\n}\n\n#chart {\n  background-color: #eee;\n  width: 100%;\n}\n\n#chart circle {\n  clip-path: url(#clip);\n}\n\n#chart .zoom {\n  cursor: move;\n  fill: none;\n  pointer-events: all;\n}\n\n#chart .line {\n  fill: none;\n  stroke: steelblue;\n  stroke-width: 1.5px;\n  clip-path: url(#clip);\n}\n\n/*#chart .price.line {\n  stroke-width: 2.5px;\n}*/\n\n#chart circle.buy {\n  fill: #7FFF00;\n}\n\n#chart circle.sell {\n  fill: red;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/backtester/result/result.vue",
    "content": "<template lang='pug'>\n  div\n    .hr.contain\n    div.contain\n      h3 Backtest result\n    result-summary(:report='result.performanceReport')\n    .hr.contain\n    chart(:data='candles', height='500')\n    .hr.contain\n    roundtripTable(:roundtrips='result.roundtrips')\n</template>\n\n<script>\nimport resultSummary from './summary.vue'\nimport chart from './chartWrapper.vue'\nimport roundtripTable from './roundtripTable.vue'\n\nexport default {\n  props: ['result'],\n  data: () => {\n    return {}\n  },\n  methods: {},\n  components: {\n    roundtripTable,\n    resultSummary,\n    chart\n  },\n  computed: {\n    candles: function() {\n      return {\n        candles: this.result.stratCandles,\n        trades: this.result.trades\n      };\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/backtester/result/roundtripTable.vue",
    "content": "<template lang='pug'>\n  .contain.roundtrips\n    h2 Roundtrips\n    table(v-if='roundtrips.length')\n      thead\n        tr\n          th Entry at (UTC)\n          th Exit at (UTC)\n          th Exposure\n          th Entry balance\n          th Exit balance\n          th P&amp;L\n          th Profit\n        tr(v-for='rt in roundtrips')\n          td {{ fmt(rt.entryAt) }}\n          td {{ fmt(rt.exitAt) }}\n          td {{ diff(rt.duration) }}\n          td {{ round(rt.entryBalance) }}\n          td {{ round(rt.exitBalance) }}\n          template(v-if=\"Math.sign(rt.pnl)===-1\")\n            td.loss {{ Math.sign(rt.pnl)*rt.pnl.toFixed(2) }}\n            td.loss {{ rt.profit.toFixed(2) }}%\n          template(v-else)\n            td.profit {{ rt.pnl.toFixed(2) }}\n            td.profit {{ rt.profit.toFixed(2) }}%\n    div(v-if='!roundtrips.length')\n      p Not enough data to display\n</template>\n\n<script>\nimport _ from 'lodash'\n\nexport default {\n  props: ['roundtrips'],\n  data: () => {\n    return {}\n  },\n  methods: {\n    diff: n => moment.duration(n).humanize(),\n    humanizeDuration: (n) => window.humanizeDuration(n),\n    fmt: date => {\n\n      // roundtrips coming out of a backtest\n      // are unix timestamp, live roundtrips\n      // are date strings.\n      // TODO: normalize\n\n      let mom;\n\n      if(_.isNumber(date)) {\n        mom = moment.unix(date);\n      } else {\n        mom = moment(date).utc();\n      }\n\n      return mom.utc().format('YYYY-MM-DD HH:mm');\n    },\n    round: n => (+n).toFixed(3),\n  },\n}\n</script>\n\n<style>\n\n.roundtrips {\n  margin-top: 50px;\n  margin-bottom: 50px;\n}\n\n.roundtrips table {\n  width: 100%;\n}\n\n.roundtrips table th,\n.roundtrips table td {\n  border: 1px solid #c6cbd1;\n  padding: 8px 12px;\n}\n\n.roundtrips table td.loss {\n  color: red;\n  text-align: right;\n}\n.roundtrips table td.profit {\n  color: green;\n  text-align: right;\n}\n\n.roundtrips table tr:nth-child(2n) {\n  background-color: #f6f8fa;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/backtester/result/summary.vue",
    "content": "<template lang='pug'>\ndiv.contain\n\n  .grd-row.summary\n    .grd-row-col-3-6\n      table.p1\n        tr\n          th start time\n          td {{ report.startTime }}\n        tr\n          th end time\n          td {{ report.endTime }}\n        tr\n          th timespan\n          td {{ report.timespan }}\n        tr\n          th start price\n          td {{ round(report.startPrice) }} {{ report.currency }}\n        tr\n          th end price\n          td {{ round(report.endPrice) }} {{ report.currency }}\n        tr\n          th market\n          td {{ round(report.market) }}%\n\n    paperTradeSummary(:report='report')\n\n</template>\n\n<script>\n\nimport paperTradeSummary from '../../global/paperTradeSummary.vue'\n\nexport default {\n  props: ['report'],\n  components: {\n    paperTradeSummary\n  },\n  methods: {\n    round: n => (+n).toFixed(5)\n  },\n  computed: {\n    profitClass: function() {\n      if(this.report.relativeProfit > 0)\n        return 'profit'\n      else\n        return 'loss'\n    }\n  }\n}\n</script>\n\n<style>\n.summary td {\n  text-align: right;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/config/apiConfigBuilder.vue",
    "content": "<template lang='pug'>\n.grd.contain\n  h3 Add an API key\n  p Make sure that the API key has the permissions to create and cancel orders and view balances.\n  .grd-row\n    .grd-row-col-3-6.mx1\n      h3 Exchange\n      exchange-picker(v-on:exchange='updateExchange', only-tradable='true')\n    .grd-row-col-3-6.mx1\n      h3 Credentials\n      template(v-for='cred in requires')\n        label {{ cred }}\n        input(v-model='credentials[cred]')\n  .txt--center\n    a.w100--s.my1.btn--primary(href='#', v-on:click.prevent='upload') Add\n</template>\n\n<script>\n\nimport exchangePicker from '../global/configbuilder/exchangepicker.vue'\nimport _ from 'lodash'\nimport { post } from '../../tools/ajax';\n\nexport default {\n  data: () => {\n    return {\n      exchange: false,\n      credentials: {}\n    }\n  },\n  components: {\n    exchangePicker\n  },\n  computed: {\n    apiKeySets: function() {\n      return this.$store.state.apiKeys;\n    },\n    exchanges: function() {\n      return this.$store.state.exchanges;\n    },\n    requires: function() {\n      if(!this.exchanges)\n        return [];\n\n      if(!this.exchange)\n        return [];\n\n      return this.exchanges[this.exchange].requires;\n    },\n    config: function() {\n      let config = {\n        exchange: this.exchange,\n        values: this.credentials\n      };\n\n      return config;\n    }\n  },\n  watch: {\n    credentials: function() {\n      this.emitConfig();\n    }\n  },\n  methods: {\n    updateExchange: function(exchange) {\n      this.credentials = {};\n      this.exchange = exchange;\n      this.emitConfig();\n    },\n    emitConfig: function() {\n      this.$emit('config', this.config);\n    },\n    upload: function() {\n\n      let exchange = this.config.exchange;\n\n      if(\n        this.exchanges &&\n        this.apiKeySets.includes(exchange) &&\n        !confirm(`You already have API keys for ${exchange} defined, do you want to overwrite them?`)\n      )\n          return;\n\n      post('addApiKey', this.config, (error, response) => {\n        if(error)\n          return alert(error);\n\n        this.credentials = {};\n      });\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/config/config.vue",
    "content": "<template lang='pug'>\ndiv.contain\n  h2 Config\n  .hr\n  h3 Available API keys\n  p(v-if='!apiKeySets.length')\n    em You don't have any API keys yet.\n  ul\n    li(v-for='exchange in apiKeySets') {{ exchange }} (\n      a(href='#', v-on:click.prevent='removeApiKey(exchange)') remove\n      | )\n  a.btn--primary(href='#', v-if='!addApiToggle', v-on:click.prevent='openAddApi') Add an API key\n  template(v-if='addApiToggle')\n    .hr\n    apiConfigBuilder\n  .hr\n  \n</template>\n\n<script>\nimport apiConfigBuilder from './apiConfigBuilder.vue';\nimport { post } from '../../tools/ajax';\n\nexport default {\n  components: {\n    apiConfigBuilder\n  },\n  data: () => {\n    return {\n      addApiToggle: false,\n    }\n  },\n  methods: {\n    openAddApi: function() {\n      this.addApiToggle = true;\n    },\n    removeApiKey: function(exchange) {\n      if(!confirm('Are you sure you want to delete these API keys?'))\n        return;\n\n      post('removeApiKey', {exchange}, (error, response) => {\n        if(error)\n          return alert(error);\n      });\n    }\n  },\n  computed: {\n    apiKeySets: function() {\n      return this.$store.state.apiKeys\n    }\n  },\n  watch: {\n    apiKeySets: function() {\n      this.addApiToggle = false;\n    }\n  }\n}\n</script>"
  },
  {
    "path": "web/vue/src/components/data/data.vue",
    "content": "<template lang='pug'>\n  .contain\n    .text(v-html='intro')\n    .hr\n    h2 Available datasets\n    .txt--center.my2(v-if='datasetScanstate === \"idle\"')\n      a.w100--s.btn--primary.scan-btn(href='#', v-on:click.prevent='scan') Scan available data\n    .txt--center.my2(v-if='datasetScanstate === \"scanning\"')\n      spinner\n    .my2(v-if='datasetScanstate === \"scanned\"')\n      .bg--orange.p1.warning.my1(v-if='unscannableMakets.length')\n        p.clickable(v-if='!viewUnscannable', v-on:click.prevent='toggleUnscannable') Some markets were unscannable, click here for details.\n        template(v-if='viewUnscannable')\n          p Unable to find datasets in the following markets:\n          .mx2(v-for='market in unscannableMakets')\n            | - {{ market.exchange }}:{{ market.currency }}:{{ market.asset }}\n      template(v-if='datasets.length')\n        table.full.data\n          thead\n            tr\n              th exchange\n              th currency\n              th asset\n              th from\n              th to\n              th duration\n          tbody\n            tr(v-for='set in datasets')\n              td {{ set.exchange }}\n              td {{ set.currency }}\n              td {{ set.asset }}\n              td {{ fmt(set.from) }}\n              td {{ fmt(set.to) }}\n              td {{ humanizeDuration(set.to.diff(set.from)) }}\n      template(v-if='!datasets.length')\n        p It looks like you don't have any local data yet.\n    .my2\n      h2 Import more data\n      p.text You can easily import more market data directly from exchanges using the importer.\n      router-link.btn--primary(to='/data/importer') Go to the importer!\n</template>\n\n<script>\n\nimport spinner from '../global/blockSpinner.vue'\nimport marked from '../../tools/marked'\nimport dataset from '../global/mixins/dataset'\n// global moment\n// global humanizeDuration\n\nlet intro = marked(`\n\n## Local data\n\nGekko needs local market data in order to backtest strategies. The local\ndata can also be used in a warmup period when running a strategy against a\nlive market.\n\n`);\n\nexport default {\n  mixins: [ dataset ],\n  components: {\n    spinner\n  },\n  data: () => {\n    return {\n      intro,\n      viewUnscannable: false\n    }\n  },\n  methods: {\n    toggleUnscannable: function() { this.viewUnscannable = true },\n    humanizeDuration: (n) => window.humanizeDuration(n),\n    fmt: mom => mom.format('YYYY-MM-DD HH:mm'),\n  }\n}\n</script>\n\n<style>\n\n.clickable {\n  cursor: pointer;\n}\n\ntable.full {\n  width: 100%;\n}\n\ntable.full td {\n  padding: 0.5rem 0;\n}\n\ntable.full.data th {\n  text-align: left;\n  padding: 0.5rem 0;\n}\n\n.warning p {\n  margin: 0;\n  padding: 0;\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/data/import/importConfigBuilder.vue",
    "content": "<template lang='pug'>\n.grd.contain\n  .grd-row\n    .grd-row-col-3-6.mx1\n      h3 Market\n      market-picker(v-on:market='updateMarketConfig', only-importable='true')\n    .grd-row-col-3-6.mx1\n      range-creator(v-on:range='updateRange')\n</template>\n\n<script>\n\nimport marketPicker from '../../global/configbuilder/marketpicker.vue'\nimport rangeCreator from '../../global/configbuilder/rangecreator.vue'\nimport _ from 'lodash'\n\nexport default {\n  data: () => {\n    return {\n      market: {},\n      range: {}\n    }\n  },\n  components: {\n    marketPicker,\n    rangeCreator\n  },\n  computed: {\n    config: function() {\n\n      let config = {};\n      Object.assign(\n        config,\n        this.market,\n        {\n          importer: {\n            daterange: this.range\n          }\n        },\n        {\n          candleWriter: { enabled: true }\n        }\n      );\n\n      return config;\n    }\n  },\n  methods: {\n    updateMarketConfig: function(mc) {\n      this.market = mc;\n      this.emitConfig();\n    },\n    updateRange: function(range) {\n      this.range = range;\n      this.emitConfig();\n    },\n    emitConfig: function() {\n      this.$emit('config', this.config);\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/data/import/importer.vue",
    "content": "<template lang='pug'>\n  div.contain.my2\n    div.text(v-html='intro')\n    .hr\n    h3 Currently running imports\n    p(v-if='imports.length === 0') You currently don't have any imports running.\n    ul(v-if='imports.length')\n      li(v-for='_import in imports')\n        router-link(:to='\"/data/importer/import/\" + _import.id') {{ _import.watch.exchange }}:{{ _import.watch.currency }}/{{ _import.watch.asset }}\n\n    .hr\n    h3 Start a new import\n    import-config-builder(v-on:config='updateConfig')\n    .hr\n    .txt--center\n      a.w100--s.my1.btn--primary(href='#', v-on:click.prevent='run') Import\n</template>\n\n<script>\n\nimport { post } from '../../../tools/ajax'\nimport spinner from '../../global/blockSpinner.vue'\nimport importConfigBuilder from './importConfigBuilder.vue'\n\nimport marked from '../../../tools/marked'\n\nlet intro = marked(`\n\n## Import data\n\nThe importer can download historical market data directly from the exchange.\n\n`)\n\nexport default {\n  components: {\n    importConfigBuilder,\n    spinner\n  },\n  data: () => {\n    return {\n      intro,\n      config: {}\n    }\n  },\n  computed: {\n    imports: function() {\n      return this.$store.state.imports\n    }\n  },\n  methods: {\n    daysApart: function(range) {\n      let to = moment(range.to);\n      let from = moment(range.from);\n\n      return to.diff(from, 'days');\n    },\n    updateConfig: function(config) {\n      this.config = config;\n    },\n    run: function() {\n      let daysApart = this.daysApart(this.config.importer.daterange);\n\n      if(daysApart < 1)\n        return alert('You can only import at least one day of data..')\n\n      let exchange = this.$store.state.exchanges[this.config.watch.exchange];\n      if (\"exchangeMaxHistoryAge\" in exchange) {\n        if (moment(this.config.importer.daterange.from) < moment().subtract(exchange.exchangeMaxHistoryAge, \"days\")) {\n          return alert('Your date from is too old for ' + this.config.watch.exchange + '. It supports only the last ' + exchange.exchangeMaxHistoryAge + ' days..');\n        }\n      }\n\n      post('import', this.config, (error, response) => {\n        if(error)\n          return alert(error);\n\n        this.$store.commit('addImport', response);\n\n        this.$router.push({\n          path: `/data/importer/import/${response.id}`,\n        })\n      });\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/data/import/single.vue",
    "content": "<template lang='pug'>\n  div.contain.my2\n    div(v-if='data && !data.done')\n      h2 Importing data..\n      .grd\n        .grd-row\n          .grd-row-col-2-6 <strong>Market:</strong>\n          .grd-row-col-4-6 {{ data.watch.exchange }}\n        .grd-row\n          .grd-row-col-2-6 <strong>Currency/Asset:</strong>\n          .grd-row-col-4-6 {{ data.watch.currency }}/{{ data.watch.asset }}\n\n      .grd\n        .grd-row\n          .grd-row-col-2-6 <strong>From:</strong>\n          .grd-row-col-4-6 {{ fmt(from) }}\n        .grd-row\n          .grd-row-col-2-6 <strong>To:</strong>\n          .grd-row-col-4-6 {{ fmt(to) }}\n        .grd-row(v-if='initialized')\n          .grd-row-col-2-6 <strong>Imported data until:</strong>\n          .grd-row-col-4-6 {{ fmt(latest) }}\n        .grd-row(v-if='initialized')\n          .grd-row-col-2-6 <strong>Remaining:</strong>\n          .grd-row-col-4-6 {{ fromEnd }}\n      spinner(v-if='!initialized')\n      .contain(v-if='initialized')\n        progressBar(:progress='progress')\n      p \n        em (you don't have to wait until the import is done,\n          | you can already start \n          router-link(to='/backtest') backtesting\n          | ).\n    div(v-if='data && data.done').txt--center\n      h2 Import done\n      p \n        | Go and \n        router-link(to='/backtest') backtest\n        |  with your new data!\n    div(v-if='!data').txt--center\n      h2 ERROR: Unknown import\n      p \n        I don't know this import..\n</template>\n\n<script>\n\nimport _ from 'lodash';\nimport progressBar from '../../global/progressBar.vue'\nimport spinner from '../../global/blockSpinner.vue'\n\nexport default {\n  components: {\n    progressBar,\n    spinner\n  },\n  computed: {\n    data: function() {\n      return _.find(\n        this.$store.state.imports,\n        { id: this.$route.params.id }\n      );\n    },\n    initialized: function() {\n      if(this.data && this.latest.isValid())\n        return true\n    },\n    latest: function() {\n      if(this.data)\n        return this.mom(this.data.latest);\n    },\n    fromEndMs: function() {\n      if(this.data)\n        return this.to.diff(this.latest);\n    },\n    fromEnd: function() {\n      if(!this.latest)\n        return 'LOADING'\n\n      return humanizeDuration(this.fromEndMs);\n    },\n    from: function() {\n      if(this.data)\n        return this.mom(this.data.from)\n    },\n    to: function() {\n      if(this.data)\n        return this.mom(this.data.to)\n    },\n    timespan: function() {\n      if(this.data)\n        return this.to.diff(this.from)\n    },\n    progress: function() {\n      if(!this.data)\n        return;\n\n      const current = this.timespan - this.fromEndMs;\n      return 100 * current / this.timespan;\n    }\n  },\n  methods: {\n    fmt: mom => { return mom.format('YYYY-MM-DD HH:mm:ss') },\n    mom: str => moment.utc(str)\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/gekko/gekkoConfigBuilder.vue",
    "content": "<template lang='pug'>\n.grd.contain\n  .grd-row\n    .grd-row-col-3-6.mx1\n      h3 Market\n      market-picker(v-on:market='updateMarketConfig', :only-tradable='isTradebot')\n    .grd-row-col-3-6.mx1\n      type-picker(v-on:type='updateType')\n  template(v-if='type !== \"market watcher\"')\n    .hr\n    strat-picker.contain.my2(v-on:stratConfig='updateStrat')\n    .hr(v-if='type === \"paper trader\"')\n    paper-trader(v-on:settings='updatePaperTrader', v-if='type === \"paper trader\"')\n</template>\n\n<script>\n\nimport marketPicker from '../global/configbuilder/marketpicker.vue'\nimport typePicker from '../global/configbuilder/typepicker.vue'\nimport stratPicker from '../global/configbuilder/stratpicker.vue'\nimport paperTrader from '../global/configbuilder/papertrader.vue'\nimport { get } from '../../tools/ajax'\nimport _ from 'lodash'\n\nexport default {\n\n  created: function() {\n    get('configPart/candleWriter', (error, response) => {\n      this.candleWriter = toml.parse(response.part);\n    });\n    get('configPart/performanceAnalyzer', (error, response) => {\n      this.performanceAnalyzer = toml.parse(response.part);\n      this.performanceAnalyzer.enabled = true;\n    });\n  },\n  data: () => {\n    return {\n      market: {},\n      range: {},\n      type: '',\n      strat: {},\n      paperTrader: {},\n      candleWriter: {},\n      performanceAnalyzer: {}\n    }\n  },\n  components: {\n    marketPicker,\n    typePicker,\n    stratPicker,\n    paperTrader\n  },\n  computed: {\n    isTradebot: function() {\n      return this.type === 'tradebot';\n    },\n    config: function() {\n      let config = {};\n      Object.assign(\n        config,\n        this.market,\n        this.strat,\n        { paperTrader: this.paperTrader },\n        { candleWriter: this.candleWriter },\n        { type: this.type },\n        { performanceAnalyzer: this.performanceAnalyzer }\n      );\n\n      if(this.isTradebot) {\n        delete config.paperTrader;\n        config.trader = { enabled: true }\n      }\n\n      config.valid = this.validConfig(config);\n\n      return config;\n    }\n  },\n  methods: {\n    validConfig: config => {\n      if(config.type === 'market watcher')\n        return true;\n\n      if(!config.tradingAdvisor)\n        return false;\n      if(_.isNaN(config.tradingAdvisor.candleSize))\n        return false;\n      else if(config.tradingAdvisor.candleSize == 0)\n        return false;\n\n      let strat = config.tradingAdvisor.method;\n      if(_.isEmpty(config[ strat ]))\n        return false;\n\n      return true;\n    },\n    updateMarketConfig: function(mc) {\n      this.market = mc;\n      this.emitConfig();\n    },\n    updateType: function(type) {\n      this.type = type;\n      this.emitConfig();\n    },\n    updateStrat: function(strat) {\n      this.strat = strat;\n      this.emitConfig();\n    },\n    updatePaperTrader: function(pt) {\n      this.paperTrader = pt;\n      this.paperTrader.enabled = true;\n      this.emitConfig();\n    },\n\n    emitConfig: function() {\n      this.$emit('config', this.config); \n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/gekko/list.vue",
    "content": "<template lang='pug'>\n  .contain.py2\n    h3 Market watchers\n    .text(v-if='!watchers.length')\n      p You don't have any market watchers.\n    table.full.clickable(v-if='watchers.length')\n      thead\n        tr\n          th exchange\n          th currency\n          th asset\n          th status\n          th started at\n          th last update\n          th duration\n      tbody\n        tr.clickable(v-for='gekko in watchers', v-on:click='$router.push({path: `/live-gekkos/${gekko.id}`})')\n          td {{ gekko.config.watch.exchange }}\n          td {{ gekko.config.watch.currency }}\n          td {{ gekko.config.watch.asset }}\n          td {{ status(gekko) }}\n          td\n            template(v-if='gekko.events.initial.candle') {{ fmt(gekko.events.initial.candle.start) }}\n          td\n            template(v-if='gekko.events.latest.candle') {{ fmt(gekko.events.latest.candle.start) }}\n          td\n            template(v-if='gekko.events.initial.candle && gekko.events.latest.candle') {{ timespan(gekko.events.latest.candle.start, gekko.events.initial.candle.start) }}\n    h3 Strat runners\n    .text(v-if='!stratrunners.length')\n      p You don't have any stratrunners.\n    table.full(v-if='stratrunners.length')\n      thead\n        tr\n          th exchange\n          th currency\n          th asset\n          th status\n          th duration\n          th strategy\n          th PnL\n          th type\n          th trades\n      tbody\n        tr.clickable(v-for='gekko in stratrunners', v-on:click='$router.push({path: `/live-gekkos/${gekko.id}`})')\n          td {{ gekko.config.watch.exchange }}\n          td {{ gekko.config.watch.currency }}\n          td {{ gekko.config.watch.asset }}\n          td {{ status(gekko) }}\n          td\n            template(v-if='gekko.events.initial.candle && gekko.events.latest.candle') {{ timespan(gekko.events.latest.candle.start, gekko.events.initial.candle.start) }}\n          td {{ gekko.config.tradingAdvisor.method }}\n          td\n            template(v-if='!report(gekko)') 0\n            template(v-if='report(gekko)') {{ round(report(gekko).profit) }} {{ report(gekko).currency }}\n          td {{ gekko.logType }}\n          td\n            template(v-if='!gekko.events.tradeCompleted') 0\n            template(v-if='gekko.events.tradeCompleted') {{ gekko.events.tradeCompleted.length }}\n    .hr\n    h2 Start a new live Gekko\n    router-link.btn--primary(to='/live-gekkos/new') Start a new live Gekko!\n</template>\n\n<script>\n// global moment\n// global humanizeDuration\n\nexport default {\n  created: function() {\n    this.timer = setInterval(() => {\n      this.now = moment();\n    }, 1000)\n  },\n  destroyed: function() {\n    clearTimeout(this.timer);\n  },\n  data: () => {\n    return {\n      timer: false,\n      now: moment()\n    }\n  },\n  computed: {\n    stratrunners: function() {\n      return _.values(this.$store.state.gekkos)\n        .concat(_.values(this.$store.state.archivedGekkos))\n          .filter(g => {\n            if(g.logType === 'papertrader')\n              return true;\n\n            if(g.logType === 'tradebot')\n              return true;\n\n            return false;\n          })\n    },\n    watchers: function() {\n      return _.values(this.$store.state.gekkos)\n        .concat(_.values(this.$store.state.archivedGekkos))\n        .filter(g => g.logType === 'watcher')\n    }\n  },\n  methods: {\n    humanizeDuration: (n) => window.humanizeDuration(n),\n    moment: mom => moment.utc(mom),\n    fmt: mom => moment.utc(mom).format('YYYY-MM-DD HH:mm'),\n    round: n => (+n).toFixed(3),\n    timespan: function(a, b) {\n      return this.humanizeDuration(this.moment(a).diff(this.moment(b)))\n    },\n    status: state => {\n      if(state.errored)\n        return 'errored';\n      if(state.stopped)\n        return 'stopped';\n      if(state.active)\n        return 'running';\n\n      console.log('unknown state:', state);\n    },\n    report: state => {\n      return _.get(state, 'events.latest.performanceReport');\n    }\n  }\n}\n</script>\n\n<style>\ntable.clickable {\n  border-collapse: separate;\n}\n\ntr.clickable td:nth-child(1) {\n  padding-left: 5px;\n}\n\ntr.clickable {\n  cursor: pointer;\n}\ntr.clickable:hover {\n  background: rgba(216,216,216,.99);\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/gekko/new.vue",
    "content": "<template lang='pug'>\n  div.contain.my2\n    h3 Start a new gekko\n    gekko-config-builder(v-on:config='updateConfig')\n    .hr\n    .txt--center(v-if='config.valid')\n      a.w100--s.my1.btn--primary(href='#', v-on:click.prevent='start', v-if=\"!pendingStratrunner\") Start\n      spinner(v-if='pendingStratrunner')\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport Vue from 'vue'\nimport { post } from '../../tools/ajax'\nimport gekkoConfigBuilder from './gekkoConfigBuilder.vue'\nimport spinner from '../global/blockSpinner.vue'\n\nexport default {\n  components: {\n    gekkoConfigBuilder,\n    spinner\n  },\n  data: () => {\n    return {\n      pendingStratrunner: false,\n      config: {}\n    }\n  },\n  computed: {\n    gekkos: function() {\n      return this.$store.state.gekkos;\n    },\n    watchConfig: function() {\n      let raw = _.pick(this.config, 'watch', 'candleWriter');\n      let watchConfig = Vue.util.extend({}, raw);\n      watchConfig.type = 'market watcher';\n      watchConfig.mode = 'realtime';\n      return watchConfig;\n    },\n    requiredHistoricalData: function() {\n      if(!this.config.tradingAdvisor || !this.config.valid)\n        return;\n\n      let stratSettings = this.config.tradingAdvisor;\n      return stratSettings.candleSize * stratSettings.historySize;\n    },\n    gekkoConfig: function() {\n      var startAt;\n\n      if(!this.existingMarketWatcher)\n        return;\n\n      if(!this.requiredHistoricalData)\n        startAt = moment().utc().startOf('minute').format();\n      else {\n        // TODO: figure out whether we can stitch data\n        // without looking at the existing watcher\n        const optimal = moment().utc().startOf('minute')\n          .subtract(this.requiredHistoricalData, 'minutes')\n          .unix();\n\n        const available = moment\n          .utc(this.existingMarketWatcher.events.initial.candle.start)\n          .unix();\n\n        startAt = moment.unix(Math.max(optimal, available)).utc().format();\n      }\n\n      const gekkoConfig = Vue.util.extend({\n        market: {\n          type: 'leech',\n          from: startAt\n        },\n        mode: 'realtime'\n      }, this.config);\n      return gekkoConfig;\n    },\n    existingMarketWatcher: function() {\n      const market = Vue.util.extend({}, this.watchConfig.watch);\n      return _.find(this.gekkos, {config: {watch: market}});\n    },\n    exchange: function() {\n      return this.watchConfig.watch.exchange;\n    },\n    existingTradebot: function() {\n      return _.find(\n        this.gekkos,\n        g => {\n          if(g.logType === 'tradebot' && g.config.watch.exchange === this.exchange) {\n            return true;\n          }\n\n          return false;\n        }\n      );\n    },\n    availableApiKeys: function() {\n      return this.$store.state.apiKeys;\n    }\n  },\n  watch: {\n    // start the stratrunner\n    existingMarketWatcher: function(val, prev) {\n      if(!this.pendingStratrunner)\n        return;\n\n      const gekko = this.existingMarketWatcher;\n\n      if(gekko.events.latest.candle) {\n        this.pendingStratrunner = false;\n\n        this.startGekko((err, resp) => {\n          this.$router.push({\n            path: `/live-gekkos/${resp.id}`\n          });\n        });\n      }\n    }\n  },\n  methods: {\n    updateConfig: function(config) {\n      this.config = config;\n    },\n    start: function() {\n\n      // if the user starts a tradebot we do some\n      // checks first.\n      if(this.config.type === 'tradebot') {\n        if(this.existingTradebot) {\n          let str = 'You already have a tradebot running on this exchange';\n          str += ', you can only run one tradebot per exchange.';\n          return alert(str);\n        }\n\n        if(!this.availableApiKeys.includes(this.exchange))\n          return alert('Please first configure API keys for this exchange in the config page.')\n      }\n\n      // internally a live gekko consists of two parts:\n      //\n      // - a market watcher\n      // - a live gekko (strat runner + (paper) trader)\n      //\n      // however if the user selected type \"market watcher\"\n      // the second part won't be created\n      if(this.config.type === 'market watcher') {\n\n        // check if the specified market is already being watched\n        if(this.existingMarketWatcher) {\n          alert('This market is already being watched, redirecting you now...');\n          this.$router.push({\n            path: `/live-gekkos/${this.existingMarketWatcher.id}`\n          });\n        } else {\n          this.startWatcher((error, resp) => {\n            this.$router.push({\n              path: `/live-gekkos/${resp.id}`\n            });\n          });\n        }\n\n      } else {\n\n        if(this.existingMarketWatcher) {\n          // the specified market is already being watched,\n          // just start a gekko!\n          this.startGekko(this.routeToGekko);\n          \n        } else {\n          // the specified market is not yet being watched,\n          // we need to create a watcher\n          this.startWatcher((err, resp) => {\n            this.pendingStratrunner = resp.id;\n            // now we just wait for the watcher to be properly initialized\n            // (see the `watch.existingMarketWatcher` method)\n          });\n        }\n      }\n    },\n    routeToGekko: function(err, resp) {\n      if(err || resp.error)\n        return console.error(err, resp.error);\n\n      this.$router.push({\n        path: `/live-gekkos/${resp.id}`\n      });\n    },\n    startWatcher: function(next) {\n      post('startGekko', this.watchConfig, next);\n    },\n    startGekko: function(next) {\n      post('startGekko', this.gekkoConfig, next);\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/gekko/singleGekko.vue",
    "content": "<template lang='pug'>\n  div.my2\n    .contain(v-if='!data')\n      h1 Unknown Gekko instance\n      p Gekko doesn't know what gekko this is...\n    div(v-if='data')\n      h2.contain Gekko {{ type }}\n      div(v-if='isArchived', class='contain brdr--mid-gray p1 bg--orange')\n        | This is an archived Gekko, it is currently not running anymore.\n      div(v-if='data.errorMessage', class='contain brdr--mid-gray p1 bg--orange')\n        | This is Gekko crashed with the following error: {{ data.errorMessage }}\n      .grd.contain\n        .grd-row\n          .grd-row-col-3-6\n            h3 Market\n            .grd-row\n              .grd-row-col-3-6 Exchange\n              .grd-row-col-3-6 {{ config.watch.exchange }}\n            .grd-row\n              .grd-row-col-3-6 Currency\n              .grd-row-col-3-6 {{ config.watch.currency }}\n            .grd-row\n              .grd-row-col-3-6 Asset\n              .grd-row-col-3-6 {{ config.watch.asset }}\n            .grd-row\n              .grd-row-col-3-6 Type\n              .grd-row-col-3-6 {{ type }}\n          .grd-row-col-3-6\n            h3 Runtime\n            spinner(v-if='isLoading')\n            template(v-if='!isLoading')\n              .grd-row(v-if='initialEvents.candle')\n                .grd-row-col-2-6 Watching since\n                .grd-row-col-4-6 {{ fmt(initialEvents.candle.start) }}\n              .grd-row(v-if='latestEvents.candle')\n                .grd-row-col-2-6 Received data until\n                .grd-row-col-4-6 {{ fmt(latestEvents.candle.start) }}\n              .grd-row(v-if='latestEvents.candle')\n                .grd-row-col-2-6 Data spanning\n                .grd-row-col-4-6 {{ humanizeDuration(moment(latestEvents.candle.start).diff(moment(initialEvents.candle.start))) }}\n              template(v-if='isStratrunner')\n                .grd-row\n                  .grd-row-col-2-6 Amount of trades\n                  .grd-row-col-4-6 {{ trades.length }}\n                .grd-row\n                  .grd-row-col-2-6 Candle size\n                  .grd-row-col-4-6 {{ config.tradingAdvisor.candleSize }}\n                .grd-row\n                  .grd-row-col-2-6 History size\n                  .grd-row-col-4-6 {{ config.tradingAdvisor.historySize }}\n        div(v-if='warmupRemaining', class='contain brdr--mid-gray p1 bg--orange')\n          | This stratrunner is still warming up for the next \n          i {{ warmupRemaining.replace(',', ' and ') }}\n          | , it will not trade until it is warmed up.\n        .grd-row(v-if='isStratrunner')\n          .grd-row-col-3-6\n            h3 Strategy\n            .grd-row\n              .grd-row-col-3-6 Name\n              .grd-row-col-3-6\n                strong {{ stratName }}\n            | Parameters\n            pre {{ stratParams }}\n          .grd-row-col-3-6\n            h3 Profit report\n            template(v-if='!report')\n              p\n                em(v-if='isArchived') This Gekko never executed a trade..\n                em(v-if='!isArchived') Waiting for at least one trade..\n            template(v-if='report')\n              .grd-row\n                .grd-row-col-3-6 Start balance\n                .grd-row-col-3-6 {{ round(report.startBalance) }}\n              .grd-row\n                .grd-row-col-3-6 Current balance\n                .grd-row-col-3-6 {{ round(report.balance) }}\n              .grd-row\n                .grd-row-col-3-6 Market\n                .grd-row-col-3-6 {{round(report.market / 100 * report.startPrice)}} {{ config.watch.currency }} ({{ round(report.market) }} %)\n              .grd-row\n                .grd-row-col-3-6 Profit\n                .grd-row-col-3-6 {{ round(report.profit) }} {{ config.watch.currency }} ({{ round(report.relativeProfit) }} %)\n              .grd-row\n                .grd-row-col-3-6 Alpha\n                .grd-row-col-3-6 {{ round(report.alpha) }} {{ config.watch.currency }}\n        p(v-if='isStratrunner && !watcher && !isArchived') WARNING: stale gekko, not attached to a watcher, please report \n          a(href='https://github.com/askmike/gekko/issues') here\n          | .\n        p(v-if='!isArchived')\n          a(v-on:click='stopGekko', class='w100--s my1 btn--red') Stop Gekko\n        p(v-if='isArchived')\n          a(v-on:click='deleteGekko', class='w100--s my1 btn--red') Delete Gekko\n        p(v-if='isStratrunner && watcher && !isArchived')\n          em This gekko gets market data from \n            router-link(:to='\"/live-gekkos/\" + watcher.id') this market watcher\n          | .\n      template(v-if='!isLoading')\n        h3.contain Market graph\n        spinner(v-if='candleFetch === \"fetching\"')\n        template(v-if='candleFetch === \"fetched\"')\n          chart(:data='chartData', :height='300')\n        roundtrips(v-if='isStratrunner', :roundtrips='roundtrips')\n</template>\n\n<script>\n\nimport Vue from 'vue'\nimport _ from 'lodash'\n\nimport { post } from '../../tools/ajax'\nimport spinner from '../global/blockSpinner.vue'\nimport chart from '../backtester/result/chartWrapper.vue'\nimport roundtrips from '../backtester/result/roundtripTable.vue'\nimport paperTradeSummary from '../global/paperTradeSummary.vue'\n// global moment\n\nexport default {\n  created: function() {\n    if(!this.isLoading)\n      this.getCandles();\n  },\n  components: {\n    spinner,\n    chart,\n    paperTradeSummary,\n    roundtrips\n  },\n  data: () => {\n    return {\n      candleFetch: 'idle',\n      candles: false\n    }\n  },\n  computed: {\n    id: function() {\n      return this.$route.params.id;\n    },\n    gekkos: function() {\n      return this.$store.state.gekkos;\n    },\n    archivedGekkos: function() {\n      return this.$store.state.archivedGekkos;\n    },\n    data: function() {\n      if(!this.gekkos)\n        return false;\n      if(_.has(this.gekkos, this.id))\n        return this.gekkos[this.id];\n      if(_.has(this.archivedGekkos, this.id))\n        return this.archivedGekkos[this.id];\n\n      return false;\n    },\n    config: function() {\n      return _.get(this, 'data.config');\n    },\n    latestEvents: function() {\n      return _.get(this, 'data.events.latest');\n    },\n    initialEvents: function() {\n      return _.get(this, 'data.events.initial');\n    },\n    trades: function() {\n      return _.get(this, 'data.events.tradeCompleted') || [];\n    },\n    roundtrips: function() {\n      return _.get(this, 'data.events.roundtrip') || [];\n    },\n    isLive: function() {\n      return _.has(this.gekkos, this.id);\n    },\n    type: function() {\n      return this.data.logType;\n    },\n    isStratrunner: function() {\n      return this.type !== 'watcher';\n    },\n    isArchived: function() {\n      return this.data.stopped;\n    },\n    warmupRemaining: function() {\n      if(!this.isStratrunner) {\n        return false;\n      }\n\n      if(this.isArchived) {\n        return false;\n      }\n\n      if(this.initialEvents.stratWarmupCompleted) {\n        return false;\n      }\n\n      if(!this.initialEvents.candle) {\n        return false;\n      }\n\n      const historySize = _.get(this.config, 'tradingAdvisor.historySize');\n\n      if(!historySize) {\n        return false;\n      }\n\n      const warmupTime = _.get(this.config, 'tradingAdvisor.candleSize') * historySize;\n\n      return humanizeDuration(\n        moment(this.initialEvents.candle.start).add(warmupTime, 'm').diff(moment()),\n        { largest: 2 }\n      );\n    },\n    chartData: function() {\n      return {\n        candles: this.candles,\n        trades: this.trades\n      }\n    },\n    report: function() {\n      return _.get(this.latestEvents, 'performanceReport');\n    },\n    stratName: function() {\n      if(this.data)\n        return this.data.config.tradingAdvisor.method;\n    },\n    stratParams: function() {\n      if(!this.data)\n        return 'Loading...';\n\n      let stratParams = Vue.util.extend({}, this.data.config[this.stratName]);\n      delete stratParams.__empty;\n\n      if(_.isEmpty(stratParams))\n        return 'No parameters'\n\n      return JSON.stringify(stratParams, null, 4);\n    },\n    isLoading: function() {\n      if(!this.data)\n        return true;\n      if(!_.get(this.data, 'events.initial.candle'))\n        return true;\n      if(!_.get(this.data, 'events.latest.candle'))\n        return true;\n\n      return false;\n    },\n    watcher: function() {\n      if(!this.isStratrunner) {\n        return false;\n      }\n\n      let watch = Vue.util.extend({}, this.data.config.watch);\n      return _.find(this.gekkos, g => {\n        if(g.id === this.id)\n          return false;\n\n        return _.isEqual(watch, g.config.watch);\n      });\n    },\n    hasLeechers: function() {\n      if(this.isStratrunner) {\n        return false;\n      }\n\n      let watch = Vue.util.extend({}, this.data.config.watch);\n\n      return _.find(this.gekkos, g => {\n        if(g.id === this.id)\n          return false;\n\n        return _.isEqual(watch, g.config.watch);\n      });\n    }\n  },\n  watch: {\n    'data.events.latest.candle.start': function() {\n      setTimeout(this.getCandles, _.random(100, 2000));\n    }\n  },\n  methods: {\n    round: n => (+n).toFixed(5),\n    humanizeDuration: (n, x) => window.humanizeDuration(n, x),\n    moment: mom => moment.utc(mom),\n    fmt: mom => moment.utc(mom).format('YYYY-MM-DD HH:mm'),\n    getCandles: function() {\n      if(this.isLoading) {\n        return;\n      }\n\n      if(this.candleFetch === 'fetching') {\n        return;\n      }\n\n      this.candleFetch = 'fetching';\n\n      let to = this.data.events.latest.candle.start;\n      let from = this.data.events.initial.candle.start;\n      let candleSize = 1;\n\n      if(this.type !== 'watcher') {\n        candleSize = this.data.config.tradingAdvisor.candleSize;\n      }\n\n      let config = {\n        watch: this.data.config.watch,\n        daterange: {\n          to, from\n        },\n        candleSize\n      };\n\n      // We timeout because of 2 reasons:\n      // - In case we get a batch of candles we only fetch once\n      // - This way we give the db (mostly sqlite) some time to write\n      //   the result before we query it.\n      setTimeout(() => {\n        post('getCandles', config, (err, res) => {\n          this.candleFetch = 'fetched';\n          if(!res || res.error || !_.isArray(res))\n            return console.log(res);\n\n          this.candles = res.map(c => {\n            c.start = moment.unix(c.start).utc().format();\n            return c;\n          });\n        })\n      }, _.random(150, 2500));\n    },\n    stopGekko: function() {\n      if(this.hasLeechers) {\n        return alert('This Gekko is fetching market data for multiple stratrunners, stop these first.');\n      }\n\n      if(!confirm('Are you sure you want to stop this Gekko?')) {\n        return;\n      }\n\n      post('stopGekko', { id: this.data.id }, (err, res) => {\n        console.log('stopped gekko');\n      });\n    },\n    deleteGekko: function() {\n      if(!this.isArchived) {\n        return alert('This Gekko is still running, stop it first!');\n      }\n\n      if(!confirm('Are you sure you want to delete this Gekko?')) {\n        return;\n      }\n\n      post('deleteGekko', { id: this.data.id }, (err, res) => {\n        this.$router.push({\n          path: `/live-gekkos/`\n        });\n      });\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/gekko/singleWatcher.vue",
    "content": "<template lang='pug'>\n  div.my2\n    .contain(v-if='!data')\n      h1 Unknown Watcher\n      p Gekko doesn't know what whatcher this is...\n    div(v-if='data')\n      h2.contain Market Watcher\n      .grd.contain\n        h3 Market\n        .grd-row\n          .grd-row-col-2-6 Exchange\n          .grd-row-col-4-6 {{ data.watch.exchange }}\n        .grd-row\n          .grd-row-col-2-6 Currency\n          .grd-row-col-4-6 {{ data.watch.currency }}\n        .grd-row\n          .grd-row-col-2-6 Asset\n          .grd-row-col-4-6 {{ data.watch.asset }}\n        h3 Statistics\n        spinner(v-if='isLoading')\n        template(v-if='!isLoading')\n          .grd-row(v-if='data.firstCandle')\n            .grd-row-col-2-6 Watching since\n            .grd-row-col-4-6 {{ fmt(data.firstCandle.start) }}\n          .grd-row(v-if='data.lastCandle')\n            .grd-row-col-2-6 Received data until\n            .grd-row-col-4-6 {{ fmt(data.lastCandle.start) }}\n          .grd-row(v-if='data.lastCandle && data.firstCandle')\n            .grd-row-col-2-6 Data spanning\n            .grd-row-col-4-6 {{ humanizeDuration(moment(data.lastCandle.start).diff(moment(data.firstCandle.start))) }}\n      template(v-if='!isLoading')\n        h3.contain Market graph\n        spinner(v-if='candleFetch === \"fetching\"')\n        template(v-if='candles.length')\n          chart(:data='chartData', :height='500')\n</template>\n\n<script>\n\nimport { post } from '../../tools/ajax'\nimport _ from 'lodash'\nimport spinner from '../global/blockSpinner.vue'\nimport Vue from 'vue'\nimport chart from '../backtester/result/chartWrapper.vue'\n// global moment\n\nexport default {\n  created: function() {\n    if(!this.isLoading)\n      this.getCandles();\n  },\n  components: {\n    spinner,\n    chart\n  },\n  data: () => {\n    return {\n      candleFetch: 'idle',\n      candles: []\n    }\n  },\n  computed: {\n    watchers: function() {\n      return this.$store.state.watchers;\n    },\n    data: function() {\n      return _.find(this.watchers, {id: this.$route.params.id});\n    },\n    chartData: function() {\n      return {\n        candles: this.candles,\n        trades: []\n      }\n    },\n    isLoading: function() {\n      if(!this.data)\n        return true;\n      if(!_.isObject(this.data.firstCandle))\n        return true;\n      if(!_.isObject(this.data.lastCandle))\n        return true;\n\n      return false;\n    },\n  },\n  watch: {\n    'data.lastCandle.start': function() {\n      this.candleFetch = 'dirty';\n    },\n    data: function(val, prev) {\n      let complete = val && val.firstCandle && val.lastCandle;\n\n      if(!complete)\n        return;\n\n      if(this.candleFetch !== 'fetched' )\n        this.getCandles();\n    }\n  },\n  methods: {\n    humanizeDuration: (n) => window.humanizeDuration(n),\n    moment: mom => moment.utc(mom),\n    fmt: mom => moment.utc(mom).format('YYYY-MM-DD HH:mm'),\n    getCandles: function() {\n\n      this.candleFetch = 'fetching';\n\n      // up unto we have data\n      let to = moment.utc(\n        this.data.lastCandle.start\n      ).unix();\n\n      // max 7 days of data\n      let from = Math.max(\n        moment.utc(this.data.firstCandle.start).unix(),\n        moment.utc(to).subtract(7, 'days').unix()\n      );\n\n      // TODO...\n      const diff = to - from;\n      let candleSize = 60;\n      if(diff < 60 * 60 * 24) // a day\n        if(diff < 60 * 60 * 12) // 3 hours\n          candleSize = 1;\n        else\n          candleSize = 5;\n\n      from = moment.unix(from).utc().format();\n      to = moment.unix(to).utc().format();\n\n      let config = {\n          watch: this.data.watch,\n          daterange: {\n            to, from\n          },\n          // hourly candles\n          candleSize\n        };\n\n      post('getCandles', config, (err, res) => {\n        this.candleFetch = 'fetched';\n        this.candles = res.map(c => {\n          c.start = moment.unix(c.start).utc().format();\n          return c;\n        });\n      })\n    }\n  }\n}\n</script>\n\n<style>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/blockSpinner.vue",
    "content": "// http://tobiasahlin.com/spinkit/\n\n<template lang='pug'>\n.spinner\n  .rect1\n  .rect2\n  .rect3\n  .rect4\n</template>\n\n<script>\n\nexport default {}\n</script>\n\n<style>\n.spinner {\n  margin: 20px auto 100px auto;\n  width: 50px;\n  height: 40px;\n  text-align: center;\n  font-size: 10px;\n}\n\n.spinner > div {\n  background-color: #333;\n  height: 100%;\n  width: 6px;\n  display: inline-block;\n  margin-right: 4px;\n  -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;\n  animation: sk-stretchdelay 1.2s infinite ease-in-out;\n}\n\n.spinner .rect2 {\n  -webkit-animation-delay: -1.1s;\n  animation-delay: -1.1s;\n}\n\n.spinner .rect3 {\n  -webkit-animation-delay: -1.0s;\n  animation-delay: -1.0s;\n}\n\n.spinner .rect4 {\n  -webkit-animation-delay: -0.9s;\n  animation-delay: -0.9s;\n}\n\n.spinner .rect5 {\n  -webkit-animation-delay: -0.8s;\n  animation-delay: -0.8s;\n}\n\n@-webkit-keyframes sk-stretchdelay {\n  0%, 40%, 100% { -webkit-transform: scaleY(0.4) }  \n  20% { -webkit-transform: scaleY(1.0) }\n}\n\n@keyframes sk-stretchdelay {\n  0%, 40%, 100% { \n    transform: scaleY(0.4);\n    -webkit-transform: scaleY(0.4);\n  }  20% { \n    transform: scaleY(1.0);\n    -webkit-transform: scaleY(1.0);\n  }\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/datasetpicker.vue",
    "content": "<template lang='pug'>\ndiv\n  h3 Select a dataset\n  .txt--center.my2(v-if='datasetScanstate === \"idle\"')\n    a.w100--s.btn--primary.scan-btn(href='#', v-on:click.prevent='scan') Scan available data\n  .txt--center.my2(v-if='datasetScanstate === \"scanning\"')\n    spinner\n  .my2(v-if='datasetScanstate === \"scanned\"')\n\n    div(v-if='datasets.length != 0')\n      table.full\n        thead\n          tr\n            th \n            th exchange\n            th currency\n            th asset\n            th from\n            th to\n            th duration\n        tbody\n          tr(v-for='(set, i) in datasets')\n            td.radio\n              input(type='radio', name='dataset', :value='i', v-model='setIndex', v-bind:id='set.id')\n            td \n              label(v-bind:for='set.id') {{ set.exchange }}\n            td \n              label(v-bind:for='set.id') {{ set.currency }}\n            td\n              label(v-bind:for='set.id') {{ set.asset }}\n            td \n              label(v-bind:for='set.id') {{ fmt(set.from) }}\n            td \n              label(v-bind:for='set.id') {{ fmt(set.to) }}\n            td\n              label(v-bind:for='set.id') {{ humanizeDuration(set.to.diff(set.from)) }}\n      a.btn--primary(href='#', v-on:click.prevent='openRange', v-if='!rangeVisible') Adjust range\n      template(v-if='rangeVisible')\n        div\n          label(for='customFrom') From:\n          input(v-model='customFrom')\n        div\n          label(for='customTo') To:\n          input(v-model='customTo')\n\n    em(v-else) No Data found \n      a(href='#/data/importer') Lets add some\n\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport Vue from 'vue'\n\nimport { post } from '../../../tools/ajax'\nimport spinner from '../../global/blockSpinner.vue'\nimport dataset from '../../global/mixins/dataset'\n\nexport default {\n  components: {\n    spinner\n  },\n  data: () => {\n    return {\n      setIndex: -1,\n      customTo: false,\n      customFrom: false,\n      rangeVisible: false,\n      set: false\n    };\n  },\n  mixins: [ dataset ],\n  methods: {\n    humanizeDuration: (n) => {\n      return window.humanizeDuration(n, {largest: 4});\n    },\n    fmt: mom => mom.utc().format('YYYY-MM-DD HH:mm'),\n    openRange: function() {\n      if(this.setIndex === -1)\n        return alert('Select a dataset to adjust range');\n\n      this.updateCustomRange();\n\n      this.rangeVisible = true;\n    },\n    updateCustomRange: function() {\n      this.customTo = this.fmt(this.set.to);\n      this.customFrom = this.fmt(this.set.from);\n    },\n    emitSet: function(val) {\n      if(!val)\n        return;\n\n      let set;\n\n      if(!this.customTo)\n        set = val;\n      else {\n        set = Vue.util.extend({}, val);\n        set.to = moment.utc(this.customTo, 'YYYY-MM-DD HH:mm').format();\n        set.from = moment.utc(this.customFrom, 'YYYY-MM-DD HH:mm').format();\n      }\n\n      this.$emit('dataset', set);\n    }\n  },\n  watch: {\n\n    setIndex: function() {\n      this.set = this.datasets[this.setIndex];\n\n      this.updateCustomRange();\n\n      this.emitSet(this.set);\n    },\n\n    customTo: function() { this.emitSet(this.set); },\n    customFrom: function() { this.emitSet(this.set); }\n  }\n}\n</script>\n<style>\ntd.radio {\n  width: 45px;\n}\ntd label{\n  display: inline;\n  font-size: 1em;\n}\n</style>"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/exchangepicker.vue",
    "content": "<template lang='pug'>\ndiv\n  .mx1\n    label(for='exchange').wrapper Exchange:\n    .custom-select.button\n      select(v-model='exchange')\n        option(v-for='(market, e) in exchanges') {{ e }}\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport rangePicker from './rangepicker.vue'\nimport rangeCreator from './rangecreator.vue'\nimport { get } from '../../../tools/ajax'\n\nexport default {\n  props: ['onlyTradable', 'onlyImportable'],\n  data: () => {\n    return {\n      exchange: 'poloniex',\n    };\n  },\n  created: function() {\n    this.emitExchange();\n  },\n  computed: {\n    exchanges: function() {\n\n      let exchanges = Object.assign({}, this.$store.state.exchanges);\n\n      if(_.isEmpty(exchanges))\n        return false;\n\n      if(this.onlyTradable) {\n        _.each(exchanges, (e, name) => {\n          if(!e.tradable)\n            delete exchanges[name];\n        });\n      }\n\n      if(this.onlyImportable) {\n        _.each(exchanges, (e, name) => {\n          if(!e.importable)\n            delete exchanges[name];\n        });\n      }\n\n      return exchanges;\n    }\n  },\n\n  watch: {\n    exchanges: function() { this.emitExchange() },\n    exchange: function() { this.emitExchange() }\n  },\n\n  methods: {\n    emitExchange: function() {\n      this.$emit('exchange', this.exchange);\n    }\n  }\n}\n</script>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/marketpicker.vue",
    "content": "<template lang='pug'>\ndiv\n  .mx1\n    label(for='exchange').wrapper Exchange:\n    .custom-select.button\n      select(v-model='exchange')\n        option(v-for='(market, e) in exchanges') {{ e }}\n  .grd-row\n    .grd-row-col-3-6.mx1\n      label(for='currency') Currency:\n      .custom-select.button\n        select(v-model='currency')\n          option(v-for='cur in currencies') {{ cur }}\n    .grd-row-col-3-6.mx1\n      label(for='asset') Asset:\n      .custom-select.button\n        select(v-model='asset')\n          option(v-for='asst in assets') {{ asst }}\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport rangePicker from './rangepicker.vue'\nimport rangeCreator from './rangecreator.vue'\nimport { get } from '../../../tools/ajax'\n\nexport default {\n  props: ['onlyTradable', 'onlyImportable'],\n  data: () => {\n    return {\n      // defaults:\n      exchange: 'poloniex',\n      currency: 'USDT',\n      asset: 'BTC',\n    };\n  },\n  created: function() {\n    this.emitConfig();\n  },\n  computed: {\n    exchanges: function() {\n\n      let exchanges = Object.assign({}, this.$store.state.exchanges);\n\n      if(_.isEmpty(exchanges))\n        return false;\n\n      if(this.onlyTradable) {\n        _.each(exchanges, (e, name) => {\n          if(!e.tradable)\n            delete exchanges[name];\n        });\n      }\n\n      if(this.onlyImportable) {\n        _.each(exchanges, (e, name) => {\n          if(!e.importable)\n            delete exchanges[name];\n        });\n      }\n\n      return exchanges;\n    },\n    markets: function() {\n      return this.exchanges ? this.exchanges[ this.exchange ] : null;\n    },\n\n    assets: function() {\n      return this.exchanges ? this.exchanges[this.exchange].markets[this.currency] : null;\n    },\n\n    currencies: function() {\n      return this.exchanges ? _.keys( this.exchanges[this.exchange].markets ) : null;\n    },\n    watchConfig: function() {\n      return {\n        watch: {\n          exchange: this.exchange,\n          currency: this.currency,\n          asset: this.asset,\n        }\n      }\n    }\n  },\n\n  watch: {\n    currency: function() { this.emitConfig() },\n    asset: function() { this.emitConfig() },\n    market: function() { this.emitConfig() },\n    exchanges: function() { this.emitConfig() },\n    exchange: function() { this.emitConfig() }\n  },\n\n  methods: {\n    emitConfig: function() {\n      this.$emit('market', this.watchConfig);\n    }\n  }\n}\n</script>\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/papertrader.vue",
    "content": "<template lang='pug'>\n.grd\n  .px1\n    h3 Paper trader\n    a.btn--primary(href='#', v-on:click.prevent='switchToggle', v-if='toggle === \"closed\"') Change paper trader settings\n    template(v-if='toggle === \"open\"')\n      p Settings:\n      textarea.params(v-model='rawPaperTraderParams')\n      p.bg--red.p1(v-if='rawPaperTraderParamsError') {{ rawPaperTraderParamsError.message }}\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport { get } from '../../../tools/ajax'\n\nexport default {\n  created: function() {\n    get('configPart/paperTrader', (error, response) => {\n      this.rawPaperTraderParams = response.part;\n    });\n  },\n  data: () => {\n    return {\n      rawPaperTraderParams: '',\n      rawPaperTraderParamsError: false,\n      paperTraderParams: {},\n      toggle: 'closed'\n    };\n  },\n  watch: {\n    rawPaperTraderParams: function() { this.emitConfig() }\n  },\n  methods: {\n    switchToggle: function() {\n      if(this.toggle === 'open')\n        this.toggle = 'closed';\n      else\n        this.toggle = 'open';\n    },\n    emitConfig: function() {\n      this.parseParams();\n      this.$emit('settings', this.paperTraderParams);\n    },\n    parseParams: function() {\n      try {\n        this.paperTraderParams = toml.parse(this.rawPaperTraderParams);\n        this.paperTraderParams.reportRoundtrips = true;\n        this.rawPaperTraderParamsError = false;\n      } catch(e) {\n        this.rawPaperTraderParamsError = e;\n        this.paperTraderParams = {};\n      }\n    }\n  }\n}\n</script>\n<style>\n.align .custom-select select {\n  padding: 0.4em 1.2em .3em .8em;\n}\n\n.label-like {\n  display: block;\n  font-size: 0.9em;\n  color: #777;\n}\n\n.align {\n  padding-left: 1em;\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/rangecreator.vue",
    "content": "<template lang='pug'>\ndiv\n  h3 Daterange\n  div\n    label(for='from') From\n    input(v-model='from')\n  div\n    label(for='to') To\n    input(v-model='to')\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport { post } from '../../../tools/ajax'\n// global moment\n\nexport default {\n  data: function() {\n    return {\n      from: '',\n      to: ''\n    }\n  },\n  created: function() {\n    let now = moment().startOf('minute');\n    let then = now.clone().subtract(3, 'months');\n\n    this.to = this.fmt(now);\n    this.from = this.fmt(then);\n    this.emitRange();\n  },\n  methods: {\n    fmtTs: (mom) => moment.unix(mom).utc(),\n    fmt: (mom) => mom.utc().format('YYYY-MM-DD HH:mm'),\n    emitRange: function() {\n      this.$emit('range', {\n        from: this.fmtTs(this.from),\n        to: this.fmtTs(this.to)\n      });\n    },\n    emitManualEntry: function() {\n      if(this.from.length < '4' || this.from.length < '4')\n        return this.$emit('range', {})\n\n      let from = moment.utc(this.from);\n      let to = moment.utc(this.to);\n\n      if(from.isValid() && to.isValid()) {\n        this.$emit('range', {\n          from: this.fmt(from),\n          to: this.fmt(to)\n        })\n      } else {\n        this.$emit('range', {})\n      }\n    }\n  },\n  watch: {\n    from: function() {\n      this.emitManualEntry();\n    },\n    to: function() {\n      this.emitManualEntry();\n    },\n    config: function() {\n      this.scanned = false;\n    },\n    tab: function() {\n      this.scanned = false;\n      this.$emit('range', {})\n    },\n    selectedRangeIndex: function() {\n      let selectedRange = this.ranges[this.selectedRangeIndex];\n      if(selectedRange)\n        this.emitRange(selectedRange);\n    }\n  }\n}\n</script>\n\n<style>\n\n.scan-btn {\n  margin-top: 80px;\n  margin-bottom: 30px;\n}\n\n.radio label {\n  margin-top: 0;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/rangepicker.vue",
    "content": "<template lang='pug'>\ndiv\n  h3 Daterange\n  template(v-if='tab === \"scan\"')\n    .txt--center(v-if='!scanned')\n      a.w100--s.btn--primary.scan-btn(href='#', v-on:click.prevent='scan') Scan available data\n    .txt--center(v-if='scanned == \"fetching\"')\n      p.scan-btn Scanning..\n    template(v-if='scanned == true')\n      template(v-if='ranges.length === 0')\n        p\n          strong Unable to find any local data, do you have local data available for\n            | \"{{ config.watch.exchange }}:{{ config.watch.currency }}/{{ config.watch.asset }}\"?\n      template(v-else)\n        label(for='exchange').wrapper Run simulation over:\n        form.radio.grd\n          div.grd-row(v-for='(range, i) in ranges').m1\n            input.grd-row-col-1-6(type='radio', :value='i', v-model='selectedRangeIndex')\n            label.grd-row-col-5-6(:for='i') {{ printRange(range) }}\n      p\n        em\n          a(href='#', v-on:click.prevent='scan') rescan\n    p.txt--center\n      em\n        a(href='#', v-on:click.prevent='tab = \"manual\"') Or manually set a daterange\n  template(v-if='tab === \"manual\"')\n    div\n      label(for='from') From:\n      input(v-model='from')\n    div\n      label(for='to') To:\n      input(v-model='to')\n    p.txt--center\n    em\n      a(href='#', v-on:click.prevent='tab = \"scan\"') Or scan for a daterange\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport { post } from '../../../tools/ajax'\n// global moment\n\nexport default {\n  props: ['config'],\n  data: () => {\n    return {\n      scanned: false, // 'fetching', true\n      ranges: [],\n      selectedRangeIndex: -1,\n      tab: 'scan',\n\n      from: '',\n      to: ''\n    }\n  },\n  methods: {\n    scan: function() {\n      this.scanned = 'fetching';\n      this.selectedRangeIndex = -1;\n\n      post('scan', this.config, (err, response) => {\n        this.scanned = true;\n        this.ranges = response;\n        this.selectedRangeIndex = 0;\n      });\n    },\n    printRange: function(range) {\n      let fmt = mom => mom.format('YYYY-MM-DD HH:mm')\n      let from = moment.unix(range.from);\n      let to = moment.unix(range.to);\n      let diff = moment.duration(to.diff(from)).humanize();\n      return `${fmt(from)} to ${fmt(to)} (${diff})`;\n    },\n    fmtTs: (mom) => moment.unix(mom).utc(),\n    fmt: (mom) => mom.utc().format(),\n    emitRange: function(range) {\n      this.$emit('range', {\n        from: this.fmtTs(range.from),\n        to: this.fmtTs(range.to)\n      });\n    },\n    emitManualEntry: function() {\n      if(this.from.length < '4' || this.from.length < '4')\n        // this cannot possibly be a valid date\n        return this.$emit('range', {})\n\n      let from = moment.utc(this.from);\n      let to = moment.utc(this.to);\n\n      if(from.isValid() && to.isValid()) {\n        this.$emit('range', {\n          from: this.fmt(from),\n          to: this.fmt(to)\n        })\n      } else {\n        this.$emit('range', {});\n      }\n    },\n    reset: function() {\n      this.scanned = false;\n      this.$emit('range', {})\n    }\n  },\n  watch: {\n    from: function() {\n      this.emitManualEntry();\n    },\n    to: function() {\n      this.emitManualEntry();\n    },\n    config: function() {\n      this.reset();\n    },\n    tab: function() {\n      this.reset();\n    },\n    selectedRangeIndex: function() {\n      let selectedRange = this.ranges[this.selectedRangeIndex];\n      if(selectedRange)\n        this.emitRange(selectedRange);\n    }\n  }\n}\n</script>\n\n<style>\n\n.scan-btn {\n  margin-top: 80px;\n  margin-bottom: 30px;\n}\n\n.radio label {\n  margin-top: 0;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/stratpicker.vue",
    "content": "<template lang='pug'>\n.grd\n  .grd-row\n    .grd-row-col-3-6.px1\n      h3 Strategy\n      div\n        label(for='strat').wrapper Strategy:\n        .custom-select.button\n          select(v-model='strategy')\n            option(v-for='strat in strategies') {{ strat.name }}\n      div\n        label(for='candleSize') Candle Size\n        .grd-row\n          .grd-row-col-3-6\n            input(v-model='rawCandleSize')\n          .grd-row-col-3-6.align\n            .custom-select.button\n              select(v-model='candleSizeUnit')\n                option minutes\n                option hours\n                option days\n      div\n        label(for='historySize') Warmup period (in {{ rawCandleSize }} {{ singularCandleSizeUnit }} candles):\n        input(v-model='historySize')\n        em.label-like (will use {{ humanizeDuration(candleSize * historySize * 1000 * 60) }} of data as history)\n    .grd-row-col-3-6.px1\n      div\n        h3 Parameters\n        p {{ strategy }} Parameters:\n        textarea.params(v-model='rawStratParams')\n        p.bg--red.p1(v-if='rawStratParamsError') {{ rawStratParamsError.message }}\n</template>\n\n<script>\n\nimport _ from 'lodash'\nimport { get } from '../../../tools/ajax'\n\nexport default {\n  data: () => {\n    return {\n      strategies: [],\n\n      candleSizeUnit: 'hours',\n      rawCandleSize: 1,\n\n      strategy: 'MACD',\n      historySize: 10,\n\n      rawStratParams: '',\n      rawStratParamsError: false,\n\n      emptyStrat: false,\n      stratParams: {}\n    };\n  },\n  created: function () {\n    get('strategies', (err, data) => {\n        this.strategies = data;\n\n        _.each(this.strategies, function(s) {\n          s.empty = s.params === '';\n        });\n\n        this.rawStratParams = _.find(this.strategies, { name: this.strategy }).params;\n        this.emptyStrat = _.find(this.strategies, { name: this.strategy }).empty;\n        this.emitConfig();\n    });\n  },\n  watch: {\n    strategy: function(strat) {\n      strat = _.find(this.strategies, { name: strat });\n      this.rawStratParams = strat.params;\n      this.emptyStrat = strat.empty;\n\n      this.emitConfig();\n    },\n    candleSize: function() { this.emitConfig() },\n    historySize: function() { this.emitConfig() },\n    rawStratParams: function() { this.emitConfig() }\n  },\n  computed: {\n    candleSize: function() {\n       if(this.candleSizeUnit === 'minutes')\n        return this.rawCandleSize;\n      else if(this.candleSizeUnit === 'hours')\n        return this.rawCandleSize * 60;\n      else if(this.candleSizeUnit === 'days')\n        return this.rawCandleSize * 60 * 24;\n    },\n    singularCandleSizeUnit: function() {\n      // hours -> hour\n      return this.candleSizeUnit.slice(0, -1);\n    },\n    config: function() {\n      let config = {\n        tradingAdvisor: {\n          enabled: true,\n          method: this.strategy,\n          candleSize: +this.candleSize,\n          historySize: +this.historySize\n        }\n      }\n\n      if(this.emptyStrat)\n        config[this.strategy] = {__empty: true}\n      else\n        config[this.strategy] = this.stratParams;\n\n      return config;\n    }\n  },\n  methods: {\n    humanizeDuration: (n) => window.humanizeDuration(n),\n    emitConfig: function() {\n      this.parseParams();\n      this.$emit('stratConfig', this.config);\n    },\n    parseParams: function() {\n      try {\n        this.stratParams = toml.parse(this.rawStratParams);\n        this.rawStratParamsError = false;\n      } catch(e) {\n        this.rawStratParamsError = e;\n        this.stratParams = {};\n      }\n    }\n  }\n}\n</script>\n<style>\n.align .custom-select select {\n  padding: 0.4em 1.2em .3em .8em;\n}\n\n.label-like {\n  display: block;\n  font-size: 0.9em;\n  color: #777;\n}\n\n.align {\n  padding-left: 1em;\n}\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/configbuilder/typepicker.vue",
    "content": "<template lang='pug'>\ndiv\n  h3 Type\n  template\n    label(for='type').wrapper What do you want to do with gekko?\n    form.radio.grd\n      div.grd-row(v-for='(type, i) in types').m1\n        input.grd-row-col-1-6(type='radio', :value='i', v-model='selectedTypeIndex')\n        label.grd-row-col-5-6(:for='i') {{ type }}\n</template>\n\n<script>\n\nexport default {\n  created: function() {\n    this.emitType();\n  },\n  data: () => {\n    return {\n      types: ['paper trader', 'market watcher', 'tradebot'],\n      selectedTypeIndex: 0,\n    }\n  },\n  methods: {\n    emitType: function() {\n      this.$emit('type', this.type);\n    }\n  },\n  watch: {\n    type: function() {\n      this.emitType();\n    }\n  },\n  computed: {\n    type: function() {\n      return this.types[ this.selectedTypeIndex ];\n    }\n  }\n}\n</script>\n\n<style>\n\n.radio label {\n  margin-top: 0;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/mixins/dataset.js",
    "content": "import { post } from '../../../tools/ajax'\n\nvar mixin = {\n  data: () => {\n    return {\n      datasets: [],\n      datasetScanstate: 'idle',\n      unscannableMakets: []\n    }    \n  },\n  methods: {\n    scan: function() {\n      this.datasetScanstate = 'scanning';\n\n      post('scansets', {}, (error, response) => {\n        this.datasetScanstate = 'scanned';\n\n        this.unscannableMakets = response.errors;\n\n        let sets = [];\n\n        response.datasets.forEach(market => {\n          market.ranges.forEach((range, i) => {\n            sets.push({\n              exchange: market.exchange,\n              currency: market.currency,\n              asset: market.asset,\n              from: moment.unix(range.from).utc(),\n              to: moment.unix(range.to).utc(),\n              id: market.exchange + market.asset + market.currency + i\n            });\n          });\n        });\n\n        // for now, filter out sets smaller than 3 hours..\n        sets = sets.filter(set => {\n          if(set.to.diff(set.from, 'hours') > 2)\n            return true;\n        });\n\n        sets = sets.sort((a, b) => {\n          let adiff = a.to.diff(a.from);\n          let bdiff = b.to.diff(b.from);\n\n          if(adiff < bdiff)\n            return -1;\n\n          if(adiff > bdiff)\n            return 1;\n\n          return 0;\n        }).reverse();\n\n        this.datasets = sets;\n      })\n    }\n  }\n}\n\nexport default mixin;"
  },
  {
    "path": "web/vue/src/components/global/paperTradeSummary.vue",
    "content": "<template lang='pug'>\n.grd-row-col-3-6\n  table.p1\n    tr\n      th amount of trades\n      td {{ report.trades }}\n    tr\n      th sharpe ratio\n      td {{ round2(report.sharpe) }}\n    tr\n      th start balance\n      td {{ round(report.startBalance) }} {{ report.currency }}\n    tr\n      th final balance\n      td {{ round(report.balance) }} {{ report.currency }}\n    tr\n      th simulated profit\n\n  .big.txt--right.price(:class='profitClass') {{ round(report.relativeProfit) }}%\n\n</template>\n\n<script>\n\nexport default {\n  props: ['report'],\n  methods: {\n    round2: n => (+n).toFixed(2),\n    round: n => (+n).toFixed(5)\n  },\n  computed: {\n    profitClass: function() {\n      if(this.report.relativeProfit > 0)\n        return 'profit'\n      else\n        return 'loss'\n    }\n  }\n}\n</script>\n\n<style>\n.summary td {\n  text-align: right;\n}\n\n.big {\n  font-size: 1.3em;\n  width: 80%;\n}\n\n.summary table {\n  width: 80%;\n}\n\n.price.profit {\n  color: #7FFF00;\n}\n\n.price.loss {\n  color: red;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/global/progressBar.vue",
    "content": "// http://stackoverflow.com/questions/7190898/progress-bar-with-html-and-css\n\n<template lang='pug'>\n.progressbarWrapper(v-if='progress')\n  p <strong>{{ round(progress) }}%</strong>\n  .progressbar\n    div(:style='{width: progress + \"%\"}')\n</template>\n\n<script>\nexport default {\n  props: ['progress'],\n  methods: {\n    round: n => (+n).toFixed(2)\n  }\n}\n</script>\n\n<style>\n.progressbarWrapper p {\n  text-align: center;\n  font-size: 20px;\n}\n\n.progressbar {\n  background-color: rgba(216,216,216,.99);\n  border-radius: 13px; /* (height of inner div) / 2 + padding */\n  padding: 0px;\n}\n\n\n@keyframes shimmer{\n    0%{\n        background-position: 0px 0\n    }\n    100%{\n        background-position: 960px 0\n    }\n}\n\n.progressbar > div {\n  height: 20px;\n  border-radius: 10px;\n  /* Progress bar animation */\n  background-color: #FFA500;\n  animation-duration: 1500ms;\n  animation-fill-mode: forwards;\n  animation-iteration-count: infinite;\n  animation-name: shimmer;\n  animation-timing-function: linear;\n  background: #f6f7f8;\n  background: linear-gradient(to right, #FFA500 10%, #ffce77 25%, #FFA500 40%);\n  background-size: 960px 50px;\n  background-position: left;\n  position: relative;\n}\n</style>"
  },
  {
    "path": "web/vue/src/components/global/ws.js",
    "content": "import _ from 'lodash'\nimport Vue from 'vue'\n\nimport { wsPath } from '../../tools/api'\nimport initializeState from '../../store/init'\n\nvar socket = null;\n\nexport const bus = new Vue();\n\nbus.$on('gekko_update', data => console.log(data))\n\nbus.$on('import_update', data => console.log(data))\nbus.$on('import_error', data => {\n  alert('IMPORT ERROR: ' + data.error);\n});\n\nconst info = {\n  connected: false\n}\n\nexport const connect = () => {\n  socket = new ReconnectingWebSocket(wsPath, null, { maxReconnectInterval: 4000 });\n\n  setTimeout(() => {\n    // in case we cannot connect\n    if(!info.connected) {\n      initializeState();\n      bus.$emit('WS_STATUS_CHANGE', info);\n    }\n  }, 500);\n\n  socket.onopen = () => {\n    if(info.connected)\n      return;\n\n    info.connected = true;\n    bus.$emit('WS_STATUS_CHANGE', info);\n    initializeState();\n  }\n  socket.onclose = () => {\n    if(!info.connected)\n      return;\n\n    info.connected = false;\n    bus.$emit('WS_STATUS_CHANGE', info);\n  }\n  socket.onerror = () => {\n    if(!info.connected)\n      return;\n\n    info.connected = false;\n    bus.$emit('WS_STATUS_CHANGE', info);\n  }\n  socket.onmessage = function(message) {\n    const payload = JSON.parse(message.data);\n    // console.log('ws message:', payload);\n    bus.$emit(payload.type, payload);\n  };\n}"
  },
  {
    "path": "web/vue/src/components/layout/footer.vue",
    "content": "<template lang='pug'>\n  footer.p2.bg--off-white\n    .contain\n      p\n        em Use Gekko at your own risk.\n      p Using Gekko v{{ version.gekko }} and Gekko UI v{{ version.ui }}.\n</template>\n\n<script>\nconst gekkoPackage = require('../../../../../package.json');\nconst uiPackage = require('../../../package.json');\n\nexport default {\n  data: () => {\n    return {\n      version: {\n        gekko: gekkoPackage.version,\n        ui: uiPackage.version\n      }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "web/vue/src/components/layout/header.vue",
    "content": "<template lang='pug'>\n  div\n    #top\n    header.bg--off-white.grd\n      .contain.grd-row\n        h3.py1.px2.col-2 Gekko UI\n    nav.bg--light-gray\n      .menu.contain\n        router-link(to='/home').py1 Home\n        router-link(to='/live-gekkos').py1 Live Gekkos\n        router-link(to='/backtest').py1 Backtest\n        router-link(to='/data').py1 Local data\n        router-link(to='/config').py1 Config\n        a(href='https://gekko.wizb.it/docs/introduction/about_gekko.html', target='_blank').py1 Documentation\n\n</template>\n\n<script>\nexport default {}\n</script>\n\n<style>\n.menu {\n  display: flex;\n  flex-direction: row;\n  margin-top: 0;\n  margin-bottom: 2rem;\n}\n\n.menu a {\n  flex: 1 1 100%;\n  display: block;\n  text-align: center;\n  text-decoration: none;\n  color: inherit;\n}\n\n.menu .router-link-active {\n  background-color: rgba(250,250,250,.99);\n}\n\n.menu a:hover {\n  text-decoration: underline;\n}\n\n</style>\n"
  },
  {
    "path": "web/vue/src/components/layout/home.vue",
    "content": "<template lang='pug'>\n  section.contain.grd-row\n    .grd-row-col-3-6(v-html='left')\n    .grd-row-col-3-6.txt--center\n      img(src='static/gekko.jpg')\n      p\n        em The most valuable commodity I know of is information.\n</template>\n\n<script>\nimport marked from '../../tools/marked';\n\nconst left = marked(`\n\n## Gekko\n\nGekko is a Bitcoin trading bot and backtesting platform that\nconnects to popular Bitcoin exchanges. It is written in javascript\nand runs on nodejs.\n\n[Find out more](https://gekko.wizb.it/).\n\n*Gekko is 100% free (open source), if you paid for this you have been scammed.*\n\n`);\n\nexport default {\n  data: () => {\n    return {\n      left\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "web/vue/src/components/layout/modal.vue",
    "content": "<template lang='pug'>\n  div(v-if='active')\n    #modal-background\n    #modal.modal\n      .modal-guts(v-html='content')\n</template>\n\n<script>\n\nimport marked from '../../tools/marked';\n\nconst messages = {\n  disconnected: marked(`\n\n## Disconnected\n\nSomething happened to either Gekko or the connection.\nPlease check the terminal where Gekko is running or\nyour network connection.\n\n*This message is shown when the UI is unable to open a websocket connection with the Gekko Server.*\n\n  `)\n}\n\nexport default {\n  computed: {\n    active: function() {\n      return !this.$store.state.warnings.connected;\n    },\n    content: function() {\n      if(!this.$store.state.warnings.connected)\n        return messages.disconnected;\n      return '';\n    }\n  }\n}\n</script>\n\n<style>\n#modal-background {\n  position: fixed;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n\n  background-color: black;\n  opacity: 0.5\n}\n\n.modal {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  width: 600px;\n  min-height: 300px;\n  background-color: white;\n}\n\n.modal-guts {\n\n  /* other stuff we already covered */\n\n  /* cover the modal */\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n\n  /* spacing as needed */\n  padding: 20px 50px 20px 20px;\n\n  /* let it scroll */\n  overflow: auto;\n  \n}\n</style>\n"
  },
  {
    "path": "web/vue/src/d3/chart3.js",
    "content": "import _ from 'lodash'\n\n// techanjs based cancle chart, unused at the moment\n\nexport default function(_data, _trades) {\n    let MAX_WIDTH = window.innerWidth - 20;\n\n    var margin = {top: 20, right: 20, bottom: 30, left: 50},\n            width = MAX_WIDTH - margin.left - margin.right,\n            height = 500 - margin.top - margin.bottom;\n\n    var x = techan.scale.financetime()\n            .range([0, width]);\n\n    var y = d3.scaleLinear()\n            .range([height, 0]);\n\n    var zoom = d3.zoom()\n            .on(\"zoom\", zoomed);\n\n    var zoomableInit;\n\n    var candlestick = techan.plot.candlestick()\n            .xScale(x)\n            .yScale(y);\n\n    var tradearrow = techan.plot.tradearrow()\n            .xScale(x)\n            .yScale(y)\n            .orient(function(d) { return d.type.startsWith(\"buy\") ? \"up\" : \"down\"; })\n            .on(\"mouseenter\", enter)\n            .on(\"mouseout\", out);\n\n    var xAxis = d3.axisBottom(x);\n\n    var yAxis = d3.axisLeft(y);\n\n    var svg = d3.select(\"#chart\").append(\"svg\")\n            .attr(\"width\", width + margin.left + margin.right)\n            .attr(\"height\", height + margin.top + margin.bottom)\n        .append(\"g\")\n            .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");\n\n    svg.append(\"clipPath\")\n            .attr(\"id\", \"clip\")\n        .append(\"rect\")\n            .attr(\"x\", 0)\n            .attr(\"y\", y(1))\n            .attr(\"width\", width)\n            .attr(\"height\", y(0) - y(1)); \n\n    svg.append(\"g\")\n        .attr(\"class\", \"candlestick\")\n        .attr(\"clip-path\", \"url(#clip)\");\n\n    svg.append(\"g\")\n        .attr(\"class\", \"tradearrow\")\n        .attr(\"clip-path\", \"url(#clip)\");\n\n    svg.append(\"g\")\n        .attr(\"class\", \"x axis\")\n        .attr(\"transform\", \"translate(0,\" + height + \")\");\n\n    svg.append(\"g\")\n        .attr(\"class\", \"y axis\")\n    .append(\"text\")\n        .attr(\"transform\", \"rotate(-90)\")\n        .attr(\"y\", 6)\n        .attr(\"dy\", \".71em\")\n        .style(\"text-anchor\", \"end\")\n        .text(\"Price ($)\");\n\n    svg.append(\"rect\")\n        .attr(\"class\", \"pane\")\n        .attr(\"width\", width)\n        .attr(\"height\", height)\n        .call(zoom);\n\n\n    var accessor = candlestick.accessor();\n\n    const data = _data.map(function(d) {\n        return {\n            date: new Date(d.start),\n            open: +d.open,\n            high: +d.high,\n            low: +d.low,\n            close: +d.close,\n            volume: +d.volume\n        };\n    }).sort(function(a, b) { return d3.ascending(accessor.d(a), accessor.d(b)); });\n\n    const trades = _trades.map(function(t) {\n        let trade = _.pick(t, ['price']);\n        trade.quantity = 1;\n        trade.type = t.action;\n        trade.date = new Date(t.date);\n        return trade;\n    });\n\n    console.log(trades);\n\n    x.domain(data.map(accessor.d));\n    y.domain(techan.scale.plot.ohlc(data, accessor).domain());\n\n    svg.select(\"g.tradearrow\").datum(trades);\n    svg.select(\"g.candlestick\").datum(data);\n    draw();\n\n    // Associate the zoom with the scale after a domain has been applied\n    // Stash initial settings to store as baseline for zooming\n    zoomableInit = x.zoomable().clamp(false).copy();\n\n    function zoomed() {\n        var rescaledY = d3.event.transform.rescaleY(y);\n        yAxis.scale(rescaledY);\n        candlestick.yScale(rescaledY);\n        tradearrow.yScale(rescaledY);\n\n        // Emulates D3 behaviour, required for financetime due to secondary zoomable scale\n        x.zoomable().domain(d3.event.transform.rescaleX(zoomableInit).domain());\n\n        draw();\n    }\n\n    function draw() {\n        svg.select(\"g.tradearrow\").call(tradearrow);\n        svg.select(\"g.candlestick\").call(candlestick);\n        // using refresh method is more efficient as it does not perform any data joins\n        // Use this if underlying data is not changing\n    //        svg.select(\"g.candlestick\").call(candlestick.refresh);\n        svg.select(\"g.x.axis\").call(xAxis);\n        svg.select(\"g.y.axis\").call(yAxis)\n    }\n\n    function enter(d) {\n        valueText.style(\"display\", \"inline\");\n        refreshText(d);\n    }\n\n    function out() {\n        valueText.style(\"display\", \"none\");\n    }\n\n    function refreshText(d) {\n        valueText.text(\"Trade: \" + dateFormat(d.date) + \", \" + d.type + \", \" + valueFormat(d.price));\n    }\n\n};"
  },
  {
    "path": "web/vue/src/d3/chart4.js",
    "content": "import _ from 'lodash';\n// global moment\n\nexport default function(_data, _trades, _height) {\n\n  const toDate = i => {\n    if(_.isNumber(i)) {\n      return moment.unix(i).utc().toDate();\n    } else {\n      return moment.utc(i).toDate();\n    }\n  }\n\n  const trades = _trades.map(t => {\n    return {\n      price: t.price,\n      date: toDate(t.date),\n      action: t.action\n    }\n  });\n\n  const data = _data.map(c => {\n    return {\n      price: c.open,\n      date: toDate(c.start)\n    }\n  });\n\n  var dates = data.map(c => +c.date);\n  var prices = data.map(c => +c.price)\n\n  var svg = d3.select(\"#chart\");\n\n  svg.attr(\"width\", window.innerWidth - 20);\n\n  var margin = {top: 20, right: 20, bottom: 110, left: 40};\n  var height = _height - margin.top - margin.bottom;\n  var margin2 = {top: _height - 70, right: 20, bottom: 30, left: 40};\n  var width = +svg.attr(\"width\") - margin.left - margin.right;\n  var height2 = _height - margin2.top - margin2.bottom;\n\n  var x = d3.scaleUtc().range([0, width]),\n      x2 = d3.scaleUtc().range([0, width]),\n      y = d3.scaleLinear().range([height, 0]),\n      y2 = d3.scaleLinear().range([height2, 0]);\n\n  var xAxis = d3.axisBottom(x),\n      xAxis2 = d3.axisBottom(x2),\n      yAxis = d3.axisLeft(y).ticks(_height / 50);\n\n  var brush = d3.brushX()\n      .extent([[0, 0], [width, height2]])\n      .on(\"brush end\", brushed);\n\n  var zoom = d3.zoom()\n      .scaleExtent([1, 100])\n      .translateExtent([[0, 0], [width, height]])\n      .extent([[0, 0], [width, height]])\n      .on(\"zoom\", zoomed);\n\n  var line = d3.line()\n      .x(function(d) { return x(d.date); })\n      .y(function(d) { return y(d.price); });\n\n  var line2 = d3.line()\n      .x(function(d) { return x2(d.date); })\n      .y(function(d) { return y2(d.price); });\n\n  svg.append(\"defs\").append(\"clipPath\")\n      .attr(\"id\", \"clip\")\n    .append(\"rect\")\n      .attr(\"width\", width)\n      .attr(\"height\", height);\n\n  var focus = svg.append(\"g\")\n      .attr(\"class\", \"focus\")\n      .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");\n\n  var context = svg.append(\"g\")\n      .attr(\"class\", \"context\")\n      .attr(\"transform\", \"translate(\" + margin2.left + \",\" + margin2.top + \")\");\n\n  x.domain(d3.extent(data, function(d) { return d.date; }));\n  y.domain([\n    d3.min(prices) * 0.99,\n    d3.max(prices) * 1.01\n  ]);\n  x2.domain(x.domain());\n  y2.domain(y.domain());\n\n  focus.append(\"path\")\n      .datum(data)\n      .attr(\"class\", \"line price\")\n      .attr(\"d\", line);\n\n  focus.append(\"g\")\n      .attr(\"class\", \"axis axis--x\")\n      .attr(\"transform\", \"translate(0,\" + height + \")\")\n      .call(xAxis);\n\n  focus.append(\"g\")\n      .attr(\"class\", \"axis axis--y\")\n      .call(yAxis);\n\n  context.append(\"path\")\n      .datum(data)\n      .attr(\"class\", \"line\")\n      .attr(\"d\", line2);\n\n  context.append(\"g\")\n      .attr(\"class\", \"axis axis--x\")\n      .attr(\"transform\", \"translate(0,\" + height2 + \")\")\n      .call(xAxis2);\n\n  var circles = svg\n    .append('g')\n    .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\")\n      .selectAll(\"circle\")\n      .data(trades)\n      .enter().append(\"circle\")\n        .attr('class', function(d) { return d.action })\n        .attr(\"cx\", function(d) { return x(d.date); })\n        .attr(\"cy\", function(d) { return y(d.price); })\n        .attr('r', 5);\n\n  var brushCircles = context\n    .append('g')\n    // .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\")\n      .selectAll(\"circle\")\n      .data(trades)\n      .enter().append(\"circle\")\n        .attr('class', function(d) { return d.action })\n        .attr(\"cx\", function(d) { return x2(d.date); })\n        .attr(\"cy\", function(d) { return y2(d.price); })\n        .attr('r', 3);\n\n\n  context.append(\"g\")\n      .attr(\"class\", \"brush\")\n      .call(brush)\n      .call(brush.move, x.range());\n\n  svg.append(\"rect\")\n      .attr(\"class\", \"zoom\")\n      .attr(\"width\", width)\n      .attr(\"height\", height)\n      .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\")\n      .call(zoom);\n\n  function brushed() {\n    if (d3.event.sourceEvent && d3.event.sourceEvent.type === \"zoom\") return; // ignore brush-by-zoom\n    var s = d3.event.selection || x2.range();\n    x.domain(s.map(x2.invert, x2));\n\n    scaleY(x.domain());\n\n    svg.select(\".axis--y\")\n      .call(yAxis);\n\n    circles\n      .attr(\"cx\", function(d) { return x(d.date); })\n      .attr(\"cy\", function(d) { return y(d.price); })\n\n    focus.select(\".line\").attr(\"d\", line);\n    focus.select(\".axis--x\").call(xAxis);\n    svg.select(\".zoom\").call(zoom.transform, d3.zoomIdentity\n        .scale(width / (s[1] - s[0]))\n        .translate(-s[0], 0));\n  }\n\n  function scaleY(domain) {\n    let [min, max] = domain;\n\n    let minIndex = _.sortedIndex(dates, min);\n    let maxIndex = _.sortedIndex(dates, max);\n\n    let set = prices.slice(minIndex, maxIndex);\n    y.domain([\n      d3.min(set) * 0.9995,\n      d3.max(set) * 1.0005\n    ]);\n  }\n\n  function zoomed() {\n    if (d3.event.sourceEvent && d3.event.sourceEvent.type === \"brush\") return; // ignore zoom-by-brush\n    var t = d3.event.transform;\n\n    scaleY(t.rescaleX(x2).domain());    \n\n    svg.select(\".axis--y\")\n      .call(yAxis);\n\n    x.domain(t.rescaleX(x2).domain());\n    focus.select(\".line\").attr(\"d\", line);\n\n    circles\n      .attr(\"cx\", function(d) { return x(d.date); })\n      .attr(\"cy\", function(d) { return y(d.price); })\n\n\n    focus.select(\".axis--x\").call(xAxis);\n    context.select(\".brush\").call(brush.move, x.range().map(t.invertX, t));\n  }\n}"
  },
  {
    "path": "web/vue/src/d3/message.js",
    "content": "export const draw = function(message) {\n  d3.select(\"#chart\").append(\"text\")\n      .attr('class', 'message')\n      .attr('x', 150)\n      .attr('y', 150)\n      .text(message);\n}\n\nexport const clear = function() {\n  d3.select(\"#chart\").find('text').remove();\n}"
  },
  {
    "path": "web/vue/src/main.js",
    "content": "import Vue from 'vue'\nimport App from './App.vue'\n\nimport VueRouter from 'vue-router'\nVue.use(VueRouter);\n\nimport store from './store'\n\nimport backtester from './components/backtester/backtester.vue'\nimport home from './components/layout/home.vue'\n\nimport data from './components/data/data.vue'\nimport importer from './components/data/import/importer.vue'\nimport singleImport from './components/data/import/single.vue'\nimport config from './components/config/config.vue'\n\nimport gekkoList from './components/gekko/list.vue'\nimport newGekko from './components/gekko/new.vue'\nimport singleGekko from './components/gekko/singleGekko.vue'\nimport { connect as connectWS } from './components/global/ws'\n\nconst router = new VueRouter({\n  mode: 'hash',\n  base: __dirname,\n  routes: [\n    { path: '/', redirect: '/home' },\n    { path: '/home', component: home },\n    { path: '/backtest', component: backtester },\n    { path: '/config', component: config },\n    { path: '/data', component: data },\n    { path: '/data/importer', component: importer },\n    { path: '/data/importer/import/:id', component: singleImport },\n    { path: '/live-gekkos', component: gekkoList },\n    { path: '/live-gekkos/new', component: newGekko },\n    { path: '/live-gekkos/:id', component: singleGekko },\n  ]\n});\n\n// setup some stuff\nconnectWS();\n\nnew Vue({\n  router,\n  store,\n  el: '#app',\n  render: h => h(App)\n})"
  },
  {
    "path": "web/vue/src/store/index.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport _ from 'lodash'\n\nimport * as importMutations from './modules/imports/mutations'\nimport * as gekkoMutations from './modules/gekkos/mutations'\nimport * as notificationMutations from './modules/notifications/mutations'\nimport * as configMutations from './modules/config/mutations'\n\nVue.use(Vuex);\n\nconst debug = process.env.NODE_ENV !== 'production'\n\nlet mutations = {};\n\n_.merge(mutations, importMutations);\n_.merge(mutations, gekkoMutations);\n_.merge(mutations, notificationMutations);\n_.merge(mutations, configMutations);\n\nexport default new Vuex.Store({\n  state: {\n    warnings: {\n      connected: true, // assume we will connect\n    },\n    imports: [],\n    gekkos: {},\n    archivedGekkos: {},\n    connection: {\n      disconnected: false,\n      reconnected: false\n    },\n    apiKeys: [],\n    exchanges: {}\n  },\n  mutations,\n  strict: debug\n})"
  },
  {
    "path": "web/vue/src/store/init.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\n\nimport syncImports from './modules/imports/sync'\nimport syncGekkos from './modules/gekkos/sync'\nimport syncNotifications from './modules/notifications/sync'\nimport syncConfig from './modules/config/sync'\n\nexport default function() {\n  syncImports();\n  syncGekkos();\n  syncNotifications();\n  syncConfig();\n}"
  },
  {
    "path": "web/vue/src/store/modules/config/mutations.js",
    "content": "import Vue from 'vue'\n\nexport const syncApiKeys = (state, apiKeys) => {\n  Vue.set(state, 'apiKeys', apiKeys);\n  return state;\n}\n\nexport const syncExchanges = (state, exchanges) => {\n  Vue.set(state, 'exchanges', exchanges);\n  return state;\n}"
  },
  {
    "path": "web/vue/src/store/modules/config/sync.js",
    "content": "import { get } from '../../../tools/ajax'\nimport store from '../../'\nimport { bus } from '../../../components/global/ws'\n\nconst transformMarkets = backendData => {\n  if(!backendData) {\n    return {};\n  }\n\n  var exchangesRaw = backendData;\n  var exchangesTemp = {};\n\n  exchangesRaw.forEach(e => {\n    exchangesTemp[e.slug] = exchangesTemp[e.slug] || {markets: {}};\n\n    e.markets.forEach( pair => {\n      let [ currency, asset ] = pair['pair'];\n      exchangesTemp[e.slug].markets[currency] = exchangesTemp[e.slug].markets[currency] || [];\n      exchangesTemp[e.slug].markets[currency].push( asset );\n    });\n\n    if (\"exchangeMaxHistoryAge\" in e) {\n      exchangesTemp[e.slug].exchangeMaxHistoryAge = e.exchangeMaxHistoryAge;\n    }\n\n    exchangesTemp[e.slug].importable = e.providesFullHistory ? true : false;\n    exchangesTemp[e.slug].tradable = e.tradable ? true : false;\n    exchangesTemp[e.slug].requires = e.requires;\n  });\n\n  return exchangesTemp;\n}\n\n\nconst init = () => {\n  get('apiKeys', (err, resp) => {\n    store.commit('syncApiKeys', resp);\n  });\n\n  get('exchanges', (err, resp) => {\n    store.commit('syncExchanges', transformMarkets(resp));\n  })\n}\n\nconst sync = () => {\n  bus.$on('apiKeys', data => {\n    store.commit('syncApiKeys', data.exchanges);\n  });\n}\n\nexport default function() {\n  init();\n  sync();\n}\n"
  },
  {
    "path": "web/vue/src/store/modules/gekkos/mutations.js",
    "content": "import Vue from 'vue'\nimport _ from 'lodash';\nconst reduceState = require('../../../../../state/reduceState');\n\nexport const syncGekkos = (state, data) => {\n  if(!data) {\n    return state;\n  }\n\n  state.gekkos = data.live;\n  state.archivedGekkos = data.archive;\n  return state;\n}\n\nexport const addGekko = (state, gekko) => {\n  state.gekkos = {\n    ...state.gekkos,\n    [gekko.id]: gekko\n  }\n  return state;\n}\n\nexport const updateGekko = (state, update) => {\n  if(!update.id || !_.has(state.gekkos, update.id)) {\n    return console.error('cannot update unknown gekko..');;\n  }\n\n  state.gekkos = {\n    ...state.gekkos,\n    [update.id]: reduceState(state.gekkos[update.id], update.event)\n  }\n  return state;\n}\n\nexport const archiveGekko = (state, id) => {\n  if(!_.has(state.gekkos, id)) {\n    return console.error('cannot archive unknown gekko..');\n  }\n\n  state.archivedGekkos = {\n    ...state.archivedGekkos,\n    [id]: {\n      ...state.gekkos[id],\n      stopped: true,\n      active: false\n    }\n  }\n\n  state.gekkos = _.omit(state.gekkos, id);\n  return state;\n}\n\nexport const errorGekko = (state, data) => {\n  if(!_.has(state.gekkos, data.id)) {\n    return console.error('cannot error unknown gekko..');\n  }\n\n  state.gekkos = {\n    ...state.gekkos,\n    [data.id]: {\n      ...state.gekkos[data.id],\n      errored: true,\n      errorMessage: data.error\n    }\n  }\n\n  return state;\n}\n\nexport const deleteGekko = (state, id) => {\n  if(!_.has(state.archivedGekkos, id)) {\n    return console.error('cannot delete unknown gekko..');\n  }\n\n  state.archivedGekkos = _.omit(state.archivedGekkos, id);\n  return state;\n}"
  },
  {
    "path": "web/vue/src/store/modules/gekkos/sync.js",
    "content": "import { get } from '../../../tools/ajax'\nimport store from '../../'\nimport { bus } from '../../../components/global/ws'\nimport _ from 'lodash'\n\nconst init = () => {\n  get('gekkos', (err, resp) => {\n    const gekkos = resp;\n    store.commit('syncGekkos', gekkos);\n  });\n}\n\nconst sync = () => {\n  bus.$on('gekko_new', data => store.commit('addGekko', data.state));\n  bus.$on('gekko_event', data => store.commit('updateGekko', data));\n  bus.$on('gekko_archived', data => store.commit('archiveGekko', data.id));\n  bus.$on('gekko_error', data => store.commit('errorGekko', data));\n  bus.$on('gekko_deleted', data => store.commit('deleteGekko', data.id));\n\n  // unused:\n  // bus.$on('gekko_stopped', data => store.commit('x', data.id));\n  // bus.$on('gekko_deleted', data => store.commit('x', data.id));\n}\n\nexport default function() {\n  init();\n  sync();\n}"
  },
  {
    "path": "web/vue/src/store/modules/imports/mutations.js",
    "content": "import Vue from 'vue'\n\nexport const addImport = (state, imp) => {\n  state.imports.push(imp);\n  return state;\n}\n\nexport const syncImports = (state, imports) => {\n  state.imports = imports;\n  return state;\n}\n\nexport const updateImport = (state, update) => {\n  let index = state.imports.findIndex(i => i.id === update.import_id);\n  let item = state.imports[index];\n  if(!item)\n    return state;\n\n  let updated = Vue.util.extend(item, update.updates);\n  Vue.set(state.imports, index, updated);\n\n  return state;\n}"
  },
  {
    "path": "web/vue/src/store/modules/imports/sync.js",
    "content": "import { get } from '../../../tools/ajax'\nimport store from '../../'\nimport { bus } from '../../../components/global/ws'\n\nconst init = () => {\n  get('imports', (err, resp) => {\n    store.commit('syncImports', resp);\n  });\n}\n\nconst sync = () => {\n  bus.$on('import_update', data => {\n    store.commit('updateImport', data);\n  });\n}\n\nexport default function() {\n  init();\n  sync();\n}"
  },
  {
    "path": "web/vue/src/store/modules/messages/mutations.js",
    "content": ""
  },
  {
    "path": "web/vue/src/store/modules/notifications/mutations.js",
    "content": "import Vue from 'vue'\nimport _ from 'lodash'\n\nexport const setGlobalWarning = (state, warning) => {\n  state.warnings[warning.key] = warning.value;\n  return state;\n}"
  },
  {
    "path": "web/vue/src/store/modules/notifications/sync.js",
    "content": "import store from '../../'\nimport { bus } from '../../../components/global/ws'\n\nconst init = () => {}\n\nconst sync = () => {\n  bus.$on('WS_STATUS_CHANGE', ws => {\n    return store.commit('setGlobalWarning', {key: 'connected', value: ws.connected});\n  });\n}\n\nexport default function() {\n  init();\n  sync();\n}"
  },
  {
    "path": "web/vue/src/tools/ajax.js",
    "content": "import superagent from 'superagent'\nimport noCache from 'superagent-no-cache'\nimport { restPath } from './api.js'\n\nconst processResponse = next => (err, res) => {\n  if(err)\n    return next(err);\n\n  if(!res.text)\n    return next('no data');\n\n  let data = JSON.parse(res.text);\n\n  next(false, data);\n}\n\nexport const post = (to, data, next) => {\n  superagent\n    .post(restPath + to)\n    .use(noCache)\n    .send(data)\n    .end(processResponse(next));\n}\n\nexport const get = (to, next) => {\n  superagent\n    .get(restPath + to)\n    .use(noCache)\n    .end(processResponse(next));\n}\n"
  },
  {
    "path": "web/vue/src/tools/api.js",
    "content": "// global window.CONFIG\n\nconst config = window.CONFIG.ui;\nconst endpoint = `${config.host}${config.port === 80 ? '' : `:${config.port}`}${config.path}`;\n\nlet basePath, restPath, wsPath;\n\n// rest API path\nif(config.ssl) {\n  basePath = `https://${endpoint}`;\n} else {\n  basePath = `http://${endpoint}`;\n}\n\nrestPath = basePath + 'api/';\n\n// ws API path\nif(config.ssl) {\n  wsPath = `wss://${endpoint}api`;\n} else {\n  wsPath = `ws://${endpoint}api`;\n}\n\nexport {\n  wsPath,\n  restPath,\n  basePath\n};\n"
  },
  {
    "path": "web/vue/src/tools/marked.js",
    "content": "const marked = require('marked');\n\n// add `target='_blank'` to outgoing links\n\n// https://github.com/chjj/marked/pull/451#issuecomment-49976076\n\nvar myRenderer = new marked.Renderer();\nmyRenderer.link = function(href, title, text) {\n  var external, newWindow, out;\n  external = /^https?:\\/\\/.+$/.test(href);\n  newWindow = external || title === 'newWindow';\n  out = \"<a href=\\\"\" + href + \"\\\"\";\n  if (newWindow) {\n    out += ' target=\"_blank\"';\n  }\n  if (title && title !== 'newWindow') {\n    out += \" title=\\\"\" + title + \"\\\"\";\n  }\n  return out += \">\" + text + \"</a>\";\n};\n\nmarked.setOptions({renderer: myRenderer});\n\nexport default marked;"
  },
  {
    "path": "web/vue/vue.config.js",
    "content": "const CopyWebpackPlugin = require('copy-webpack-plugin');\n\nmodule.exports = {\n  configureWebpack: {\n    plugins: [\n      new CopyWebpackPlugin([\n        {\n          from: '../baseUIconfig.js',\n          to: '../public/UIconfig.js'\n        },\n        {\n          from: '../baseUIconfig.js',\n          to: 'UIconfig.js'\n        },\n      ])\n    ]\n  },\n  baseUrl: ''\n}"
  }
]